Tutorial 2: Developing RDF backed RESTful applications

Author: Reto Bachmann-Gmür and Tsuyoshi Ito - clerezza.org

Contributor: Hasan - clerezza.org

Table of Contents

1. Introduction

2. Setting up the project

3. Creating an accessible service

4. Build

5. Installing the bundle

5. Test your bundle

6. References

1. Introduction

REST [1] is a software architecture style applicable to the World Wide Web. With the advent of the Semantic Web this resource oriented design shows its strength. The web of documents evolves seamlessly to a web of data and knowledge.

RESTful Web applications are designed based on a set of REST principles. In this introductory tutorial you'll learn how to develop a RESTful application that delivers human readable semantic content which is stored in a triple store.

Therefore, you will learn about SCB [2] and Triaxrs [3] and how to use them to develop an RDF-backed RESTful Web application. The time it takes to go through this tutorial is around 30 minutes.

2. Setting up the project

Create a maven project with the following parent and dependencies (see the Triaxrs Tutorial 1 (Developing a RESTful Web Application for OSGi Runtime Environment) for more detail [4]):

First configure the repositories as follows:

<repositories> <repository> <id>clerezza-release</id> <name>clerezza.org distribution repository</name> <url>http://repo.trialox.org/release</url> <layout>default</layout> </repository> <repository> <id>clerezza-snapshot</id> <name>clerezza.org snapshot repository</name> <url>http://repo.trialox.org/snapshot</url> <layout>default</layout> </repository> </repositories> <parent> <artifactId>org.clerezza.parent</artifactId> <groupId>org.clerezza</groupId> <version>0.1-SNAPSHOT</version> //check here for the newest release version or here for newest snapshot version</parent>

It in not necessary to define the version parameter of each dependency because they are specified in the parents pom file.

<dependency> <groupId>org.clerezza</groupId> <artifactId>org.clerezza.jaxrs.rdf.providers</artifactId> </dependency> <dependency> <groupId>org.clerezza</groupId> <artifactId>org.clerezza.platform.typerendering.seedsnipe</artifactId> </dependency> <dependency> <groupId>org.clerezza</groupId> <artifactId>org.clerezza.triaxrs</artifactId> </dependency>

Also set packaging to bundle

By default the maven-bundle-plugin will export the package named <groupId>.<artifactId> and its subpackages, so the exposed components must be defined in a package named that way. In our example we use org.example.clerezza as groupId and combined.tutorial as artifactId.

3. Creating an accessible service

Like in the Triaxrs Tutorial 1 [4] we create a JAX-RS class to get information about persons. To have some data to play with, we will add an RDF file encoded in the Turtle format into the resource tree of our project. Thus, we create the file src/main/resources/org/example/clerezza/combined/tutorial/data.turtle with the following content:

@prefix foaf: <http://xmlns.com/foaf/0.1/>. [ a foaf:Person; foaf:title "Mr"; foaf:name "John Doe"; foaf:mbox <mailto:john@example.org>; foaf:topic_interest <http://dbpedia.org/resource/Category:BBC_television_sitcoms>; foaf:nick "jo" ] . [ a foaf:Person; foaf:title "Mrs"; foaf:name "Jane Bloggs"; foaf:mbox <mailto:jane@example.org>; foaf:openid <http://openid.example.org/jbloggs> ] .

The JAX-RS resource class mentioned above is called in this tutorial TutorialApp and looks as follows:

package org.example.clerezza.combined.tutorial; import java.io.InputStream; import java.net.URISyntaxException; import java.net.URL; import java.util.Iterator; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import org.osgi.service.component.ComponentContext; import org.clerezza.platform.typerendering.seedsnipe.SeedsnipeRenderlet; import org.clerezza.platform.typerendering.RenderletManager; import org.clerezza.rdf.ontologies.FOAF; import org.clerezza.rdf.utils.GraphNode; import org.clerezza.rdf.core.Graph; import org.clerezza.rdf.core.MGraph; import org.clerezza.rdf.core.NonLiteral; import org.clerezza.rdf.core.Triple; import org.clerezza.rdf.core.TripleCollection; import org.clerezza.rdf.core.UriRef; import org.clerezza.rdf.core.access.NoSuchEntityException; import org.clerezza.rdf.core.access.TcManager; import org.clerezza.rdf.core.serializedform.Parser; /** * Get Persons by their email * * @scr.component * @scr.service interface="java.lang.Object" * @scr.property name="javax.ws.rs" type="Boolean" value="true" */ @Path("/foaf") public class TutorialApp { /** * @scr.reference */ TcManager tcManager; /** * @scr.reference */ private RenderletManager renderletManager; private UriRef graphName = new UriRef("http://localhost.mygraph"); @GET @Path("find") @Produces("application/rdf+xml") public Graph getPersonRdf(@QueryParam("mbox") String mboxString) { MGraph mGraph = tcManager.getMGraph(graphName); NonLiteral person = getPersonByMbox(mboxString, mGraph); return new GraphNode(person, mGraph).getNodeContext(); } @GET @Path("find") @Produces("application/xhtml+xml") public GraphNode getPersonHtml(@QueryParam("mbox") String mboxString) { MGraph mGraph = tcManager.getMGraph(graphName); NonLiteral person = getPersonByMbox(mboxString, mGraph); return new GraphNode(person, mGraph); } private NonLiteral getPersonByMbox(String mboxString, MGraph mGraph) { Iterator<Triple> iter = mGraph.filter(null, FOAF.mbox, new UriRef(mboxString)); NonLiteral person = null; while(iter.hasNext()) { person = iter.next().getSubject(); } return person; } /** * The activate method is called when SCR activates the component configuration. * This method gets the system graph or create a new one if it doesn't exist. * * @param componentContext */ protected void activate(ComponentContext componentContext) { URL templateURL = getClass().getResource("tutorial.xhtml"); try { renderletManager.registerRenderlet(SeedsnipeRenderlet.class .getName(), new UriRef(templateURL.toURI().toString()), FOAF.Person, null, MediaType.APPLICATION_XHTML_XML_TYPE, true); } catch (URISyntaxException ex) { throw new WebApplicationException(ex); } TripleCollection tc; try { tcManager.getMGraph(graphName); } catch (NoSuchEntityException nsee) { tc = tcManager.createMGraph(graphName); InputStream fin = null; fin = getClass().getResourceAsStream("data.turtle"); Parser parser = Parser.getInstance(); tc.addAll(parser.parse(fin, "text/turtle")); } } }

The resource class above provides two resource methods to process GET requests specifying the path /foaf/find. The JAX-RS annotation @Path on TutorialApp sets the path of the resource to “/foaf”, while the JAX-RS annotation @Path on the resource methods getPersonRdf and getPersonHtml defines the subpath "find". Furthermore, the JAX-RS annotation @Produces defines the list of media types that a Java type or a method can produce. A media type corresponds with the representation of a resource. In this tutorial getPersonRdf should produce "application/rdf+xml", whereas getPersonHtml should produce "application/xhtml+xml". Both methods accept a parameter, whose value is obtained from the GET request parameter called mbox. This is defined through the JAX-RS annotation @QueryParam.

A resource can have multiple representations. For example, a web page can be represented as html, pdf, plain text, or other representations. The HTTP defines a mechanism known as content negotiation to allow a client (e.g., a web browser) to specify which representation it would like to get from the server. Using JAX-RS we can define a MessageBodyWriter which maps a Java type to a representation. In this tutorial getPersonRdf returns a Graph, whereas getPersonHtml returns a GraphNode, which represents a node in the context of a graph. The clerezza platform provides for either resources Graph and GraphNode a corresponding MessageBodyWriter.

The clerezza platform's TemplatingMessageBodyWriter produces a representation of the format "application/xhtml+xml" from a GraphNode, whereas the GraphWriter produces "application/rdf+xml" from a Graph. GraphWriter is implemented in the maven project org.clerezza.jaxrs.rdf.providers. The TemplatingMessageBodyWriter uses a templating engine to render a GraphNode based on a predefined template file. In order to allow a different GraphNode to be rendered using a different template, each GraphNode and template is bound to a specific RDF type.

For the purpose of registering a template, a RenderletManager service is made available. In this tutorial, a template (obtained from the file "tutorial.xhtml") is registered for the RDF type FOAF.Person (http://xmlns.com/foaf/0.1/Person). This is done in the activate method using the RenderletManager service.

In the activate method we also use the TcManager to get the MGraph called "http://localhost.mygraph". If this graph doesn't exist, a NoSuchEntityException is thrown. In this latter case, we catch this exception and create an MGraph. Afterwards we add the triples from the file mentioned above into the graph.

The following template renders a FOAF.Person. For easier readability namespaces can be defined. Statements which should be interpreted by the templating engine starts with the character $. The templating language allows loops and conditions. More examples are available on the project website of the templating engine (http://clerezza.org/projects/org.clerezza.templating.seedsnipe/documentation/overview.xhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> ${ns:foaf=http://xmlns.com/foaf/0.1/} <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>clerezza - Combined Tutorial</title> </head> <body> <h1>clerezza - Combined Tutorial</h1> <h2>FOAF Person:</h2> <div> <p>Name: ${foaf:title} ${foaf:name}</p> <p>Email: ${foaf:mbox}</p> ${if foaf:nick} <p>Nickname: ${foaf:nick}</p> ${/if} <p>Topic interests: <br /> ${loop} ${foaf:topic_interest}<br /> ${/loop} </p> </div> </body> </html>

4. Build

To build the package, execute the command:

$ mvn package

5. Installing the bundle in the Clerezza Platform

Download the latest clerezza platform launcher from http://repo.trialox.org/snapshot/org/clerezza/org.clerezza.platform.launcher.sesame/ and start it. Go to http://localhost:8080/user/admin/control-panel (enter username: admin, password; admin) and upload your bundle.

Test your bundle

Open the URL http://localhost:8080/foaf/find and add the URL parameter mbox=mailto:john@example.org to receive information about john

References

[1] R.T. Fielding: Architectural Styles and the Design of Network-based Software Architectures; CHAPTER 5 Representational State Transfer (REST), 2000, http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm

[2] Clerezza Smart Content Binding SCB http://clerezza.org/projects/org.clerezza.rdf.core/

[3] Clerezza Triaxrshttp://clerezza.org/projects/org.clerezza.triaxrs/

[4] Clerezza Triaxrs Tutorial 1http://clerezza.org/projects/org.clerezza.triaxrs/documentation/tutorial_1.xhtml

That's all folks for this time!

Copyright (c) 2008-2009 trialox.org (trialox AG, Switzerland)