Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/stain/paq

Example of using PROV-AQ
https://github.com/stain/paq

Last synced: about 1 month ago
JSON representation

Example of using PROV-AQ

Awesome Lists containing this project

README

        

Providing provenance for a RESTful service
==========================================

This is an example of how a a RESTful service, implemented using [JAX-RS and CXF](http://cxf.apache.org/docs/jax-rs-basics.html), can expose [provenance](http://www.w3.org/TR/prov-overview/) of the resources it exposes.

There are two branches in this project on https://github.com/stain/paq:
* *master* - REST service that can say hello, and return provenance of greeting
* *paq* - REST service that also provides link between greeting and its provenance

To compile/run, you will need Java and [Maven](http://maven.apache.org/download.cgi):

PS C:\users\stain\src\paq> mvn clean jetty:run
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Example PROV-AQ usage 0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
(..)
2013-03-25 15:39:09.419:INFO::Started [email protected]:8080
[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 10 seconds.

The base URI should be http://localhost:8080/paq/ unless you modified the port with mvn -Djetty.port=9999

Check the HelloWorld REST service is working using your favourite HTTP client (e.g. browser or curl in a new terminal window).

PS C:\Users\stain\src\paq> curl http://localhost:8080/paq/hello/Alice
Hello, Alice

You may replace *Alice* with any name, as long as it is URI escaped:

PS C:\Users\stain\src\paq> curl http://localhost:8080/paq/hello/Joe%20Bloggs
Hello, Joe Bloggs

Provenance resource
-------------------

This example service provide [provenance](http://www.w3.org/TR/prov-overview/),
using the [PROV-N](http://www.w3.org/TR/prov-n/) format:

PS C:\Users\stain\src\paq> curl -i http://localhost:8080/paq/provenance/hello/Alice
HTTP/1.1 200 OK
Content-Type: text/provenance-notation
Date: Mon, 25 Mar 2013 15:41:02 GMT
Content-Length: 305
Server: Jetty(6.1.26)

document
prefix hello
prefix app
entity(hello:Alice)
wasDerivedFrom(hello:Alice, name)
entity(name, [ prov:value="Alice" ])
agent(app:hello, [ prov:type=prov:SoftwareAgent ])
wasAttributedTo(hello:Alice, app:hello)
endDocument

Note that we used the -i parameter above to verify that the correct media-type [text/provenance-notation](http://www.iana.org/assignments/media-types/text/provenance-notation) was returned.

This provenance says that the resource was derived from a name with value "Alice", and made by the (web) service .

This PROV-N trace is generated by HelloWorld.helloProvenance() by filling in the URIs and name in the template src/main/resources/provTemplate.txt - a more detailed provenance trace might include things like timestamps and details about who provided the name.

Providing links to the provenance
---------------------------------

A restful client who has requested will not magically know that there is a provenance trace at - the URI for the provenance resource could just as well have been say .

Rather than for each publisher to invent specific ways to locate the provenance resource, the W3C [PROV-AQ](http://www.w3.org/TR/prov-aq/) Note suggests a common way to find the provenance resource by using HTTP Link: headers according to [RFC5988](http://tools.ietf.org/html/rfc5988)

Specifically, PAQ says that a [resource accessed by HTTP](http://www.w3.org/TR/2013/WD-prov-aq-20130312/#resource-accessed-by-http) can
describe its provenance trace by adding a Link}} header with the relation "http://www.w3.org/ns/prov#has_provenance". So in our case, this can be achieved with:

Link: ; rel="http://www.w3.org/ns/prov#has_provenance"

OK, so how do we provide this Link header? Our existing greeting is
quite simple thanks to [JAX-RS and CXF](http://cxf.apache.org/docs/jax-rs-basics.html):

@GET
@Path("hello/{name}")
@Produces("text/plain")
public String hello(@PathParam("name") String name) {
String greeting = "Hello, " + name + "\n";
return greeting;
}

Our provenance method is a bit more complicated as it [generates
the absolute URIs](http://cxf.apache.org/docs/jax-rs-basics.html#JAX-RSBasics-URIcalculationusingUriInfoandUriBuilder) for the greeting resource (depending on the name parameter) and then build the PROV-N trace - here using a simple [MessageFormat](http://docs.oracle.com/javase/7/docs/api/java/text/MessageFormat.html) template.

@GET
@Path("provenance/hello/{name}")
@Produces("text/provenance-notation")
public String helloProvenance(@PathParam("name") String name,
@Context UriInfo ui) throws IOException {
// Get our absolute URI
// See http://cxf.apache.org/docs/jax-rs-basics.html#JAX-RSBasics-URIcalculationusingUriInfoandUriBuilder
UriBuilder appUri = ui.getBaseUriBuilder();
// Absolute URIs for resources we are to give provenance about
URI helloURI = appUri.path(getClass(), "hello").build(name);

// Prepare prefixes for PROV-N qualified names
URI appURI = appUri.build("").resolve("../");
URI helloPrefix = helloURI.resolve("./");

// The PROV-N qualified name for our /hello/{name} resource
String helloEntity = "hello:" + helloPrefix.relativize(helloURI);

// Simple PROV-N trace, see
// Here this is done in a naive way by loading a template
// from src/main/resources and do string-replace to insert
// our URIs.
String template = IOUtils.toString(getClass().getResourceAsStream("/provTemplate.txt"));
String prov = MessageFormat.format(template,
helloPrefix, appURI, helloEntity, name);
// Note: PROV-N should be be built using say the PROV Toolbox
// rather than this naive template approach!
return prov;
}

So in order to provide the RESTful links we will need to insert *Link:*
headers in the hello() response. As we need to return both the greeting and HTTP headers,
we change our return to a [Response](http://jax-rs-spec.java.net/nonav/2.0-SNAPSHOT/apidocs/javax/ws/rs/core/Response.html):

@GET
@Path("hello/{name}")
@Produces("text/plain")
public Response hello(@PathParam("name") String name) {
String greeting = "Hello, " + name + "\n";
ResponseBuilder responseBuilder = Response.ok().entity(greeting);
return responseBuilder.build();
}

We'll inject the same @Context UriInfo ui parameter as in
in order to find the absolute URI to calling the helloProvenance() method:

public Response hello(@PathParam("name") String name, @Context UriInfo ui) {
URI provUri = ui.getBaseUriBuilder().path(getClass(), "helloProvenance").build(name);

and then build a new [Link](http://jax-rs-spec.java.net/nonav/2.0-SNAPSHOT/apidocs/javax/ws/rs/core/Link.html) instance:

Link provLink = Link.fromUri(provUri).rel(HAS_PROVENANCE).build();

This uses the fixed URI for the provenance relation:

private static final String HAS_PROVENANCE = "http://www.w3.org/ns/prov#has_provenance";

Finally we include the new Link header by adding it to the response builder before returning:

return responseBuilder.header(HttpHeaders.LINK, provLink).build();

The final version of hello() should then look something like:

@GET
@Path("hello/{name}")
@Produces("text/plain")
public Response hello(@PathParam("name") String name, @Context UriInfo ui) {
String greeting = "Hello, " + name + "\n";
ResponseBuilder responseBuilder = Response.ok().entity(greeting);
// TODO: Could have used Link.fromResourceMethod but it seems to return wrong URI in CXF :(
URI provUri = ui.getBaseUriBuilder().path(getClass(), "helloProvenance").build(name);
Link provLink = Link.fromUri(provUri).rel(HAS_PROVENANCE).build();
return responseBuilder.header(HttpHeaders.LINK, provLink).build();
}

You may check out the paq branch from https://github.com/stain/paq to see the final version.

Finding the provenance links
----------------------------
If you have not followed the tutorial above, make sure you *check out* and *build*
the paq branch from https://github.com/stain/paq to include the PROV-AQ Link headers.