From commits-return-5687-apmail-oodt-commits-archive=oodt.apache.org@oodt.apache.org Sun Aug 18 12:09:58 2013 Return-Path: X-Original-To: apmail-oodt-commits-archive@www.apache.org Delivered-To: apmail-oodt-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 411B210AF3 for ; Sun, 18 Aug 2013 12:09:58 +0000 (UTC) Received: (qmail 17819 invoked by uid 500); 18 Aug 2013 12:09:58 -0000 Delivered-To: apmail-oodt-commits-archive@oodt.apache.org Received: (qmail 17779 invoked by uid 500); 18 Aug 2013 12:09:51 -0000 Mailing-List: contact commits-help@oodt.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@oodt.apache.org Delivered-To: mailing list commits@oodt.apache.org Received: (qmail 17379 invoked by uid 99); 18 Aug 2013 12:09:47 -0000 Received: from arcas.apache.org (HELO arcas.apache.org) (140.211.11.28) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 18 Aug 2013 12:09:47 +0000 Date: Sun, 18 Aug 2013 12:09:47 +0000 (UTC) From: "Ross Laidlaw (JIRA)" To: commits@oodt.apache.org Message-ID: In-Reply-To: References: Subject: [jira] [Commented] (OODT-612) Implement a JAX-RS interface to access File Manager product information and metadata as configurable RDF streams MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-JIRA-FingerPrint: 30527f35849b9dde25b450d4833f0394 [ https://issues.apache.org/jira/browse/OODT-612?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13743188#comment-13743188 ] Ross Laidlaw commented on OODT-612: ----------------------------------- I've been experimenting with a different design that takes advantage of some of the built-in features of Apache CXF and capabilities of JAXRS. h4. Summary We could annotate our resource classes with JAXB annotations and JAXRS will then automatically marshal these classes into appropriate responses. We can map response types to file extensions (used in the URL) with the 'jaxrs.extensions' property in our web.xml. CXF will then select the appropriate provider to marshal the object into the desired format. CXF already has various data bindings for XML, JSON, etc. but we can also write our own custom providers to marshal objects into our desired formats (e.g. RDF, RSS). The providers can be configured using the 'jaxrs.providers' parameter in our web.xml. With XML as our base format, it's also possible for us to use XSLT transformations in our providers to transform the XML to other formats. h4. Details In our web.xml we can use the 'jaxrs.extensions' parameter to map extensions to MIME types, as follows: {code:xml|borderStyle=solid} jaxrs.extensions xml=application/xml json=application/json atom=application/atom+xml rdf=application/rdf+xml rss=application/rss+xml zip=application/zip {code} With this setting, we can add file extensions to the URL and JAXRS/CXF will attempt to return the MIME type associated with that extension, for example: {panel:title=Example URLs|borderStyle=solid} http://host/fmprod/service/reference.zip?... http://host/fmprod/service/product.xml?... http://host/fmprod/service/dataset.rdf?... http://host/fmprod/service/reference.rss?... http://host/fmprod/service/product.json?... http://host/fmprod/service/dataset.atom?... {panel} Then in our service class, we can annotate our response methods with the same MIME types and JAXRS will attempt to select the appropriate provider to provide the response: {code:java|borderStyle=solid} @GET @Path("product") @Produces({"application/xml", "application/json", "application/atom+xml", "application/rdf+xml", "application/rss+xml", "application/zip"}) public ProductResource getProduct(...) { ... } {code} Providers can be specified in web.xml using the 'jaxrs.providers' parameter. For example, CXF has a 'built-in' JSON capability, which can be enabled using the JSONProvider (along with JAXB annotated resources): {code:xml|borderStyle=solid} jaxrs.providers org.apache.cxf.jaxrs.provider.json.JSONProvider {code} As a side note, the following extra POM dependencies are needed for CXF data bindings and for example JSON using Jettison (other providers such as Jackson can be used instead): {code:xml|borderStyle=solid} org.apache.cxf cxf-rt-rs-extension-providers 2.6.8 org.codehaus.jettison jettison 1.3.4 {code} We can also write our own providers for different formats (e.g. RDF, RSS, etc) and add them to the jaxrs.providers list. CXF will then link the providers to the MIME types and deliver our resources in the desired format. To write a provider, we should annotate the class with @Provider and @Produces("[target_mime_type]") and implement javax.ws.rs.ext.MessageBodyWriter, for example: {code:java|title=ProductRdfWriter|borderStyle=solid} @Provider @Produces("application/rdf+xml") public class ProductRdfWriter implements MessageBodyWriter { @Override public long getSize(ProductResource resource, Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { return -1; } @Override public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { return type.isAnnotationPresent(XmlRootElement.class); } @Override public void writeTo(ProductResource resource, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { // write RDF representation to the 'entityStream' OutputStream. } } {code} The 'writeTo' method is where we write the desired output to the output stream that's sent in the response. In this method, we can use whatever we want to create the format we need. For CXF/JAXRS to pick up our custom writers, we should them to the list of providers in web.xml, e.g. as follows: {code:xml|borderStyle=solid} jaxrs.providers org.apache.cxf.jaxrs.provider.json.JSONProvider, org.apache.oodt.cas.product.service.ProductRdfWriter {code} To make the connection with our resource classes, I've implemented a single service class called 'CasProductService' to contain the @GET methods and handle all requests: {code:java|title=CasProductService.java|borderStyle=solid} public class CasProductService { @Context private ServletContext context; @GET @Path("product") @Produces({"application/xml", "application/json", "application/atom+xml", "application/rdf+xml", "application/rss+xml", "application/zip"}) public ProductResource getProduct(...) { ... } @GET @Path("dataset") @Produces({"application/xml", "application/json", "application/atom+xml", "application/rdf+xml", "application/rss+xml", "application/zip"}) public DatasetResource getDataset(...) { ... } } {code} This is specified as a service class in web.xml using the 'jaxrs.serviceClasses' parameter: {code:xml|borderStyle=solid} jaxrs.serviceClasses org.apache.oodt.cas.product.service.CasProductService {code} Our JAXB annotated resource classes can then be used as the return types for the methods. For example, shown partially below are three JAXRS annotated resource classes for products, metadata and references (ProductResource, MetadataResource and ReferenceResource): {code:java|title=ProductResource.java|borderStyle=solid} @XmlRootElement(name="product") @XmlAccessorType(XmlAccessType.NONE) public class ProductResource { private Product product; private MetadataResource metadata; private List references = new ArrayList(); public ProductResource() { } @XmlElement(name="id") public String getProductId() { return product.getProductId(); } @XmlElement(name="name") public String getProductName() { return product.getProductName(); } @XmlElement(name="structure") public String getProductStructure() { return product.getProductStructure(); } @XmlElement public MetadataResource getMetadata() { return metadata; } @XmlElementWrapper(name="references") @XmlElement(name="reference") public List getReferences() { return references; } } {code} {code:java|title=ReferenceResource.java|borderStyle=solid} @XmlRootElement(name="reference") @XmlAccessorType(XmlAccessType.NONE) public class ReferenceResource { private Reference reference; @XmlElement public String getDataStoreReference() { return reference.getDataStoreReference(); } @XmlElement public long getFileSize() { return reference.getFileSize(); } @XmlElement public String getMimeType() { MimeType m = reference.getMimeType(); if (m != null) { return m.getName(); } return null; } @XmlElement public String getOrigReference() { return reference.getOrigReference(); } } {code} {code:java|title=MetadataResource.java|borderStyle=solid} @XmlRootElement(name="metadata") @XmlAccessorType(XmlAccessType.NONE) public class MetadataResource { private Metadata metadata; @XmlElement(name="metadata") public Map getMetadatas() { Map map = new HashMap(); List keys = metadata.getAllKeys(); for (String key : keys) { map.put(key, metadata.getMetadata(key)); } return map; } } {code} Using the above setup, an example output is shown below for a request using ".xml" as the file extension in the URL (e.g. http://host/fmprod/service/product.xml?productID=1787a257-df87-11e2-8a2d-e3f6264e86c5): {code:xml|borderStyle=solid} 1787a257-df87-11e2-8a2d-e3f6264e86c5 test.txt Flat FileLocation /usr/local/oodt/filemgr/repository/test.txt ProductType GenericFile CAS.ProductId 1787a257-df87-11e2-8a2d-e3f6264e86c5 ProductStructure Flat MimeType text/plain CAS.ProductName test.txt CAS.ProductReceivedTime 2013-06-28T01:10:08.308Z Filename test.txt file:/usr/local/oodt/filemgr/repository/test.txt/test.txt 10 text/plain file:///tmp/test.txt {code} And here's the output after changing the extension from ".xml" to ".json" (i.e. http://host/fmprod/service/product.xml?productID=1787a257-df87-11e2-8a2d-e3f6264e86c5): {code:borderStyle=solid} {"product": {"id":"1787a257-df87-11e2-8a2d-e3f6264e86c5", "name":"test.txt", "structure":"Flat", "metadata": {"entry":[ {"key":"FileLocation","value":"\/usr\/local\/oodt\/filemgr\/repository\/test.txt"}, {"key":"ProductType","value":"GenericFile"}, {"key":"CAS.ProductId","value":"1787a257-df87-11e2-8a2d-e3f6264e86c5"}, {"key":"ProductStructure","value":"Flat"}, {"key":"MimeType","value":"text\/plain"}, {"key":"CAS.ProductName","value":"test.txt"}, {"key":"CAS.ProductReceivedTime","value":"2013-06-28T01:10:08.308Z"}, {"key":"Filename","value":"test.txt"}] }, "references": {"reference": {"dataStoreReference":"file:\/usr\/local\/oodt\/filemgr\/repository\/test.txt\/test.txt", "fileSize":10, "mimeType":"text\/plain", "origReference":"file:\/\/\/tmp\/test.txt"} } } } {code} It looks like it should be possible to use this approach to return files and zip archives as well, either by returning File objects directly from the service class or returning a resource marshalled via a custom provider (e.g. ProductZipWriter). > Implement a JAX-RS interface to access File Manager product information and metadata as configurable RDF streams > ---------------------------------------------------------------------------------------------------------------- > > Key: OODT-612 > URL: https://issues.apache.org/jira/browse/OODT-612 > Project: OODT > Issue Type: Sub-task > Components: product server > Affects Versions: 0.6 > Reporter: Ross Laidlaw > Assignee: Ross Laidlaw > Labels: gsoc2013 > Fix For: 0.7 > > > Add Java classes to the org.apache.oodt.cas.product.service package and add XML configuration files to allow File Manager product information and metadata to be accessible as RDF streams via a JAX-RS RESTful interface (URLs). > The URLs should allow information on single products to be retrieved by product ID, information on product sets to be retrieved by product type and information to be retrieved for any transfers in progress. > The new JAX-RS interface should also maintain backwards-compatibility with the URLs supported by the servlets in the org.apache.oodt.cas.product.rdf package, as detailed in the user guide: https://cwiki.apache.org/confluence/display/OODT/File+Manager+REST+API. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira