Difference between revisions of "Primer"

From Linked Data Platform
Jump to: navigation, search
(Basic concepts and terminology)
(Create a new Bug)
Line 153: Line 153:
 
|
 
|
  
LDP servers allow creation of resources by posting a representation of the resource to an existing container. Continuing from the previous example, we can report a Bug against 'Product A' by creating a Bug LDPR under the 'Product A' LDPC.  
+
Continuing from the previous example, we can report a Bug against 'product1' by creating a Bug LDPR under the 'Product' LDPC.  
  
 
'''Steps'''
 
'''Steps'''

Revision as of 14:11, 7 June 2013

This page collects content for a future Note on LDP Primer to be produced by the Linked Data Platform WG.

This primer provides an introduction to Linked Data Platform (LDP), including the basic concepts of LDP including Linked Data Platform Resource (LDPR) and Linked Data Platform Container (LDPC) and their affordances, and a running example showing how an LDP client can interact with a LDP server in the context of read-write Linked Data application i.e. how to HTTP for accessing, updating, creating and deleting resources from servers that expose their resources as Linked Data.

1 Introduction

Linked Data is a universal approach for handling data which fundamentally includes the notion linking between data items. Much like the Web is giant network of interlinked documents for a human reader, the graph of Linked Data in the Web is a data layer on top of which applications are delivered, information is modified, processed, visualised and shared.

A bit about Linked Data, current state, and the need for a Linked Data Platform (Read/Write LD) etc.

A bit about generic LDP servers and LDP servers that represent business applications. That is bit confusing for most of the people.

from test cases, Generic vs domain-specific servers

There will be two types of systems implementing the LDP specification:

Generic RDF storage systems that allow interacting with their resources by means of the LDP specification. These servers do not impose any restriction on LDPRs. Systems exposing their data using the LDP specification. These systems impose restrictions on LDPRs since they have an underlying business logic and data model. In order to cover both types of systems, we do not provide concrete input data in the test suite. It is up to the evaluator to define concrete input data for a certain system. Evaluators must include these input data along with the results when reporting the results of a certain system.

2 Organization of this Document

2.1 2.1 Conventions Used in This Document

Example representations are provided in text/turtle format [TURTLE].

Commonly used namespace prefixes:

	@prefix dcterms: <http://purl.org/dc/terms/>.
	@prefix rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
	@prefix rdfs:    <http://www.w3.org/2000/01/rdf-schema#>.
	@prefix ldp:     <http://www.w3.org/ns/ldp#>.
	@prefix xsd:     <http://www.w3.org/2001/XMLSchema#>.
        @prefix bt:      <http://example.org/vocab/bugtracker#>.

3 Basic concepts and terminology

3.1 LDPR

  • LDPRs are HTTP resources that can be created, modified, deleted and read using standard HTTP methods (i.e., POST, PUT/PATCH, DELETE, GET).
  • LDPRs use RDF to define their states.
  • You can request a Turtle representation of a LDPR and possibly other representations (e.g., XML/RDF)
  • LDP clients use Optimistic Collision Detection on update.
  • LDPRs set rdf:type explicitly.
  • LDP clients expect to encounter unknown properties and content.
  • LDP clients do not assume the type of a resource at the end of a link.

From WWW LDP presentation

3.2 LDPC

  • LDPCs are LDPRs
  • Clients can retrieve the list of resource members of an LDPC using GET
  • New resources are created using POST
  • Any resource can be POSTed to an LDPC – not just LDPRs
  • After POSTing a new resource to an LDPC, the new resource will appear as a member untilit is deleted.
  • Clients can retrieve information about an LDPC without retrieving a full representation of its content, including its members.
  • On deleting an LDPC the server MAY delete member resources.

From WWW LDP presentation

4 Examples

This section provides a set of examples to show the Linked Data Platform interactions. Note, this is a primer and should not be considered as a canonical example of ideal LDP modelling.

The examples in this section will revolve around a very simple Bug Tracker application. Bug Tracker application records the bugs of several products allowing reporting, updating and deleting bugs and products. We can re-use simple domain vocabulary, e.g. has_bug or related, to express our data. LDP provides the addition interaction capability in the protocol to perform dynamic evolution of knowledge representation.

4.1 Simple Scenarios

4.1.1 Lookup a Product

Primer1 1.png

The client request a GET with the URI of a known Product resource.

 GET /app/product1 HTTP/1.1
 Host: example.org
 Accept: text/turtle 

If the resource is available, the server responds with the representation of the resource.

 HTTP/1.1 200 OK 
 Content-Type: text/turtle
 ETag: W/"123456789"

 <http://example.org/app/product1> a bt:Product;
      dcterms:title "Product 1" . 

4.1.2 Lookup a Bug

Primer1 2.png


Based on links in the representation of the Product, the client uses GET to navigate to a known Bug resource.

 GET /app/product1/bug3 HTTP/1.1
 Host: example.org
 Accept: text/turtle 

The server responds with the representation of the resource.

 HTTP/1.1 200 OK 
 Content-Type: text/turtle
 ETag: W/"123456789"

 <http://example.org/app/product1/bug3> a bt:Bug;
      dcterms:title "Product A crashes when shutting down.";
      dcterms:creator <http://example.org/users/johndoe>;
      dcterms:created "2013-05-05T10:00"^^xsd:dateTime
      bt:isInState "New" . 

4.1.3 Update a Bug

Primer1 3.png

 PUT /app/BugTracker/ProductA/Bug1 HTTP/1.1
 Host: example.org
 Content-Type: text/turtle
 If-Match: W/"123456789"

 <http://example.org/app/BugTracker/ProductA/Bug1> a bt:Bug;
      dcterms:title "Product A crashes when shutting down.";
      dcterms:creator <http://example.org/users/johndoe>;
      dcterms:created "2013-05-05T10:00"^^xsd:dateTime;
      bt:isInState "InProgress";
      bt:relatedBug <http://example.org/app/BugTracker/ProductB/Bug5> . 

If the update is successful, the server will respond with a success status and a new etag.

 HTTP/1.1 204 No Content 
 ETag: W/"123456790" 


4.1.4 Create a new Bug

Primer1 4.png

Continuing from the previous example, we can report a Bug against 'product1' by creating a Bug LDPR under the 'Product' LDPC.

Steps The client POSTs a representation of a Bug to the Bug Tracker LDPC.

 POST /app/BugTracker/ProductA HTTP/1.1
 Host: example.org
 Content-Type: text/turtle
 
 <> a bt:Bug;
      dcterms:title "Product A crashes when shutting down.";
      dcterms:creator <http://example.org/users/johndoe> . 

If the create is successful, the server responds with location of the newly created resource.

 HTTP/1.1 201 Created
 Location: http://example.org/app/BugTracker/ProductA/Bug1
 Content-Length: 0  

If the creation fails, the server will respond with an appropriate status code depending on the error.

After the resource is creation, the Product A LDPC will have the following representation.

 <http://example.org/app/BugTracker/ProductA> a ldp:Container, bt:Product;
        dcterms:title "A container that tracks bugs of Product A" ;
	rdfs:member <http://example.org/app/BugTracker/ProductA/Bug1> . 
again, isn't it bugs:has_bug (and not rdfs:member) ?

And the created Bug resource will have the following representation. Note that server has added a server managed property, creation date (dcterms:created), and a default value for the state (bt:isInState) to the Bug in addition to what was being POSTed.

 <http://example.org/app/BugTracker/ProductA/Bug1> a bt:Bug;
      dcterms:title "Product A crashes when shutting down.";
      dcterms:creator <http://example.org/users/johndoe>;
      dcterms:created "2013-05-05T10:00"^^xsd:dateTime;
      bt:isInState "New" . 

4.2 Basic scenarios

4.2.1 Creating a container

If the LDP server may allow creating LDPC by posting a representation of the container to an existing container. So we will add a new Product

The mechanism for creating the first ever container of a system is not defined in the specification and it is assumed that servers will make available one or more containers as the starting point for interacting with the server. In this example, we assume that 'Bug Tracker' container is already available and it has the following representation.

 <http://example.org/app/BugTracker> a ldp:Container . 
i think this needs a membershipPredicate added ... (?)


Steps

The client POSTs a representation of the 'Project A' to the Bug Tracker LDPC. As the URI of the 'Project A' is not known until it's created, clients can include a null relative URI in the representation and the LDP servers interpret the null relative URI for the subject of triples in the request entity body as referring to the entity in the request body.

use a slug header in the example below ?
 POST /app/BugTracker HTTP/1.1
 Host: example.org
 Content-Type: text/turtle
 
 <> a ldp:Container, bt:Product;
      dcterms:title "A container that tracks bugs of Product A" . 

If the create is successful, the server responds with location of the newly created container.

 HTTP/1.1 201 Created
 Location: http://example.org/app/BugTracker/ProductA
 Content-Length: 0 

If the creation fails, the server will respond with an appropriate status code depending on the error.

After creation of this new container, 'Product A', the representation of the 'Tracker' container will be

 <http://example.org/app/BugTracker> a ldp:Container;
    rdfs:member <http://example.org/app/BugTracker/ProductA> . 
is this tracksproduct (rather than rdfs:member) ?

and the 'Product A' will have the following representation.

 <http://example.org/app/BugTracker/ProductA> a ldp:Container, bt:Product;
        dcterms:title "A container that tracks bugs of Product A" . 


Bug1.png

4.2.2 Creating a resource

LDP servers allow creation of resources by posting a representation of the resource to an existing container. Continuing from the previous example, we can report a Bug against 'Product A' by creating a Bug LDPR under the 'Product A' LDPC.

Steps The client POSTs a representation of a Bug to the Bug Tracker LDPC.

 POST /app/BugTracker/ProductA HTTP/1.1
 Host: example.org
 Content-Type: text/turtle
 
 <> a bt:Bug;
      dcterms:title "Product A crashes when shutting down.";
      dcterms:creator <http://example.org/users/johndoe> . 

If the create is successful, the server responds with location of the newly created resource.

 HTTP/1.1 201 Created
 Location: http://example.org/app/BugTracker/ProductA/Bug1
 Content-Length: 0  

If the creation fails, the server will respond with an appropriate status code depending on the error.

After the resource is creation, the Product A LDPC will have the following representation.

 <http://example.org/app/BugTracker/ProductA> a ldp:Container, bt:Product;
        dcterms:title "A container that tracks bugs of Product A" ;
	rdfs:member <http://example.org/app/BugTracker/ProductA/Bug1> . 
again, isn't it bugs:has_bug (and not rdfs:member) ?

And the created Bug resource will have the following representation. Note that server has added a server managed property, creation date (dcterms:created), and a default value for the state (bt:isInState) to the Bug in addition to what was being POSTed.

 <http://example.org/app/BugTracker/ProductA/Bug1> a bt:Bug;
      dcterms:title "Product A crashes when shutting down.";
      dcterms:creator <http://example.org/users/johndoe>;
      dcterms:created "2013-05-05T10:00"^^xsd:dateTime;
      bt:isInState "New" . 

Bug2.png

4.2.3 Retrieving a resource

Steps

The client request a GET with the URI of a known Bug resource.

 GET /app/BugTracker/ProductA/Bug1 HTTP/1.1
 Host: example.org
 Accept: text/turtle 

If the resource is available, the server responds with the representation of the resource.

 HTTP/1.1 200 OK 
 Content-Type: text/turtle
 ETag: W/"123456789"

 <http://example.org/bugtracker/Tracker/ProductA/Bug1> a bt:Bug;
      dcterms:title "Product A crashes when shutting down.";
      dcterms:creator <http://example.org/users/johndoe>;
      dcterms:created "2013-05-05T10:00"^^xsd:dateTime
      bt:isInState "New" . 


4.2.4 Updating a resource

LDP servers may allow updating certain resources. For example, in the Bug Tracker application bugs can be updated to change their state and/or add information about related bugs.

Steps

First, get the resource that has to be updated.

 GET /app/BugTracker/ProductA/Bug1 HTTP/1.1
 Host: example.org
 Accept: text/turtle 
 HTTP/1.1 200 OK 
 Content-Type: text/turtle
 ETag: W/"123456789"

 <http://example.org/app/BugTracker/ProductA/Bug1> a bt:Bug;
      dcterms:title "Product A crashes when shutting down.";
      dcterms:creator <http://example.org/users/johndoe>;
      dcterms:created "2013-05-05T10:00"^^xsd:dateTime
      bt:isInState "New" . 

An alternative way of retrieving the entity tag would be to use the HEAD operation in the cases whether the current representation of the resource is not necessary.

 HEAD /app/BugTracker/ProductA/Bug1 HTTP/1.1
 Host: example.org
 Accept: text/turtle 
 HTTP/1.1 204 No Content
 Allow: GET, PUT, POST, HEAD, PATCH, DELETE
 ETag: W/"123456789" 

After the modifications are done in the resource, the updated representation can be PUT to the resource URI. The etag from the previous retrieval has to be send along with the PUT request.

 PUT /app/BugTracker/ProductA/Bug1 HTTP/1.1
 Host: example.org
 Content-Type: text/turtle
 If-Match: W/"123456789"

 <http://example.org/app/BugTracker/ProductA/Bug1> a bt:Bug;
      dcterms:title "Product A crashes when shutting down.";
      dcterms:creator <http://example.org/users/johndoe>;
      dcterms:created "2013-05-05T10:00"^^xsd:dateTime;
      bt:isInState "InProgress";
      bt:relatedBug <http://example.org/app/BugTracker/ProductB/Bug5> . 

Alternatively, if a client can use PATCH method to update resource by sending a diff of the changes to the resource if the PATCH is allowed. PATCH is an optional feature in the LDP specification and the clients may use OPTIONS method to determine whether PATCH method is allowed. LDP specification does not mandate any PATCH formats and which PATCH formats are supported by the server has to be communicated out-of-band to the client. In this example, we use changesets as the PATCH format.

 PATCH /app/BugTracker/ProductA/Bug1 HTTP/1.1
 Host: example.org
 Content-Type: text/turtle
 If-Match: W/"123456789"

 @prefix cs: <http://purl.org/vocab/changeset/schema#>.

 _:changeSet a cs:ChangeSet ;
  cs:subjectOfChange <http://example.org/app/BugTracker/ProductA/Bug1> ;
  cs:createdDate "2012-01-01T00:00:00Z" ;
  cs:changeReason "Update to in progress and the related bug" ;
  cs:removal [
    a rdf:Statement ;
    rdf:subject <http://example.org/app/BugTracker/ProductA/Bug1> ;
    rdf:predicate bt:isInState ;
    rdf:object "New" .
  ] ;
  cs:addition [
    a rdf:Statement ;
    rdf:subject <http://example.org/app/BugTracker/ProductA/Bug1> ;
    rdf:predicate bt:state ;
    rdf:object "InProgress" .
  ] ;
  cs:addition [
    a rdf:Statement ;
    rdf:subject <http://example.org/app/BugTracker/ProductA/Bug1> ;
    rdf:predicate bt:relatedBug ;
    rdf:object <http://example.org/app/BugTracker/ProductB/Bug5> .
  ] . 

If the update is successful, the server will respond with a success status and a new etag.

 HTTP/1.1 204 No Content 
 ETag: W/"123456790" 

Bug3.png

4.2.5 Deleting a resource

LDP servers may allow deleting resources.

Steps

 DELETE /app/BugTracker/ProductA/Bug1 HTTP/1.1 
 Host: example.org

If the delete is successful, the server will respond with a success status code.

 
  HTTP/1.1 204 No Content
  ETag: W/"123456790" 

4.2.6 Retrieving a container

Steps

The client request a GET with the URI of a known Product container.

 GET /app/BugTracker/ProductB/ HTTP/1.1
 Host: example.org
 Accept: text/turtle  

If the Product B container is available, the server responds with the representation of the container.

 HTTP/1.1 200 OK 
 Content-Type: text/turtle
 ETag: W/"123456789"

 <http://example.org/app/BugTracker/ProductB> a ldp:Container, bt:Product;
        dcterms:title "A container that tracks bugs of Product B" ;
	rdfs:member <http://example.org/app/BugTracker/ProductB/Bug10> ;
        rdfs:member <http://example.org/app/BugTracker/ProductB/Bug11> ;
        rdfs:member <http://example.org/app/BugTracker/ProductB/Bug12> .  

Alternatively, the servers can also inline the membership resources in the container representation.

 HTTP/1.1 200 OK 
 Content-Type: text/turtle
 ETag: W/"123456790"

 <http://example.org/app/BugTracker/ProductB> a ldp:Container, bt:Product;
        dcterms:title "A container that tracks bugs of Product B" ;
	rdfs:member <http://example.org/app/BugTracker/ProductB/Bug10> ;
        rdfs:member <http://example.org/app/BugTracker/ProductB/Bug11> ;
        rdfs:member <http://example.org/app/BugTracker/ProductB/Bug12> . 

 <http://example.org/app/BugTracker/ProductB/Bug10> a bt:Bug;
      dcterms:title "Product B does not make coffee";
      dcterms:creator <http://example.org/users/johndoe>;
      dcterms:created "2013-05-05T10:00"^^xsd:dateTime;
      bt:isInState "New";

 <http://example.org/app/BugTracker/ProductB/Bug11> a bt:Bug;
      dcterms:title "Product B GUI is too reddish";
      dcterms:creator <http://example.org/users/janeroe>;
      dcterms:created "2013-05-06T10:00"^^xsd:dateTime;
      bt:isInState "InProgress";

 <http://example.org/app/BugTracker/ProductB/Bug12> a bt:Bug;
      dcterms:title "Product B is too slow";
      dcterms:creator <http://example.org/users/johndoe>;
      dcterms:created "2013-05-07T10:00"^^xsd:dateTime;
      bt:isInState "InProgress"; 

4.2.7 Updating a container

4.2.8 Deleting a container

LDP servers may allow deleting containers.

Steps

 DELETE /app/BugTracker/ProductB HTTP/1.1 
 Host: example.org

If the delete is successful, the server will respond with a success status code.

 
  HTTP/1.1 204 No Content
  ETag: W/"123456790" 

The sever may delete all membership resources (eg. Bug10, Bug11, and Bug12) recursively. But as LDP specification does not mandate this, there is no guarantee that the server will do this recursive delete unless it is advertised out of band.

4.3 Advanced scenarios

4.3.1 Managing binary resources

ex-1) We have an LDPC which we can use to create binary resources

GET /Bug1/attachments/ HTTP/1.1
Host: example.org
Accept: text/turtle 

HTTP/1.1 200 OK 
Content-Type: text/turtle
ETag: W/"123456789"

</Bug1/attachments/> a ldp:Container . 

ex-2). We POST the binary resource to the LDPC and it responds with a Location header and a Link header.

POST /Bug1/attachments/ HTTP/1.1
Host: example.org
Content-Type: image/png
Slug: login-page.png
Content-Length: 1254

#### binary data ##### 

HTTP/1.1 201 Created
Location: /Bug1/attachments/login-page.png
Link: </Bug1/attachments/attachment1>; rel="meta"
Content-Length: 0 

ex-3). We can access the created resource using the URI in the location header.

GET /Bug1/attachments/login-page.png
Host: example.org
Accept: image/png 

HTTP/1.1 200 OK 
Content-Type: text/turtle
Link: </Bug1/attachments/attachment1>; rel="meta"
ETag: W/"123456789"

#### binary data ##### 

ex-4). We can access the metadata about the resource using the URI in the Link header.

GET /Bug1/attachments/attachment1
Host: example.org
Accept: text/turtle 

HTTP/1.1 200 OK 
Content-Type: text/turtle
ETag: W/"123456789"

</Bug1/attachments/login-page.png> wdrs:describedby </Bug1/attachments/attachment1> ;
	
</Bug1/attachments/login-page.png> ;
      dct:created "2013-05-27T17:05Z"^^xsd:dateTime ;
      dct:creator </user/jhondoe#me> . 

ex-5). The container is updated to with the binary resource as a member.

GET /Bug1/attachments/ HTTP/1.1
Host: exampl[1] - https://dev.twitter.com/docs/api/1.1/post/statuses/update_with_mediae.org
Accept: text/turtle 

HTTP/1.1 200 OK 
Content-Type: text/turtle
ETag: W/"123456789"

</Bug1/attachments/> a ldp:Container ;
       rdfs:member </Bug1/login-page.png> . 

ex-6). We can update the metadata about the binary resource using the metadata URI

PUT /Bug1/attachments/attachment1 HTTP/1.1
Host: example.org
Content-Type: text/turtle
If-Match: W/"123456789"

</Bug1/attachments/attachment1> x:content </Bug1/attachments/login-page.png> ;	
</Bug1/attachments/login-page.png> ;
      dc:title "Screenshop of the Web UI of the login page when error happened"; 
      dct:created "2013-05-27T17:05Z"^^xsd:dateTime ;
      dct:creator </user/jhondoe#me> . 

HTTP/1.1 204 No Content 
ETag: W/"123456790" 

ex-7). We can delete the binary resource and the metadata LDPR must be automatically deleted.

 DELETE /Bug1/attachments/login-page.png HTTP/1.1
 Host: example.org 

 HTTP/1.1 204 No Content
 ETag: W/"123456790" 

Then if we retrieve

GET /Bug1/attachments/login-page.png HTTP/1.1
 Host: example.org 

 HTTP/1.1 410 Gone 

and

 GET /Bug1/attachments/attachment1 HTTP/1.1
 Host: example.org 

 HTTP/1.1 410 Gone 

4.3.2 Container member ordering

4.3.3 Paging

5 LDP Implementations

A list of implementations that plan to be LDP compliant is available in the LDP Implementations wiki page.

LDP Implementation report provides the coverage of the specification by each LDP implementation.

6 Mapping with other documents (only in the draft)

6.1 Use Case and Requirements

Mappings to UCR document
UCR Use Cases Primer Example
4.1 Manage containers 4.1.1 create container 4.1
4.1.2 create a nested container
4.2 Manage resources 4.2.1 create resource 4.2
4.2.2 delete resource 4.5
4.2.3 moving contained resources
4.3 Retrieve resource description 4.3.1 Retrive 4.3
4.3.2 retrieve description of a non-document resource
4.4 Update existing resource 4.4.1 enrichment 4.4
4.4.2 selective update of a resource 4.4
4.5 Determine if a resource has changed 4.5.1 Determine if a resource has changed
4.6 Aggregate resources 4.6.1 add a resource to a collection
4.6.2 add a resource to multiple collections
4.7 Filter resource description 4.7.1 retrieve collection-level description
4.7.2 Alternative scenario: retrieve item-level description of a collection
4.8 Manage media resources 4.8.1 access media resources
4.8.2 media-resource attachments

6.2 Test cases document

Mappings to Test Cases document
UCR Use Cases Primer Example
TC-R1. GET on an LDPR 4.3
TC-R2. GET on an LDPR without content type
TC-R3. GET on a non-existing LDPR
TC-R4. PUT on an LDPR 4.4
TC-R5. PUT on an LDPR without matching ETags
TC-R6. DELETE on an LDPR 4.5
TC-R7. HEAD on an LDPR 4.4
TC-C1. GET on an LDPC 4.6
TC-C3. GET on a non-existing LDPC
TC-C4. PUT on an LDPC 4.7
TC-C5. PUT on an LDPC without matching ETags
TC-C6. DELETE on an LDPC 4.8
TC-C7. DELETE on an LDPR in an LDPC
TC-C8. HEAD on an LDPC 4.4
TC-C9. POST an LDPR on an LDPC 4.2

6.3 Not covered in UCR and Tests

  • Ordering
  • Paging
  • Inlining

7 References

[TURTLE] David Beckett; Tim Berners-Lee. Turtle: Terse RDF Triple Language. February 2013. W3C Candidate Recommendation. URL: http://www.w3.org/TR/turtle/

8 Appendix

8.1 Example Ontology (probably for our use only)

BugTracker.jpg

 
 @prefix rdfs:    <http://www.w3.org/2000/01/rdf-schema#>.
 @prefix owl:     <http://www.w3.org/2002/07/owl#> .
 @prefix xsd:     <http://www.w3.org/2001/XMLSchema#"> .
 @prefix dcterms: <http://purl.org/dc/elements/1.1/> .
 @prefix foaf:    <http://xmlns.com/foaf/0.1/>.
 @prefix bt:      <http://example.org/vocab/bugtracker#> .

 bt:Ontology a owl:Ontology;
      rdfs:label "Bug Tracker Example Ontology";
      rdfs:comment "An ontology for Bug Tracker example in the LDP Primer" .

 bt:tracksProject a owl:ObjectProperty;
      rdfs:domain bt:BugTracker;
      rdfs:range bt:Product .

 bt:hasBug a owl:ObjectProperty;
      rdfs:domain bt:Product;
      rdfs:range bt:Bug .

 bt:isInState a owl:ObjectProperty;
      rdfs:domain bt:Bug;
      rdfs:range xsd:string .

 bt:relatedBug a owl:ObjectProperty;
      rdfs:domain bt:Bug;
      rdfs:range bt:Bug .

 bt:Product a owl:Class;
    owl:subClassOf [
	a owl:Restriction ;
        owl:onProperty dcterms:title;
        owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger ;
	owl:onDataRange xsd:string 
    ] . 

 bt:Bug a owl:Class;
    owl:subClassOf [
	a owl:Restriction ;
        owl:onProperty dcterms:created;
        owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger ;
	owl:onDataRange xsd:dateTime 
    ];
    owl:subClassOf [
	a owl:Restriction ;
        owl:onProperty dcterms:creator;
        owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger ;
	owl:onClass foaf:Person
    ];
    owl:subClassOf [
	a owl:Restriction ;
        owl:onProperty dcterms:title;
        owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger ;
	owl:onDataRange xsd:string 
    ];
    owl:subClassOf [
	a owl:Restriction ;
        owl:onProperty bt:isInState;
        owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger ;
	owl:onDataRange xsd:string 
    ] .