Author: rwesten
Date: Wed Feb 8 13:09:47 2012
New Revision: 1241888
URL: http://svn.apache.org/viewvc?rev=1241888&view=rev
Log:
STANBOL-481: Implementation of the MessageBodyReader/Writer for ContentItmes
including unit tests for both
They are not yet used by any Resource but they are fully functionally
Other changes:
* Corrected several Bugs/Issues in the ContentItemHelper utility
* Added required dependencies (see also comments of STANBOL-481) to the parent
POM and the commons bundle list
Added:
incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/reader/
incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/reader/ContentItemReader.java
(with props)
incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/
incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ContentItemWriter.java
(with props)
incubator/stanbol/trunk/enhancer/jersey/src/test/java/
incubator/stanbol/trunk/enhancer/jersey/src/test/java/org/
incubator/stanbol/trunk/enhancer/jersey/src/test/java/org/apache/
incubator/stanbol/trunk/enhancer/jersey/src/test/java/org/apache/stanbol/
incubator/stanbol/trunk/enhancer/jersey/src/test/java/org/apache/stanbol/enhancer/
incubator/stanbol/trunk/enhancer/jersey/src/test/java/org/apache/stanbol/enhancer/jersey/
incubator/stanbol/trunk/enhancer/jersey/src/test/java/org/apache/stanbol/enhancer/jersey/ContentItemReaderWriterTest.java
(with props)
Modified:
incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/ContentItem.java
incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ContentItemHelper.java
incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ContentItemImpl.java
incubator/stanbol/trunk/enhancer/jersey/pom.xml
incubator/stanbol/trunk/launchers/bundlelists/stanbolcommons/src/main/bundles/list.xml
incubator/stanbol/trunk/parent/pom.xml
Modified:
incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/ContentItem.java
URL:
http://svn.apache.org/viewvc/incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/ContentItem.java?rev=1241888&r1=1241887&r2=1241888&view=diff
==============================================================================
---
incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/ContentItem.java
(original)
+++
incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/ContentItem.java
Wed Feb 8 13:09:47 2012
@@ -78,18 +78,28 @@ public interface ContentItem {
* A content item may consists of multiple parts, while the part with
index 0 should always be a blob,
* higher position may be used by Enhancer to story arbitrary objects,
such objects can be used for
* accessing the precomputations of EnhancementEngines previous in the
chain.
- *
+ * @throws NoSuchPartException if no part with the parsed index exists
+ * @throws ClassCastException if the class of the part is not compatiple
with
+ * the requested class
+ * @throws IllegalArgumentException if <code>null</code> is parsed as
+ * clazz.
*/
<T> T getPart(int index, Class<T> clazz) throws NoSuchPartException;
/**
* Each part of the content item has a URI. EnhancementEngines typically
access parts by their Uri as the
* position may vary depending on the chain.
+ * @throws NoSuchPartException if no part with the parsed uri exists
+ * @throws ClassCastException if the class of the part is not compatiple
with
+ * the requested class
+ * @throws IllegalArgumentException if <code>null</code> is parsed as
+ * uri or clazz.
*/
<T> T getPart(UriRef uri, Class<T> clazz) throws NoSuchPartException;
/**
* Get the uri of the part at the specified index
+ * @throws NoSuchPartException if no part with the parsed index exists
*/
UriRef getPartUri(int index) throws NoSuchPartException;
@@ -100,6 +110,8 @@ public interface ContentItem {
* @param object the part
* @return the part replaced by the parsed object or <code>null</code> if
* no part with the parsed URI was present
+ * @throws IllegalArgumentException if <code>null</code> is parsed as
+ * uriRef or object.
*/
Object addPart(UriRef uriRef, Object object);
}
Modified:
incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ContentItemHelper.java
URL:
http://svn.apache.org/viewvc/incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ContentItemHelper.java?rev=1241888&r1=1241887&r2=1241888&view=diff
==============================================================================
---
incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ContentItemHelper.java
(original)
+++
incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ContentItemHelper.java
Wed Feb 8 13:09:47 2012
@@ -27,6 +27,9 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -230,7 +233,9 @@ public class ContentItemHelper {
* set only contains lower case values!
* <li> A read lock on the parsed {@link ContentItem} is applied while
* searching for a fitting {@link Blob}
- * </ul>
+ * </ul><p>
+ * In contrast to the contentPart related methods of the {@link
ContentItem}
+ * this method does NOT throw {@link NoSuchPartException}.
* @param ci the contentITem
* @param mimeTypes List of possible mimeTypes
* @return the {@link UriRef URI} and the {@link Blob content} of the
content
@@ -253,15 +258,19 @@ public class ContentItemHelper {
do {
try {
cpUri = ci.getPartUri(index);
- if(cpUri != null){
+ index++;
+ try {
Blob blob = ci.getPart(cpUri, Blob.class);
- if(blob != null && mimeTypes.contains(
- blob.getMimeType().toLowerCase())){
+
if(mimeTypes.contains(blob.getMimeType().toLowerCase())){
return Collections.singletonMap(cpUri, blob)
.entrySet().iterator().next();
} // else no match
- } // else no more parts
- } catch (NoSuchPartException e) {/* ignore*/}
+ } catch (ClassCastException e) {
+ // not a Blob -> ignore!
+ }
+ } catch (NoSuchPartException e) {
+ cpUri = null; // no more parts
+ }
} while(cpUri != null);
} finally {
ci.getLock().readLock().unlock();
@@ -269,6 +278,47 @@ public class ContentItemHelper {
return null; // not found
}
/**
+ * Returns a Map with the current content parts of the parsed type. future
+ * changes to the contentParts of the content item will NOT be reflected
+ * within the returned map. The ordering of the {@link Iterator}s over the
+ * returned map is consistent with the ordering of the contentPart within
the
+ * {@link ContentItem}. <p> When parsing {@link Object} as class the number
+ * of the element will be equals to the index of that content part.<p>
+ * In contrast to the contentPart related methods of the {@link
ContentItem}
+ * this method does NOT throw {@link NoSuchPartException}.
+ * @param ci the content item
+ * @param clazz the class of the content part
+ * @return the Map with the {@link UriRef id}s and the content as entries.
+ */
+ public static <T> LinkedHashMap<UriRef,T> getContentParts(ContentItem ci,
Class<T> clazz){
+ if(ci == null){
+ throw new IllegalArgumentException("The parsed ContentItem MUST
NOT be NULL!");
+ }
+ LinkedHashMap<UriRef,T> blobs = new LinkedHashMap<UriRef,T>();
+ UriRef cpUri = null;
+ int index = 0;
+ ci.getLock().readLock().lock();
+ try {
+ do {
+ try {
+ cpUri = ci.getPartUri(index);
+ index++;
+ try {
+ blobs.put(cpUri, ci.getPart(cpUri, clazz));
+ } catch (ClassCastException e) {
+ //not of type T -> skip
+ }
+ } catch (NoSuchPartException e) {
+ cpUri = null; // no more parts
+ }
+ } while(cpUri != null);
+ } finally {
+ ci.getLock().readLock().unlock();
+ }
+ return blobs;
+ }
+
+ /**
* Getter for the Text of an {@link Blob}. This method respects the
* "charset" if present in the {@link Blob#getParameter() parameter} of the
* Blob.
@@ -285,4 +335,20 @@ public class ContentItemHelper {
String charset = blob.getParameter().get("charset");
return IOUtils.toString(blob.getStream(), charset != null ? charset :
UTF8);
}
+ /**
+ * Creates the "{type}/{subtime}; [{param}={value}]+" mime type
representation
+ * for the {@link Blob#getMimeType()} and {@link Blob#getParameter()}
values
+ * @param blob the Blob
+ * @return the mime type with parameters (e.g. <code>
+ * text/plain;charset=UTF-8</code>)
+ */
+ public static String getMimeTypeWithParameters(Blob blob) {
+ StringBuilder mimeType = new StringBuilder(blob.getMimeType());
+ //ensure parameters are preserved
+ for(Entry<String,String> param : blob.getParameter().entrySet()){
+ mimeType.append(";
").append(param.getKey()).append('=').append(param.getValue());
+ }
+ return mimeType.toString();
+ }
+
}
Modified:
incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ContentItemImpl.java
URL:
http://svn.apache.org/viewvc/incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ContentItemImpl.java?rev=1241888&r1=1241887&r2=1241888&view=diff
==============================================================================
---
incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ContentItemImpl.java
(original)
+++
incubator/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ContentItemImpl.java
Wed Feb 8 13:09:47 2012
@@ -138,11 +138,17 @@ public abstract class ContentItemImpl im
public <T> T getPart(UriRef uri, Class<T> clazz) throws
NoSuchPartException {
readLock.lock();
try {
- if(parts.containsKey(uri)){
- return (T) parts.get(uri);
+ Object part = parts.get(uri);
+ if(part == null){
+ throw new NoSuchPartException(uri);
+ }
+ if(clazz.isAssignableFrom(part.getClass())){
+ return (T)part;
} else {
- throw new NoSuchPartException(uri);
- }
+ throw new ClassCastException("The part '"+part+"'(class: "
+ + part.getClass()+") is not compatiple to the
requested"
+ + "type "+clazz);
+ }
}finally {
readLock.unlock();
}
Modified: incubator/stanbol/trunk/enhancer/jersey/pom.xml
URL:
http://svn.apache.org/viewvc/incubator/stanbol/trunk/enhancer/jersey/pom.xml?rev=1241888&r1=1241887&r2=1241888&view=diff
==============================================================================
--- incubator/stanbol/trunk/enhancer/jersey/pom.xml (original)
+++ incubator/stanbol/trunk/enhancer/jersey/pom.xml Wed Feb 8 13:09:47 2012
@@ -59,7 +59,7 @@
<Export-Package>
org.apache.stanbol.enhancer.jersey.*
</Export-Package>
-
<Embed-Dependency>*;scope=compile|runtime;inline=false;artifactId=jersey-json|jettison|jackson-core-asl
+
<Embed-Dependency>*;scope=compile|runtime;inline=false;artifactId=jersey-json|jettison|jackson-core-asl|httpmime
</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
<Import-Package>
@@ -164,7 +164,20 @@
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
-
+ <!-- dependencies to read/write ContentItems as multipart mime -->
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore-osgi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpmime</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-fileupload</groupId>
+ <artifactId>commons-fileupload</artifactId>
+ <!-- <version>1.2.2</version> -->
+ </dependency>
<!-- OSGi tax -->
<dependency>
<groupId>org.osgi</groupId>
Added:
incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/reader/ContentItemReader.java
URL:
http://svn.apache.org/viewvc/incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/reader/ContentItemReader.java?rev=1241888&view=auto
==============================================================================
---
incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/reader/ContentItemReader.java
(added)
+++
incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/reader/ContentItemReader.java
Wed Feb 8 13:09:47 2012
@@ -0,0 +1,255 @@
+package org.apache.stanbol.enhancer.jersey.reader;
+
+import static
org.apache.stanbol.enhancer.servicesapi.helper.EnhancementEngineHelper.randomUUID;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+import java.util.Iterator;
+import java.util.Map.Entry;
+
+import javax.print.attribute.standard.Media;
+import javax.servlet.ServletContext;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.ext.MessageBodyReader;
+
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.TripleCollection;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.serializedform.Parser;
+import org.apache.clerezza.rdf.core.serializedform.ParsingProvider;
+import org.apache.clerezza.rdf.jena.parser.JenaParserProvider;
+import org.apache.commons.fileupload.FileItemIterator;
+import org.apache.commons.fileupload.FileItemStream;
+import org.apache.commons.fileupload.FileUpload;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.RequestContext;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.entity.mime.HttpMultipart;
+import org.apache.http.entity.mime.MultipartEntity;
+import org.apache.stanbol.commons.indexedgraph.IndexedMGraph;
+import org.apache.stanbol.commons.web.base.ContextHelper;
+import org.apache.stanbol.enhancer.jersey.writers.ContentItemWriter;
+import org.apache.stanbol.enhancer.servicesapi.Blob;
+import org.apache.stanbol.enhancer.servicesapi.ContentItem;
+import org.apache.stanbol.enhancer.servicesapi.helper.ContentItemHelper;
+import org.apache.stanbol.enhancer.servicesapi.helper.EnhancementEngineHelper;
+import org.apache.stanbol.enhancer.servicesapi.helper.InMemoryBlob;
+import org.apache.stanbol.enhancer.servicesapi.helper.InMemoryContentItem;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.core.util.MultivaluedMapImpl;
+import com.sun.jersey.core.util.StringKeyIgnoreCaseMultivaluedMap;
+
+public class ContentItemReader implements MessageBodyReader<ContentItem> {
+
+ private static Logger log =
LoggerFactory.getLogger(ContentItemReader.class);
+ FileUpload fu = new FileUpload();
+ private ServletContext servletContext;
+ private Parser parser;
+
+ public static final MediaType MULTIPART =
MediaType.valueOf(MediaType.MULTIPART_FORM_DATA_TYPE.getType()+"/*");
+
+ public ContentItemReader(@Context ServletContext context) {
+ this.servletContext = context;
+ if(context != null){
+ this.parser = ContextHelper.getServiceFromContext(Parser.class,
context);
+ } else { //mainly for unit tests we want also allow initialisation
without context
+ this.parser = new Parser();
+ parser.bindParsingProvider(new JenaParserProvider());
+ }
+ }
+ @Override
+ public boolean isReadable(Class<?> type, Type genericType, Annotation[]
annotations, MediaType mediaType) {
+ return ContentItem.class.isAssignableFrom(type);
+ }
+
+ @Override
+ public ContentItem readFrom(Class<ContentItem> type,
+ Type genericType,
+ Annotation[] annotations,
+ MediaType mediaType,
+ MultivaluedMap<String,String> httpHeaders,
+ InputStream entityStream) throws IOException,
WebApplicationException {
+ //boolean withMetadata = withMetadata(httpHeaders);
+ ContentItem contentItem = null;
+ if(mediaType.isCompatible(MULTIPART)){
+ //try to read ContentItem from "multipart/from-data"
+ MGraph metadata = null;
+ FileItemIterator fileItemIterator;
+ String contentItemId = null;
+ try {
+ fileItemIterator = fu.getItemIterator(new
MessageBodyReaderContext(entityStream, mediaType));
+ while(fileItemIterator.hasNext()){
+ FileItemStream fis = fileItemIterator.next();
+ if(fis.getFieldName().equals("metadata")){
+ if(contentItem != null){
+ throw new WebApplicationException(
+ Response.status(Response.Status.BAD_REQUEST)
+ .entity("The Multipart MIME part with the
'metadata' " +
+ "MUST BE before the MIME part
containing the " +
+ "'content'!").build());
+ }
+ //the metadata may define the ID for the contentItem
+ if(fis.getName() != null && !fis.getName().isEmpty()){
+ contentItemId = fis.getName();
+ }
+ metadata = new IndexedMGraph();
+ try {
+ parser.parse(metadata, fis.openStream(),
fis.getContentType());
+ } catch (Exception e) {
+ throw new WebApplicationException(e,
+ Response.status(Response.Status.BAD_REQUEST)
+ .entity(String.format("Unable to parse
Metadata " +
+ "from Multipart MIME part '%s'
(" +
+ "contentItem: %s| contentType:
%s)",
+
fis.getFieldName(),fis.getName(),fis.getContentType()))
+ .build());
+ }
+ } else if(fis.getFieldName().equals("content")){
+ contentItem = createContentItem(contentItemId,
metadata, fis);
+ } else { //additional metadata as serialised RDF
+ if(contentItem == null){
+ throw new WebApplicationException(
+ Response.status(Response.Status.BAD_REQUEST)
+ .entity("Multipart MIME parts for additional "
+
+ "contentParts MUST BE after the
MIME " +
+ "parts for 'metadata' AND
'content'")
+ .build());
+ }
+ if(fis.getFieldName() == null ||
fis.getFieldName().isEmpty()){
+ throw new WebApplicationException(
+ Response.status(Response.Status.BAD_REQUEST)
+ .entity("Multipart MIME parts representing " +
+ "ContentParts for additional
RDF metadata" +
+ "MUST define the contentParts
URI as" +
+ "'name' of the MIME
part!").build());
+ }
+ MGraph graph = new IndexedMGraph();
+ try {
+ parser.parse(graph, fis.openStream(),
fis.getContentType());
+ } catch (Exception e) {
+ throw new WebApplicationException(e,
+ Response.status(Response.Status.BAD_REQUEST)
+ .entity(String.format("Unable to parse RDF " +
+ "for ContentPart '%s' ( contentType:
%s)",
+ fis.getName(),fis.getContentType()))
+ .build());
+ }
+ contentItem.addPart(new UriRef(fis.getFieldName()),
graph);
+ }
+ }
+ } catch (FileUploadException e) {
+ throw new WebApplicationException(e,
Response.Status.BAD_REQUEST);
+ }
+ } else { //normal content
+ contentItem = new InMemoryContentItem(
+ IOUtils.toByteArray(entityStream), mediaType.toString());
+ }
+ return contentItem;
+ }
+ private ContentItem createContentItem(String id, MGraph metadata,
FileItemStream content) throws IOException, FileUploadException {
+ MediaType partContentType =
MediaType.valueOf(content.getContentType());
+ ContentItem contentItem = null;
+ if(partContentType.isCompatible(MULTIPART)){
+ //multiple contentParts are parsed
+ FileItemIterator contentPartIterator = fu.getItemIterator(
+ new MessageBodyReaderContext(
+ content.openStream(), partContentType));
+ while(contentPartIterator.hasNext()){
+ FileItemStream fis = contentPartIterator.next();
+ String contentPartUri = fis.getFieldName();
+ if(contentItem == null){
+ contentItem = new InMemoryContentItem(id,
+ IOUtils.toByteArray(fis.openStream()),
+ fis.getContentType(), metadata);
+ } else {
+ Blob blob = new InMemoryBlob(fis.openStream(),
fis.getContentType());
+ UriRef contentPartId = null;
+ if(fis.getFieldName() != null &&
!fis.getFieldName().isEmpty()){
+ contentPartId = new UriRef(fis.getFieldName());
+ } else {
+ //generating a random ID might break metadata
+ //TODO maybe we should throw an exception instead
+ contentPartId = new UriRef("urn:contentpart:"+
randomUUID());
+ }
+ contentItem.addPart(contentPartId, blob);
+ }
+ }
+ } else {
+ contentItem = new InMemoryContentItem(id,
+ IOUtils.toByteArray(content.openStream()),
+ content.getContentType(), metadata);
+ }
+ return contentItem;
+ }
+
+ /**
+ * @param httpHeaders
+ * @return if this requests parses an contentItem with metadata
+ */
+ private boolean withMetadata(MultivaluedMap<String,String> httpHeaders) {
+ boolean withMetadata = httpHeaders.containsKey("inputWithMetadata");
+ if(withMetadata){
+ String value = httpHeaders.getFirst("inputWithMetadata");
+ //null empty or "true"
+ withMetadata = value == null || value.isEmpty() ||
Boolean.parseBoolean(value);
+ }
+ return withMetadata;
+ }
+ /**
+ * Adapter from the parameter present in an {@link MessageBodyReader} to
+ * the {@link RequestContext} as used by the commons.fileupload framework
+ * @author rwesten
+ *
+ */
+ private static class MessageBodyReaderContext implements RequestContext{
+
+ private final InputStream in;
+ private final String contentType;
+ private final String charEncoding;
+
+ public MessageBodyReaderContext(InputStream in, MediaType mediaType){
+ this.in = in;
+ this.contentType = mediaType.toString();
+ String charset = mediaType.getParameters().get("charset");
+ this.charEncoding = charset == null ? "UTF-8" : charset;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return charEncoding;
+ }
+
+ @Override
+ public String getContentType() {
+ return contentType;
+ }
+
+ @Override
+ public int getContentLength() {
+ return -1;
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return in;
+ }
+
+ }
+
+}
Propchange:
incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/reader/ContentItemReader.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ContentItemWriter.java
URL:
http://svn.apache.org/viewvc/incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ContentItemWriter.java?rev=1241888&view=auto
==============================================================================
---
incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ContentItemWriter.java
(added)
+++
incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ContentItemWriter.java
Wed Feb 8 13:09:47 2012
@@ -0,0 +1,212 @@
+package org.apache.stanbol.enhancer.jersey.writers;
+
+import static
org.apache.stanbol.enhancer.servicesapi.helper.ContentItemHelper.getContentParts;
+import static
org.apache.stanbol.enhancer.servicesapi.helper.ContentItemHelper.getMimeTypeWithParameters;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map.Entry;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.NonLiteral;
+import org.apache.clerezza.rdf.core.TripleCollection;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.apache.clerezza.rdf.core.serializedform.Serializer;
+import org.apache.clerezza.rdf.core.serializedform.SupportedFormat;
+import org.apache.clerezza.rdf.jena.serializer.JenaSerializerProvider;
+import org.apache.clerezza.rdf.ontologies.RDF;
+import org.apache.http.entity.mime.FormBodyPart;
+import org.apache.http.entity.mime.HttpMultipart;
+import org.apache.http.entity.mime.MultipartEntity;
+import org.apache.http.entity.mime.content.AbstractContentBody;
+import org.apache.http.entity.mime.content.ContentBody;
+import org.apache.http.entity.mime.content.ContentDescriptor;
+import org.apache.http.entity.mime.content.InputStreamBody;
+import org.apache.stanbol.commons.web.base.ContextHelper;
+import org.apache.stanbol.enhancer.servicesapi.Blob;
+import org.apache.stanbol.enhancer.servicesapi.ContentItem;
+import org.apache.stanbol.enhancer.servicesapi.helper.ExecutionMetadataHelper;
+import org.apache.stanbol.enhancer.servicesapi.helper.ExecutionPlanHelper;
+import org.apache.stanbol.enhancer.servicesapi.helper.InMemoryBlob;
+import org.apache.stanbol.enhancer.servicesapi.helper.InMemoryContentItem;
+
+import com.sun.jersey.core.util.StringKeyIgnoreCaseMultivaluedMap;
+
+@Provider
+public class ContentItemWriter implements MessageBodyWriter<ContentItem> {
+
+ protected ServletContext servletContext;
+
+ protected Serializer serializer;
+
+ public ContentItemWriter(@Context ServletContext servletContext){
+ this.servletContext = servletContext;
+ if(servletContext != null){
+ serializer = ContextHelper.getServiceFromContext(Serializer.class,
servletContext);
+ } else {
+ serializer = new Serializer();
+ serializer.bindSerializingProvider(new JenaSerializerProvider());
+ }
+ }
+
+ @Override
+ public boolean isWriteable(Class<?> type, Type genericType, Annotation[]
annotations, MediaType mediaType) {
+ return MediaType.MULTIPART_FORM_DATA_TYPE.isCompatible(mediaType) &&
+ ContentItem.class.isAssignableFrom(type);
+ }
+
+ @Override
+ public long getSize(ContentItem t,
+ Class<?> type,
+ Type genericType,
+ Annotation[] annotations,
+ MediaType mediaType) {
+ return -1;
+ }
+
+ @Override
+ public void writeTo(ContentItem ci,
+ Class<?> type,
+ Type genericType,
+ Annotation[] annotations,
+ MediaType mediaType,
+ MultivaluedMap<String,Object> httpHeaders,
+ OutputStream entityStream) throws IOException,
WebApplicationException {
+
+ String boundary = "contentItem";
+ String charsetName = mediaType.getParameters().get("charset");
+ if(charsetName == null){
+ charsetName = "UTF-8";
+ }
+ Charset charset = Charset.forName(charsetName);
+ String contentType = String.format("%s/%s; charset=%s; boundary=%s",
+
mediaType.getType(),mediaType.getSubtype(),charset.toString(),boundary);
+ HttpMultipart entity = new HttpMultipart("from-data",
charset,boundary);
+ entity.addBodyPart(new FormBodyPart("metadata", new
ClerezzaContentBody(
+ ci.getUri().getUnicodeString(), ci.getMetadata(),
+ //TODO: find a way to parse the intended RDF serialisation format
+ SupportedFormat.RDF_XML)));
+
+ HttpMultipart content = new HttpMultipart("alternate",
Charset.forName("UTF-8"),"contentParts");
+ for(Entry<UriRef,Blob> entry :
getContentParts(ci,Blob.class).entrySet()){
+ content.addBodyPart(new
FormBodyPart(entry.getKey().getUnicodeString(),
+ new InputStreamBody(
+ entry.getValue().getStream(),
+ getMimeTypeWithParameters(entry.getValue()),
+ null))); //no file name
+ }
+ //add all the blobs
+ entity.addBodyPart(new FormBodyPart("content",new
MultipartContentBody(content, null)));
+ //add additional metadata stored in contentParts
+ for(Entry<UriRef,TripleCollection> entry : getContentParts(ci,
TripleCollection.class).entrySet()){
+ entity.addBodyPart(new
FormBodyPart(entry.getKey().getUnicodeString(),
+ new ClerezzaContentBody(null, //no file name
+ entry.getValue(),SupportedFormat.RDF_XML)));
+ }
+ entity.writeTo(entityStream);
+ httpHeaders.put(HttpHeaders.CONTENT_TYPE,
+ Collections.singletonList((Object)contentType));
+ }
+
+ /**
+ * Supports sending multipart mime as {@link ContentBody}.
+ * @author Rupert Westenthaler
+ *
+ */
+ private class MultipartContentBody extends AbstractContentBody implements
ContentBody,ContentDescriptor {
+
+ private HttpMultipart multipart;
+ private String name;
+
+ public MultipartContentBody(HttpMultipart multipart,String name){
+ super(String.format("multipart/%s; boundary=%s",
+ multipart.getSubType(), multipart.getBoundary()));
+ this.name = name;
+ this.multipart = multipart;
+ }
+ @Override
+ public String getCharset() {
+ return multipart.getCharset().toString();
+ }
+
+ @Override
+ public String getTransferEncoding() {
+ return "7bit";
+ }
+
+ @Override
+ public long getContentLength() {
+ return multipart.getTotalLength();
+ }
+
+ @Override
+ public String getFilename() {
+ return name;
+ }
+
+ @Override
+ public void writeTo(OutputStream out) throws IOException {
+ multipart.writeTo(out);
+ }
+
+ }
+ /**
+ * Supports serialised RDF graphs as {@link ContentBody}
+ * @author Rupert Westenthaler
+ *
+ */
+ private class ClerezzaContentBody extends AbstractContentBody implements
ContentBody,ContentDescriptor {
+
+ private TripleCollection graph;
+ private String name;
+
+ protected ClerezzaContentBody(String name, TripleCollection graph,
String mimeType){
+ super(mimeType);
+ this.name = name;
+ this.graph = graph;
+ }
+
+ @Override
+ public String getCharset() {
+ return "UTF-8"; //clerezza uses statically UTF-8
+ }
+
+ @Override
+ public String getTransferEncoding() {
+ // TODO Javadoc says 7bit; constants is MIMETYPE define 8bit and
binary
+ return "7bit";
+ }
+
+ @Override
+ public long getContentLength() {
+ return -1;
+ }
+
+ @Override
+ public String getFilename() {
+ return name;
+ }
+
+ @Override
+ public void writeTo(OutputStream out) throws IOException {
+ serializer.serialize(out, graph, getMediaType()+'/'+getSubType());
+ }
+
+
+ }
+}
Propchange:
incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ContentItemWriter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
incubator/stanbol/trunk/enhancer/jersey/src/test/java/org/apache/stanbol/enhancer/jersey/ContentItemReaderWriterTest.java
URL:
http://svn.apache.org/viewvc/incubator/stanbol/trunk/enhancer/jersey/src/test/java/org/apache/stanbol/enhancer/jersey/ContentItemReaderWriterTest.java?rev=1241888&view=auto
==============================================================================
---
incubator/stanbol/trunk/enhancer/jersey/src/test/java/org/apache/stanbol/enhancer/jersey/ContentItemReaderWriterTest.java
(added)
+++
incubator/stanbol/trunk/enhancer/jersey/src/test/java/org/apache/stanbol/enhancer/jersey/ContentItemReaderWriterTest.java
Wed Feb 8 13:09:47 2012
@@ -0,0 +1,164 @@
+package org.apache.stanbol.enhancer.jersey;
+
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map.Entry;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.NonLiteral;
+import org.apache.clerezza.rdf.core.TripleCollection;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.impl.SimpleMGraph;
+import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.apache.clerezza.rdf.ontologies.RDF;
+import org.apache.commons.io.IOUtils;
+import org.apache.stanbol.commons.indexedgraph.IndexedMGraph;
+import org.apache.stanbol.enhancer.jersey.reader.ContentItemReader;
+import org.apache.stanbol.enhancer.jersey.writers.ContentItemWriter;
+import org.apache.stanbol.enhancer.servicesapi.Blob;
+import org.apache.stanbol.enhancer.servicesapi.ContentItem;
+import org.apache.stanbol.enhancer.servicesapi.helper.ContentItemHelper;
+import org.apache.stanbol.enhancer.servicesapi.helper.ExecutionMetadataHelper;
+import org.apache.stanbol.enhancer.servicesapi.helper.ExecutionPlanHelper;
+import org.apache.stanbol.enhancer.servicesapi.helper.InMemoryBlob;
+import org.apache.stanbol.enhancer.servicesapi.helper.InMemoryContentItem;
+import org.apache.stanbol.enhancer.servicesapi.rdf.ExecutionMetadata;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.sun.jersey.core.util.StringKeyIgnoreCaseMultivaluedMap;
+
+public class ContentItemReaderWriterTest {
+
+ private static ContentItem contentItem;
+ private static ContentItemWriter ciWriter;
+ private static ContentItemReader ciReader;
+ /**
+ * @return
+ */
+ @BeforeClass
+ public static void createTestContentItem() {
+ contentItem = new InMemoryContentItem("urn:test",
+ "<html>\n" +
+ " <body>\n" +
+ " This is a <b>ContentItem</b> to <i>Mime Multipart</i>
test!\n" +
+ " </body>\n" +
+ "</html>","text/html");
+ contentItem.addPart(new UriRef("run:text:text"), new InMemoryBlob(
+ "This is a ContentItem to Mime Multipart test!", "text/plain"));
+ contentItem.getMetadata().add(new TripleImpl(
+ new UriRef("urn:test"), RDF.type, new
UriRef("urn:types:Document")));
+ MGraph em
=ExecutionMetadataHelper.initExecutionMetadataContentPart(contentItem);
+ NonLiteral ep = ExecutionPlanHelper.createExecutionPlan(em,
"testChain");
+ ExecutionPlanHelper.writeExecutionNode(em, ep, "testEngine", true,
null);
+ ExecutionMetadataHelper.initExecutionMetadata(em, em,
contentItem.getUri(), "testChain", false);
+ ciWriter = new ContentItemWriter(null);
+ ciReader = new ContentItemReader(null);
+ }
+ /**
+ * @param out
+ * @return
+ * @throws IOException
+ */
+ private MediaType serializeContentItem(ByteArrayOutputStream out) throws
IOException {
+ MultivaluedMap<String,Object> headers = new
StringKeyIgnoreCaseMultivaluedMap<Object>();
+ ciWriter.writeTo(contentItem, ContentItem.class, null, null,
MediaType.MULTIPART_FORM_DATA_TYPE,
+ headers , out);
+ //check the returned content type
+ String contentTypeString =
(String)headers.getFirst(HttpHeaders.CONTENT_TYPE);
+ assertNotNull(contentTypeString);
+ MediaType contentType = MediaType.valueOf(contentTypeString);
+ return contentType;
+ }
+
+ @Test
+ public void testWriter() throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ MediaType contentType = serializeContentItem(out);
+
assertTrue(MediaType.MULTIPART_FORM_DATA_TYPE.isCompatible(contentType));
+ assertNotNull(contentType.getParameters().get("boundary"));
+
assertEquals(contentType.getParameters().get("boundary"),"contentItem");
+ assertNotNull(contentType.getParameters().get("charset"));
+ assertEquals(contentType.getParameters().get("charset"),"UTF-8");
+ //check the serialised multipart MIME
+ String multipartMime = new
String(out.toByteArray(),Charset.forName(contentType.getParameters().get("charset")));
+ String[] tests = new String[]{
+ "--"+contentType.getParameters().get("boundary"),
+ "Content-Disposition: form-data; name=\"metadata\";
filename=\"urn:test\"",
+ "Content-Type: application/rdf+xml; charset=UTF-8",
+ "<rdf:type rdf:resource=\"urn:types:Document\"/>",
+ "--"+contentType.getParameters().get("boundary"),
+ "Content-Disposition: form-data; name=\"content\"",
+ "Content-Type: multipart/alternate; boundary=contentParts;
charset=UTF-8",
+ "--contentParts",
+ "Content-Disposition: form-data; name=\"urn:test_main\"",
+ "Content-Type: text/html; charset=UTF-8",
+ "This is a <b>ContentItem</b> to <i>Mime Multipart</i> test!",
+ "--contentParts",
+ "Content-Disposition: form-data; name=\"run:text:text\"",
+ "Content-Type: text/plain; charset=UTF-8",
+ "This is a ContentItem to Mime Multipart test!",
+ "--contentParts--",
+ "--"+contentType.getParameters().get("boundary"),
+ "Content-Disposition: form-data;
name=\"http://stanbol.apache.org/ontology/enhancer/executionMetadata#ChainExecution\"",
+ "Content-Type: application/rdf+xml; charset=UTF-8",
+ "<rdf:type
rdf:resource=\"http://stanbol.apache.org/ontology/enhancer/executionplan#ExecutionNode\"/>",
+ "--"+contentType.getParameters().get("boundary")+"--"
+ };
+ for(String test : tests){
+ int index = multipartMime.indexOf(test);
+ assertTrue(index >=0);
+ multipartMime = multipartMime.substring(index);
+ }
+ }
+
+ @Test
+ public void testReader() throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ MediaType contentType = serializeContentItem(out);
+ ContentItemReader cir = new ContentItemReader(null);
+ ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+ ContentItem ci = cir.readFrom(ContentItem.class, null, null,
contentType, null, in);
+ //assert ID
+ assertEquals(contentItem.getUri(), ci.getUri());
+ //assert metadata
+ MGraph copy = new SimpleMGraph();
+ copy.addAll(contentItem.getMetadata());
+ assertTrue(copy.removeAll(ci.getMetadata()));
+ assertTrue(copy.isEmpty());
+ //assert Blob
+ assertEquals(contentItem.getBlob().getMimeType(),
ci.getBlob().getMimeType());
+ String content = IOUtils.toString(contentItem.getStream(),"UTF-8");
+ String readContent = IOUtils.toString(ci.getStream(), "UTF-8");
+ assertEquals(content, readContent);
+ Iterator<Entry<UriRef,Blob>> contentItemBlobsIt =
ContentItemHelper.getContentParts(contentItem,
Blob.class).entrySet().iterator();
+ Iterator<Entry<UriRef,Blob>> ciBlobsIt =
ContentItemHelper.getContentParts(ci, Blob.class).entrySet().iterator();
+ while(contentItemBlobsIt.hasNext() && ciBlobsIt.hasNext()){
+ Entry<UriRef,Blob> contentItemBlobPart = contentItemBlobsIt.next();
+ Entry<UriRef,Blob> ciBlobPart = ciBlobsIt.next();
+ assertEquals(contentItemBlobPart.getKey(), ciBlobPart.getKey());
+ String partContentType =
contentItemBlobPart.getValue().getMimeType();
+ String readPartContentType = ciBlobPart.getValue().getMimeType();
+ assertEquals(partContentType, readPartContentType);
+ String partContent =
IOUtils.toString(contentItemBlobPart.getValue().getStream(),"UTF-8");
+ String readPartContent =
IOUtils.toString(ciBlobPart.getValue().getStream(), "UTF-8");
+ assertEquals(partContent, readPartContent);
+ }
+ MGraph executionMetadata =
contentItem.getPart(ExecutionMetadata.CHAIN_EXECUTION, MGraph.class);
+ MGraph readExecutionMetadata =
ci.getPart(ExecutionMetadata.CHAIN_EXECUTION, MGraph.class);
+ assertNotNull(executionMetadata);
+ assertNotNull(readExecutionMetadata);
+ assertEquals(executionMetadata.size(), readExecutionMetadata.size());
+ }
+
+}
Propchange:
incubator/stanbol/trunk/enhancer/jersey/src/test/java/org/apache/stanbol/enhancer/jersey/ContentItemReaderWriterTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified:
incubator/stanbol/trunk/launchers/bundlelists/stanbolcommons/src/main/bundles/list.xml
URL:
http://svn.apache.org/viewvc/incubator/stanbol/trunk/launchers/bundlelists/stanbolcommons/src/main/bundles/list.xml?rev=1241888&r1=1241887&r2=1241888&view=diff
==============================================================================
---
incubator/stanbol/trunk/launchers/bundlelists/stanbolcommons/src/main/bundles/list.xml
(original)
+++
incubator/stanbol/trunk/launchers/bundlelists/stanbolcommons/src/main/bundles/list.xml
Wed Feb 8 13:09:47 2012
@@ -107,11 +107,6 @@
<version>1.0</version>
</bundle>
<bundle>
- <groupId>org.apache.httpcomponents</groupId>
- <artifactId>httpcore-osgi</artifactId>
- <version>4.0.1</version>
- </bundle>
- <bundle>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.5</version>
@@ -121,6 +116,17 @@
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</bundle>
+ <bundle>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore-osgi</artifactId>
+ <version>4.1.4</version>
+ </bundle>
+<!-- not a bundle (need to be embedded)
+ <bundle>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpmime</artifactId>
+ <version>4.1.2</version>
+ </bundle> -->
<bundle> <!-- only used by the Entityhub -->
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
Modified: incubator/stanbol/trunk/parent/pom.xml
URL:
http://svn.apache.org/viewvc/incubator/stanbol/trunk/parent/pom.xml?rev=1241888&r1=1241887&r2=1241888&view=diff
==============================================================================
--- incubator/stanbol/trunk/parent/pom.xml (original)
+++ incubator/stanbol/trunk/parent/pom.xml Wed Feb 8 13:09:47 2012
@@ -1004,7 +1004,16 @@
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
-
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore-osgi</artifactId>
+ <version>4.1.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpmime</artifactId>
+ <version>4.1.2</version>
+ </dependency>
<!-- Joda Time -->
<dependency>
@@ -1091,13 +1100,6 @@
<version>${jersey-version}</version>
</dependency>
-<!-- jersey-multipart now uses a different library allowing streaming of
- binary data (see http://mimepull.java.net/)
- <dependency>
- <groupId>javax.mail</groupId>
- <artifactId>mail</artifactId>
- <version>1.4</version>
- </dependency> -->
<!-- JAX-RS JSR311 -->
<!-- NOTE that JAX-RS is included and exported by jersey-core