You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stanbol.apache.org by og...@apache.org on 2011/03/28 20:41:25 UTC
svn commit: r1086333 - in
/incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java:
./ org/ org/apache/ org/apache/stanbol/ org/apache/stanbol/enhancer/
org/apache/stanbol/enhancer/jersey/ org/apache/stanbol/enhancer/jersey/c...
Author: ogrisel
Date: Mon Mar 28 18:41:24 2011
New Revision: 1086333
URL: http://svn.apache.org/viewvc?rev=1086333&view=rev
Log:
STANBOL-120: started to refactor enhancer/jersey to use the new WebFragment incremental contribution system (step 3)
Added:
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/cache/
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/cache/CachingDereferencerEngine.java
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/cache/EntityCacheProvider.java
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/fragment/
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/fragment/EnhancerWebFragment.java
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/ContentItemResource.java
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/EnginesRootResource.java
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/SparqlQueryResource.java
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/StoreRootResource.java
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/GraphWriter.java
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/JsonLdSerializerProvider.java
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ResultSetToXml.java
incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ResultSetWriter.java
Added: incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/cache/CachingDereferencerEngine.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/cache/CachingDereferencerEngine.java?rev=1086333&view=auto
==============================================================================
--- incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/cache/CachingDereferencerEngine.java (added)
+++ incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/cache/CachingDereferencerEngine.java Mon Mar 28 18:41:24 2011
@@ -0,0 +1,227 @@
+package org.apache.stanbol.enhancer.jersey.cache;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.clerezza.rdf.core.Graph;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.TripleCollection;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.NoSuchEntityException;
+import org.apache.clerezza.rdf.core.access.WeightedTcProvider;
+import org.apache.clerezza.rdf.core.impl.SimpleMGraph;
+import org.apache.clerezza.rdf.core.serializedform.Parser;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.stanbol.enhancer.servicesapi.ContentItem;
+import org.apache.stanbol.enhancer.servicesapi.EngineException;
+import org.apache.stanbol.enhancer.servicesapi.EnhancementEngine;
+import org.apache.stanbol.enhancer.servicesapi.EnhancementJobManager;
+import org.apache.stanbol.enhancer.servicesapi.ServiceProperties;
+import org.apache.stanbol.enhancer.servicesapi.Store;
+import org.apache.stanbol.enhancer.servicesapi.rdf.Properties;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+import static org.apache.clerezza.rdf.core.serializedform.SupportedFormat.RDF_XML;
+
+/**
+ * Simple engine that does not enhance content items but fetches resources
+ * metadata from remote sites to cache them locally for the sole purpose of
+ * displaying up to date data in the user interface.
+ * <p>
+ * This engine might be replaced by a proper dereferencer engine in a future
+ * version of enhancer.
+ *
+ * @author Olivier Grisel
+ */
+@Component(immediate = true, metatype = true)
+@Service
+public class CachingDereferencerEngine implements EnhancementEngine,
+ ServiceProperties, EntityCacheProvider {
+
+ public static final String ENTITY_CACHE_GRAPH_NAME = "enhancerEntityCache";
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ /**
+ * The default value for the Execution of this Engine. Currently set to
+ * {@link EnhancementJobManager#DEFAULT_ORDER}
+ */
+ public static final Integer defaultOrder = ORDERING_POST_PROCESSING;
+
+ @Reference
+ protected Parser parser;
+
+ @Reference
+ protected Store store;
+
+ @Reference
+ protected WeightedTcProvider tcProvider;
+
+ protected ThreadPoolExecutor executor;
+
+ protected BlockingQueue<TripleCollection> serializationQueue;
+
+ protected Thread serializer;
+
+ protected boolean serializerActive = false;
+
+ protected LinkedBlockingQueue<Runnable> fetchTaskQueue;
+
+ protected void activate(ComponentContext ce) throws IOException {
+ fetchTaskQueue = new LinkedBlockingQueue<Runnable>();
+ executor = new ThreadPoolExecutor(4, 10, 5, TimeUnit.MINUTES,
+ fetchTaskQueue);
+ serializationQueue = new LinkedBlockingQueue<TripleCollection>();
+ final MGraph entityCache = getEntityCache();
+ serializerActive = true;
+ serializer = new Thread() {
+ @Override
+ public void run() {
+ while (serializerActive) {
+ try {
+ entityCache.addAll(serializationQueue.take());
+ } catch (InterruptedException e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+ };
+ serializer.start();
+ }
+
+ protected void deactivate(ComponentContext ce) throws IOException {
+ executor.shutdownNow();
+ executor = null;
+ fetchTaskQueue = null;
+ // stop the serialization queue by sending it a last job
+ serializerActive = false;
+ serializationQueue.add(new SimpleMGraph());
+ }
+
+ @Override
+ public void computeEnhancements(ContentItem ci) throws EngineException {
+ MGraph metadata = ci.getMetadata();
+ Set<UriRef> references = new HashSet<UriRef>();
+ Iterator<Triple> entities = metadata.filter(null,
+ Properties.ENHANCER_ENTITY_REFERENCE, null);
+ while (entities.hasNext()) {
+ references.add((UriRef) entities.next().getObject());
+ }
+
+ final MGraph entityCache = getEntityCache();
+ for (final UriRef reference : references) {
+ if (entityCache.filter(reference, null, null).hasNext()) {
+ // already in cache
+ continue;
+ }
+ if (fetchTaskQueue.contains(reference)) {
+ // optim: do not try to submit twice the same job
+ continue;
+ }
+
+ // asynchronously dereference (fire and forget)
+ executor.execute(new Runnable() {
+ @Override
+ public boolean equals(Object other) {
+ // overridden to implement queue membership to avoid
+ // duplicate submissions for dereferencing of the same URI
+ if (other instanceof UriRef) {
+ return reference.equals(other);
+ }
+ return this == other;
+ }
+
+ @Override
+ public void run() {
+ try {
+ serializationQueue.add(dereference(reference));
+ } catch (IOException e) {
+ log.warn("unable to dereference " + reference + " : "
+ + e.getMessage());
+ log.debug(e.getMessage(), e);
+ }
+ }
+ });
+ }
+ }
+
+ public Graph dereferenceHTTP(UriRef reference) throws IOException {
+ final URL url = new URL(reference.getUnicodeString());
+ final URLConnection con = url.openConnection();
+ con.addRequestProperty("Accept", RDF_XML);
+ return parser.parse(con.getInputStream(), RDF_XML);
+ }
+
+ public Graph dereferenceSPARQL(String endpointURL, UriRef reference)
+ throws IOException {
+
+ StringBuilder query = new StringBuilder();
+ query.append("CONSTRUCT { ");
+ query.append(reference);
+ query.append(" ?p ?o } WHERE { ");
+ query.append(reference);
+ query.append(" ?p ?o }");
+
+ String format = RDF_XML;
+ final URI uri = UriBuilder.fromUri(endpointURL).queryParam("query",
+ "{query}").queryParam("format", "{format}").build(
+ query.toString(), format);
+ final URLConnection con = uri.toURL().openConnection();
+ con.addRequestProperty("Accept", format);
+ return parser.parse(con.getInputStream(), format);
+ }
+
+ public Graph dereference(UriRef reference) throws IOException {
+ log.debug("dereferencing: " + reference);
+ // TODO: make the switch between SPARQL and HTTP configurable
+ if (reference.getUnicodeString().startsWith(
+ "http://dbpedia.org/resource/")) {
+ // special handling of dbpedia references using SPARQL since the
+ // basic HTTP dereference run the risk of a truncated output
+ return dereferenceSPARQL("http://dbpedia.org/sparql", reference);
+ } else {
+ return dereferenceHTTP(reference);
+ }
+ }
+
+ @Override
+ public int canEnhance(ContentItem ci) throws EngineException {
+ return ENHANCE_SYNCHRONOUS;
+ }
+
+ @Override
+ public Map<String, Object> getServiceProperties() {
+ return Collections.unmodifiableMap(Collections.singletonMap(
+ ENHANCEMENT_ENGINE_ORDERING,
+ (Object) defaultOrder));
+ }
+
+ public MGraph getEntityCache() {
+ final UriRef graphUri = new UriRef(ENTITY_CACHE_GRAPH_NAME);
+ try {
+ return tcProvider.getMGraph(graphUri);
+ } catch (NoSuchEntityException e) {
+ return tcProvider.createMGraph(graphUri);
+ }
+ }
+
+}
Added: incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/cache/EntityCacheProvider.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/cache/EntityCacheProvider.java?rev=1086333&view=auto
==============================================================================
--- incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/cache/EntityCacheProvider.java (added)
+++ incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/cache/EntityCacheProvider.java Mon Mar 28 18:41:24 2011
@@ -0,0 +1,9 @@
+package org.apache.stanbol.enhancer.jersey.cache;
+
+import org.apache.clerezza.rdf.core.MGraph;
+
+public interface EntityCacheProvider {
+
+ MGraph getEntityCache();
+
+}
Added: incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/fragment/EnhancerWebFragment.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/fragment/EnhancerWebFragment.java?rev=1086333&view=auto
==============================================================================
--- incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/fragment/EnhancerWebFragment.java (added)
+++ incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/fragment/EnhancerWebFragment.java Mon Mar 28 18:41:24 2011
@@ -0,0 +1,61 @@
+package org.apache.stanbol.enhancer.jersey.fragment;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.stanbol.commons.web.WebFragment;
+import org.apache.stanbol.enhancer.jersey.resource.EnginesRootResource;
+import org.apache.stanbol.enhancer.jersey.resource.SparqlQueryResource;
+import org.apache.stanbol.enhancer.jersey.resource.StoreRootResource;
+
+import freemarker.cache.ClassTemplateLoader;
+import freemarker.cache.TemplateLoader;
+
+/**
+ * Statically define the list of available resources and providers to be contributed to the the Stanbol JAX-RS
+ * Endpoint.
+ */
+@Component(immediate = true, metatype = true)
+@Service
+public class EnhancerWebFragment implements WebFragment {
+
+ private static final String NAME = "enhancer";
+
+ private static final String STATIC_RESOURCE_PATH = "org/apache/stanbol/enhancer/jersey/static";
+
+ private static final String TEMPLATE_PATH = "org/apache/stanbol/enhancer/jersey/templates";
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @Override
+ public Set<Class<?>> getJaxrsResourceClasses() {
+ Set<Class<?>> classes = new HashSet<Class<?>>();
+ // resources
+ classes.add(EnginesRootResource.class);
+ classes.add(StoreRootResource.class);
+ classes.add(SparqlQueryResource.class);
+ return classes;
+ }
+
+ @Override
+ public Set<Object> getJaxrsResourceSingletons() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public String getStaticResourceClassPath() {
+ return STATIC_RESOURCE_PATH;
+ }
+
+ @Override
+ public TemplateLoader getTemplateLoader() {
+ return new ClassTemplateLoader(getClass(), TEMPLATE_PATH);
+ }
+
+}
Added: incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/ContentItemResource.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/ContentItemResource.java?rev=1086333&view=auto
==============================================================================
--- incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/ContentItemResource.java (added)
+++ incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/ContentItemResource.java Mon Mar 28 18:41:24 2011
@@ -0,0 +1,477 @@
+package org.apache.stanbol.enhancer.jersey.resource;
+
+import static javax.ws.rs.core.MediaType.TEXT_HTML;
+import static org.apache.stanbol.enhancer.servicesapi.rdf.OntologicalClasses.DBPEDIA_ORGANISATION;
+import static org.apache.stanbol.enhancer.servicesapi.rdf.OntologicalClasses.DBPEDIA_PERSON;
+import static org.apache.stanbol.enhancer.servicesapi.rdf.OntologicalClasses.DBPEDIA_PLACE;
+import static org.apache.stanbol.enhancer.servicesapi.rdf.Properties.GEO_LAT;
+import static org.apache.stanbol.enhancer.servicesapi.rdf.Properties.GEO_LONG;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.clerezza.rdf.core.Graph;
+import org.apache.clerezza.rdf.core.Language;
+import org.apache.clerezza.rdf.core.Literal;
+import org.apache.clerezza.rdf.core.LiteralFactory;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.PlainLiteral;
+import org.apache.clerezza.rdf.core.Resource;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.TripleCollection;
+import org.apache.clerezza.rdf.core.TypedLiteral;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.TcManager;
+import org.apache.clerezza.rdf.core.impl.SimpleMGraph;
+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.core.sparql.ParseException;
+import org.apache.clerezza.rdf.core.sparql.QueryParser;
+import org.apache.clerezza.rdf.core.sparql.ResultSet;
+import org.apache.clerezza.rdf.core.sparql.SolutionMapping;
+import org.apache.clerezza.rdf.core.sparql.query.SelectQuery;
+import org.apache.clerezza.rdf.utils.GraphNode;
+import org.apache.commons.io.IOUtils;
+import org.apache.stanbol.commons.web.resource.NavigationMixin;
+import org.apache.stanbol.enhancer.servicesapi.ContentItem;
+import org.apache.stanbol.enhancer.servicesapi.rdf.Properties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.ImplicitProduces;
+
+@ImplicitProduces(TEXT_HTML + ";qs=2")
+public class ContentItemResource extends NavigationMixin {
+
+ @SuppressWarnings("unused")
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ // TODO make this configurable trough a property
+ public static final UriRef SUMMARY = new UriRef(
+ "http://www.w3.org/2000/01/rdf-schema#comment");
+
+ // TODO make this configurable trough a property
+ public static final UriRef THUMBNAIL = new UriRef(
+ "http://dbpedia.org/ontology/thumbnail");
+
+ public static final Map<UriRef, String> DEFAULT_THUMBNAILS = new HashMap<UriRef, String>();
+ static {
+ DEFAULT_THUMBNAILS.put(DBPEDIA_PERSON, "/static/images/user_48.png");
+ DEFAULT_THUMBNAILS.put(DBPEDIA_ORGANISATION, "/static/images/organization_48.png");
+ DEFAULT_THUMBNAILS.put(DBPEDIA_PLACE, "/static/images/compass_48.png");
+ }
+
+ protected ContentItem contentItem;
+
+ protected String localId;
+
+ protected String textContent;
+
+ protected URI imageSrc;
+
+ protected URI downloadHref;
+
+ protected URI metadataHref;
+
+ protected final TcManager tcManager;
+
+ protected final Serializer serializer;
+
+ protected String serializationFormat = SupportedFormat.RDF_XML;
+
+ protected final TripleCollection remoteEntityCache;
+
+ protected Collection<EntityExtractionSummary> people;
+
+ protected Collection<EntityExtractionSummary> organizations;
+
+ protected Collection<EntityExtractionSummary> places;
+
+ public ContentItemResource(String localId, ContentItem ci,
+ TripleCollection remoteEntityCache, UriInfo uriInfo,
+ TcManager tcManager, Serializer serializer) throws IOException {
+ this.contentItem = ci;
+ this.localId = localId;
+ this.uriInfo = uriInfo;
+ this.tcManager = tcManager;
+ this.serializer = serializer;
+ this.remoteEntityCache = remoteEntityCache;
+
+ if (localId != null) {
+ URI rawURI = UriBuilder.fromPath("/store/raw/" + localId).build();
+ if (ci.getMimeType().equals("text/plain")) {
+ this.textContent = IOUtils.toString(ci.getStream(), "UTF-8");
+ } else if (ci.getMimeType().startsWith("image/")) {
+ this.imageSrc = rawURI;
+ }
+ this.downloadHref = rawURI;
+ this.metadataHref = UriBuilder.fromPath(
+ "/store/metadata/" + localId).build();
+ }
+ }
+
+ public String getRdfMetadata(String mediatype)
+ throws UnsupportedEncodingException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ serializer.serialize(out, contentItem.getMetadata(), mediatype);
+ return out.toString("utf-8");
+ }
+
+ public String getRdfMetadata() throws UnsupportedEncodingException {
+ return getRdfMetadata(serializationFormat);
+ }
+
+ public ContentItem getContentItem() {
+ return contentItem;
+ }
+
+ public String getLocalId() {
+ return localId;
+ }
+
+ public String getTextContent() {
+ return textContent;
+ }
+
+ public URI getImageSrc() {
+ return imageSrc;
+ }
+
+ public URI getDownloadHref() {
+ return downloadHref;
+ }
+
+ public URI getMetadataHref() {
+ return metadataHref;
+ }
+
+ public Collection<EntityExtractionSummary> getPersonOccurrences()
+ throws ParseException {
+ if (people == null) {
+ people = getOccurrences(DBPEDIA_PERSON);
+ }
+ return people;
+ }
+
+ public Collection<EntityExtractionSummary> getOrganizationOccurrences()
+ throws ParseException {
+ if (organizations == null) {
+ organizations = getOccurrences(DBPEDIA_ORGANISATION);
+ }
+ return organizations;
+ }
+
+ public Collection<EntityExtractionSummary> getPlaceOccurrences()
+ throws ParseException {
+ if (places == null) {
+ places = getOccurrences(DBPEDIA_PLACE);
+ }
+ return places;
+ }
+
+ public Collection<EntityExtractionSummary> getOccurrences(UriRef type)
+ throws ParseException {
+ MGraph graph = contentItem.getMetadata();
+ String q = "PREFIX enhancer: <http://fise.iks-project.eu/ontology/> "
+ + "PREFIX dc: <http://purl.org/dc/terms/> "
+ + "SELECT ?textAnnotation ?text ?entity ?entity_label ?confidence WHERE { "
+ + " ?textAnnotation a enhancer:TextAnnotation ."
+ + " ?textAnnotation dc:type %s ."
+ + " ?textAnnotation enhancer:selected-text ?text ."
+ + " OPTIONAL {"
+ + " ?entityAnnotation dc:relation ?textAnnotation ."
+ + " ?entityAnnotation a enhancer:EntityAnnotation . "
+ + " ?entityAnnotation enhancer:entity-reference ?entity ."
+ + " ?entityAnnotation enhancer:entity-label ?entity_label ."
+ + " ?entityAnnotation enhancer:confidence ?confidence . }"
+ + "} ORDER BY ?text ";
+ q = String.format(q, type);
+
+ SelectQuery query = (SelectQuery) QueryParser.getInstance().parse(q);
+ ResultSet result = tcManager.executeSparqlQuery(query, graph);
+ Map<String, EntityExtractionSummary> occurrenceMap = new TreeMap<String, EntityExtractionSummary>();
+ LiteralFactory lf = LiteralFactory.getInstance();
+ while (result.hasNext()) {
+ SolutionMapping mapping = result.next();
+
+ UriRef textAnnotationUri = (UriRef) mapping.get("textAnnotation");
+ if (graph.filter(textAnnotationUri, Properties.DC_RELATION, null).hasNext()) {
+ // this is not the most specific occurrence of this name: skip
+ continue;
+ }
+ // TODO: collect the selected text and contexts of subsumed
+ // annotations
+
+ TypedLiteral textLiteral = (TypedLiteral) mapping.get("text");
+ String text = lf.createObject(String.class, textLiteral);
+
+ EntityExtractionSummary entity = occurrenceMap.get(text);
+ if (entity == null) {
+ entity = new EntityExtractionSummary(text, type);
+ occurrenceMap.put(text, entity);
+ }
+ UriRef entityUri = (UriRef) mapping.get("entity");
+ if (entityUri != null) {
+ String label = ((Literal) mapping.get("entity_label")).getLexicalForm();
+ Double confidence = lf.createObject(Double.class,
+ (TypedLiteral) mapping.get("confidence"));
+ Graph properties = new GraphNode(entityUri, remoteEntityCache).getNodeContext();
+ entity.addSuggestion(entityUri, label, confidence, properties);
+ }
+ }
+ return occurrenceMap.values();
+ }
+
+ public static class EntityExtractionSummary implements
+ Comparable<EntityExtractionSummary> {
+
+ protected final String name;
+
+ protected final UriRef type;
+
+ protected List<EntitySuggestion> suggestions = new ArrayList<EntitySuggestion>();
+
+ protected List<String> mentions = new ArrayList<String>();
+
+ public EntityExtractionSummary(String name, UriRef type) {
+ this.name = name;
+ this.type = type;
+ mentions.add(name);
+ }
+
+ public void addSuggestion(UriRef uri, String label, Double confidence,
+ TripleCollection properties) {
+ EntitySuggestion suggestion = new EntitySuggestion(uri, type,
+ label, confidence, properties);
+ if (!suggestions.contains(suggestion)) {
+ suggestions.add(suggestion);
+ Collections.sort(suggestions);
+ }
+ }
+
+ public String getName() {
+ EntitySuggestion bestGuess = getBestGuess();
+ if (bestGuess != null) {
+ return bestGuess.getLabel();
+ }
+ return name;
+ }
+
+ public String getUri() {
+ EntitySuggestion bestGuess = getBestGuess();
+ if (bestGuess != null) {
+ return bestGuess.getUri();
+ }
+ return null;
+ }
+
+ public String getSummary() {
+ if (suggestions.isEmpty()) {
+ return "";
+ }
+ return suggestions.get(0).getSummary();
+ }
+
+ public String getThumbnailSrc() {
+ if (suggestions.isEmpty()) {
+ return DEFAULT_THUMBNAILS.get(type);
+ }
+ return suggestions.get(0).getThumbnailSrc();
+ }
+
+ public String getMissingThumbnailSrc() {
+ return DEFAULT_THUMBNAILS.get(type);
+ }
+
+ public EntitySuggestion getBestGuess() {
+ if (suggestions.isEmpty()) {
+ return null;
+ }
+ return suggestions.get(0);
+ }
+
+ public List<EntitySuggestion> getSuggestions() {
+ return suggestions;
+ }
+
+ public List<String> getMentions() {
+ return mentions;
+ }
+
+ @Override
+ public int compareTo(EntityExtractionSummary o) {
+ return getName().compareTo(o.getName());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ EntityExtractionSummary that = (EntityExtractionSummary) o;
+
+ return !(name != null ? !name.equals(that.name) : that.name != null);
+ }
+
+ @Override
+ public int hashCode() {
+ return name != null ? name.hashCode() : 0;
+ }
+ }
+
+ public static class EntitySuggestion implements
+ Comparable<EntitySuggestion> {
+
+ protected final UriRef uri;
+
+ protected final UriRef type;
+
+ protected final String label;
+
+ protected final Double confidence;
+
+ protected TripleCollection entityProperties;
+
+ public EntitySuggestion(UriRef uri, UriRef type, String label,
+ Double confidence, TripleCollection entityProperties) {
+ this.uri = uri;
+ this.label = label;
+ this.type = type;
+ this.confidence = confidence;
+ this.entityProperties = entityProperties;
+ }
+
+ @Override
+ public int compareTo(EntitySuggestion o) {
+ // order suggestions by decreasing confidence
+ return -confidence.compareTo(o.confidence);
+ }
+
+ public String getUri() {
+ return uri.getUnicodeString();
+ }
+
+ public Double getConfidence() {
+ return confidence;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public String getThumbnailSrc() {
+ Iterator<Triple> abstracts = entityProperties.filter(uri,
+ THUMBNAIL, null);
+ while (abstracts.hasNext()) {
+ Resource object = abstracts.next().getObject();
+ if (object instanceof UriRef) {
+ return ((UriRef) object).getUnicodeString();
+ }
+ }
+ return DEFAULT_THUMBNAILS.get(type);
+ }
+
+ public String getMissingThumbnailSrc() {
+ return DEFAULT_THUMBNAILS.get(type);
+ }
+
+ public String getSummary() {
+ Iterator<Triple> abstracts = entityProperties.filter(uri, SUMMARY,
+ null);
+ while (abstracts.hasNext()) {
+ Resource object = abstracts.next().getObject();
+ if (object instanceof PlainLiteral) {
+ PlainLiteral abstract_ = (PlainLiteral) object;
+ if (abstract_.getLanguage().equals(new Language("en"))) {
+ return abstract_.getLexicalForm();
+ }
+ }
+ }
+ return "";
+ }
+
+ // consider entities with same URI as equal even if we have alternate
+ // label values
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((uri == null) ? 0 : uri.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ EntitySuggestion other = (EntitySuggestion) obj;
+ if (uri == null) {
+ if (other.uri != null)
+ return false;
+ } else if (!uri.equals(other.uri))
+ return false;
+ return true;
+ }
+
+ }
+
+ public void setRdfSerializationFormat(String format) {
+ serializationFormat = format;
+ }
+
+ /**
+ * @return an RDF/JSON descriptions of places for the word map widget
+ */
+ public String getPlacesAsJSON() throws ParseException,
+ UnsupportedEncodingException {
+ MGraph g = new SimpleMGraph();
+ if (remoteEntityCache != null) {
+ LiteralFactory lf = LiteralFactory.getInstance();
+ for (EntityExtractionSummary p : getPlaceOccurrences()) {
+ EntitySuggestion bestGuess = p.getBestGuess();
+ if (bestGuess == null) {
+ continue;
+ }
+ UriRef uri = new UriRef(bestGuess.getUri());
+ Iterator<Triple> latitudes = remoteEntityCache.filter(uri,
+ GEO_LAT, null);
+ if (latitudes.hasNext()) {
+ g.add(latitudes.next());
+ }
+ Iterator<Triple> longitutes = remoteEntityCache.filter(uri,
+ GEO_LONG, null);
+ if (longitutes.hasNext()) {
+ g.add(longitutes.next());
+ g.add(new TripleImpl(uri, Properties.RDFS_LABEL,
+ lf.createTypedLiteral(bestGuess.getLabel())));
+ }
+ }
+ }
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ serializer.serialize(out, g, SupportedFormat.RDF_JSON);
+ return out.toString("utf-8");
+ }
+
+}
Added: incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/EnginesRootResource.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/EnginesRootResource.java?rev=1086333&view=auto
==============================================================================
--- incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/EnginesRootResource.java (added)
+++ incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/EnginesRootResource.java Mon Mar 28 18:41:24 2011
@@ -0,0 +1,213 @@
+package org.apache.stanbol.enhancer.jersey.resource;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
+import static javax.ws.rs.core.MediaType.TEXT_HTML;
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+import static javax.ws.rs.core.MediaType.WILDCARD;
+import static org.apache.clerezza.rdf.core.serializedform.SupportedFormat.RDF_JSON;
+import static org.apache.clerezza.rdf.core.serializedform.SupportedFormat.RDF_XML;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.TripleCollection;
+import org.apache.clerezza.rdf.core.access.TcManager;
+import org.apache.clerezza.rdf.core.serializedform.Serializer;
+import org.apache.stanbol.commons.web.resource.NavigationMixin;
+import org.apache.stanbol.enhancer.jersey.cache.EntityCacheProvider;
+import org.apache.stanbol.enhancer.servicesapi.ContentItem;
+import org.apache.stanbol.enhancer.servicesapi.EngineException;
+import org.apache.stanbol.enhancer.servicesapi.EnhancementEngine;
+import org.apache.stanbol.enhancer.servicesapi.EnhancementJobManager;
+import org.apache.stanbol.enhancer.servicesapi.helper.InMemoryContentItem;
+import org.codehaus.jettison.json.JSONArray;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.ImplicitProduces;
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * RESTful interface to browse the list of available engines and allow to call
+ * them in a stateless, synchronous way.
+ * <p>
+ * If you need the content of the extractions to be stored on the server, use
+ * the StoreRootResource API instead.
+ */
+@Path("/engines")
+@ImplicitProduces(TEXT_HTML + ";qs=2")
+public class EnginesRootResource extends NavigationMixin {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ protected EnhancementJobManager jobManager;
+
+ protected TcManager tcManager;
+
+ protected Serializer serializer;
+
+ protected TripleCollection entityCache;
+
+ // bind the job manager by looking it up from the servlet request context
+ public EnginesRootResource(@Context ServletContext context) {
+ jobManager = (EnhancementJobManager) context.getAttribute(EnhancementJobManager.class.getName());
+ tcManager = (TcManager) context.getAttribute(TcManager.class.getName());
+ serializer = (Serializer) context.getAttribute(Serializer.class.getName());
+ EntityCacheProvider entityCacheProvider = (EntityCacheProvider) context.getAttribute(EntityCacheProvider.class.getName());
+ if (entityCacheProvider != null) {
+ entityCache = entityCacheProvider.getEntityCache();
+ }
+ }
+
+ public List<EnhancementEngine> getActiveEngines() {
+ if (jobManager != null) {
+ return jobManager.getActiveEngines();
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ private List<EnhancementEngine> getEngines() {
+ if (jobManager != null) {
+ return jobManager.getActiveEngines();
+ }
+ return new ArrayList<EnhancementEngine>();
+ }
+
+ @GET
+ @Produces(APPLICATION_JSON)
+ public JSONArray getEnginesAsJsonArray() {
+ JSONArray uriArray = new JSONArray();
+ for (EnhancementEngine engine : getEngines()) {
+ UriBuilder ub = uriInfo.getAbsolutePathBuilder();
+ URI userUri = ub.path(makeEngineId(engine)).build();
+ uriArray.put(userUri.toASCIIString());
+ }
+ return uriArray;
+ }
+
+ @GET
+ @Produces(TEXT_PLAIN)
+ public String getEnginesAsString() {
+ final StringBuilder sb = new StringBuilder();
+ for (EnhancementEngine engine : getEngines()) {
+ sb.append(engine.getClass().getName());
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+ public static String makeEngineId(EnhancementEngine engine) {
+ // TODO: add a property on engines to provided custom local ids and make
+ // this static method a method of the interface EnhancementEngine
+ String engineClassName = engine.getClass().getSimpleName();
+ String suffixToRemove = "EnhancementEngine";
+ if (engineClassName.endsWith(suffixToRemove)) {
+ engineClassName = engineClassName.substring(0,
+ engineClassName.length() - suffixToRemove.length());
+ }
+ return engineClassName.toLowerCase();
+ }
+
+ /**
+ * Form-based OpenCalais-compatible interface
+ *
+ * TODO: should we parse the OpenCalais paramsXML and find the closest
+ * Stanbol Enhancer semantics too?
+ *
+ * Note: the format parameter is not part of the official API
+ *
+ * @throws EngineException if the content is somehow corrupted
+ * @throws IOException
+ */
+ @POST
+ @Consumes(APPLICATION_FORM_URLENCODED)
+ public Response enhanceFromForm(@FormParam("content") String content,
+ @FormParam("format") String format,
+ @FormParam("ajax") boolean buildAjaxview,
+ @Context HttpHeaders headers) throws EngineException, IOException {
+ log.info("enhance from From: "+content); ContentItem ci = new InMemoryContentItem(content.getBytes("UTF-8"),
+ TEXT_PLAIN);
+ return enhanceAndBuildResponse(format, headers, ci, buildAjaxview);
+ }
+
+ /**
+ * Media-Type based handling of the raw POST data.
+ *
+ * @param data binary payload to analyze
+ * @param uri optional URI for the content items (to be used as an
+ * identifier in the enhancement graph)
+ * @throws EngineException if the content is somehow corrupted
+ * @throws IOException
+ */
+ @POST
+ @Consumes(WILDCARD)
+ public Response enhanceFromData(byte[] data,
+ @QueryParam(value = "uri") String uri, @Context HttpHeaders headers)
+ throws EngineException, IOException {
+ String format = TEXT_PLAIN;
+ if (headers.getMediaType() != null) {
+ format = headers.getMediaType().toString();
+ }
+ if (uri != null && uri.isEmpty()) {
+ // let the store build an internal URI basted on the content
+ uri = null;
+ }
+ ContentItem ci = new InMemoryContentItem(uri, data, format);
+ return enhanceAndBuildResponse(null, headers, ci, false);
+ }
+
+ protected Response enhanceAndBuildResponse(String format,
+ HttpHeaders headers, ContentItem ci, boolean buildAjaxview)
+ throws EngineException, IOException {
+ if (jobManager != null) {
+ jobManager.enhanceContent(ci);
+ }
+ MGraph graph = ci.getMetadata();
+
+ if (buildAjaxview) {
+ ContentItemResource contentItemResource = new ContentItemResource(
+ null, ci, entityCache, uriInfo, tcManager, serializer);
+ contentItemResource.setRdfSerializationFormat(format);
+ Viewable ajaxView = new Viewable("/ajax/contentitem",
+ contentItemResource);
+ return Response.ok(ajaxView).type(TEXT_HTML).build();
+ }
+ if (format != null) {
+ // force mimetype from form params
+ return Response.ok(graph, format).build();
+ }
+ if (headers.getAcceptableMediaTypes().contains(
+ APPLICATION_JSON_TYPE)) {
+ // force RDF JSON media type (TODO: move this logic
+ return Response.ok(graph, RDF_JSON).build();
+ } else if (headers.getAcceptableMediaTypes().isEmpty()) {
+ // use RDF/XML as default format to keep compat with OpenCalais
+ // clients
+ return Response.ok(graph, RDF_XML).build();
+ }
+
+ // traditional response lookup
+ return Response.ok(graph).build();
+ }
+
+}
Added: incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/SparqlQueryResource.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/SparqlQueryResource.java?rev=1086333&view=auto
==============================================================================
--- incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/SparqlQueryResource.java (added)
+++ incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/SparqlQueryResource.java Mon Mar 28 18:41:24 2011
@@ -0,0 +1,89 @@
+package org.apache.stanbol.enhancer.jersey.resource;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+
+import org.apache.clerezza.rdf.core.access.TcManager;
+import org.apache.clerezza.rdf.core.sparql.ParseException;
+import org.apache.clerezza.rdf.core.sparql.QueryParser;
+import org.apache.clerezza.rdf.core.sparql.query.ConstructQuery;
+import org.apache.clerezza.rdf.core.sparql.query.DescribeQuery;
+import org.apache.clerezza.rdf.core.sparql.query.Query;
+import org.apache.stanbol.commons.web.resource.NavigationMixin;
+import org.apache.stanbol.enhancer.servicesapi.Store;
+import org.apache.stanbol.enhancer.servicesapi.SparqlQueryEngine.SparqlQueryEngineException;
+
+import com.sun.jersey.api.view.Viewable;
+
+
+import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED;
+import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+import static javax.ws.rs.core.MediaType.TEXT_HTML;
+
+/**
+ * Implementation of a SPARQL endpoint as defined by the W3C:
+ *
+ * http://www.w3.org/TR/rdf-sparql-protocol/
+ *
+ * (not 100% compliant yet, please report bugs/missing features in the issue
+ * tracker).
+ *
+ * If the "query" parameter is not present, then fallback to display and HTML
+ * view with an ajax-ified form to test the SPARQL endpoint from the browser.
+ */
+@Path("/sparql")
+public class SparqlQueryResource extends NavigationMixin {
+
+ protected Store store;
+
+ protected TcManager tcManager;
+
+ public SparqlQueryResource(@Context ServletContext servletContext) {
+ tcManager = (TcManager) servletContext.getAttribute(TcManager.class.getName());
+ store = (Store) servletContext.getAttribute(Store.class.getName());
+ }
+
+ @GET
+ @Consumes(APPLICATION_FORM_URLENCODED)
+ @Produces( { TEXT_HTML + ";qs=2",
+ "application/sparql-results+xml", "application/rdf+xml",
+ APPLICATION_XML })
+ public Object sparql(@QueryParam(value = "query") String sparqlQuery,
+ @Deprecated @QueryParam(value = "q") String q)
+ throws SparqlQueryEngineException, ParseException {
+ if (q != null) {
+ // compat with old REST API that was not respecting the SPARQL RDF
+ // protocol
+ sparqlQuery = q;
+ }
+ if (sparqlQuery == null) {
+ return Response.ok(new Viewable("index", this), TEXT_HTML).build();
+ }
+ Query query = QueryParser.getInstance().parse(sparqlQuery);
+ String mediaType = "application/sparql-results+xml";
+ if (query instanceof DescribeQuery || query instanceof ConstructQuery) {
+ mediaType = "application/rdf+xml";
+ }
+ Object result = tcManager.executeSparqlQuery(query,
+ store.getEnhancementGraph());
+ return Response.ok(result, mediaType).build();
+ }
+
+ @POST
+ @Consumes(APPLICATION_FORM_URLENCODED)
+ @Produces( { "application/sparql-results+xml", "application/rdf+xml",
+ APPLICATION_XML })
+ public Object postSparql(@FormParam("query") String sparqlQuery)
+ throws SparqlQueryEngineException, ParseException {
+ return sparql(sparqlQuery, null);
+ }
+
+}
Added: incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/StoreRootResource.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/StoreRootResource.java?rev=1086333&view=auto
==============================================================================
--- incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/StoreRootResource.java (added)
+++ incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/StoreRootResource.java Mon Mar 28 18:41:24 2011
@@ -0,0 +1,412 @@
+package org.apache.stanbol.enhancer.jersey.resource;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
+import static javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA;
+import static javax.ws.rs.core.MediaType.TEXT_HTML;
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
+import static javax.ws.rs.core.MediaType.WILDCARD;
+import static org.apache.clerezza.rdf.core.serializedform.SupportedFormat.N3;
+import static org.apache.clerezza.rdf.core.serializedform.SupportedFormat.N_TRIPLE;
+import static org.apache.clerezza.rdf.core.serializedform.SupportedFormat.RDF_JSON;
+import static org.apache.clerezza.rdf.core.serializedform.SupportedFormat.RDF_XML;
+import static org.apache.clerezza.rdf.core.serializedform.SupportedFormat.TURTLE;
+import static org.apache.clerezza.rdf.core.serializedform.SupportedFormat.X_TURTLE;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+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.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.TripleCollection;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.TcManager;
+import org.apache.clerezza.rdf.core.serializedform.Serializer;
+import org.apache.clerezza.rdf.core.sparql.ParseException;
+import org.apache.clerezza.rdf.core.sparql.QueryParser;
+import org.apache.clerezza.rdf.core.sparql.ResultSet;
+import org.apache.clerezza.rdf.core.sparql.SolutionMapping;
+import org.apache.clerezza.rdf.core.sparql.query.SelectQuery;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.stanbol.commons.web.resource.NavigationMixin;
+import org.apache.stanbol.enhancer.jersey.cache.EntityCacheProvider;
+import org.apache.stanbol.enhancer.servicesapi.ContentItem;
+import org.apache.stanbol.enhancer.servicesapi.EngineException;
+import org.apache.stanbol.enhancer.servicesapi.EnhancementJobManager;
+import org.apache.stanbol.enhancer.servicesapi.Store;
+import org.apache.stanbol.enhancer.servicesapi.helper.ContentItemHelper;
+import org.apache.stanbol.enhancer.servicesapi.rdf.Properties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+import com.sun.jersey.core.header.FormDataContentDisposition;
+
+/**
+ * Resource to provide a CRU[D] REST API for content items and there related
+ * enhancements.
+ * <p>
+ * Creation is achieved using either POST requests on the root of the store or
+ * as PUT requests on the expected content item URI.
+ * <p>
+ * Retrieval is achieved using simple GET requests on the content item or
+ * enhancement public URIs.
+ * <p>
+ * Update is achieved by issue a PUT request on an existing content item public
+ * URI.
+ * <p>
+ * The Delete operation is not implemented yet.
+ */
+@Path("/store")
+public class StoreRootResource extends NavigationMixin {
+
+ public static final Set<String> RDF_MEDIA_TYPES = new TreeSet<String>(
+ Arrays.asList(N3, N_TRIPLE, RDF_XML, TURTLE, X_TURTLE, RDF_JSON));
+
+ private static final Logger log = LoggerFactory.getLogger(StoreRootResource.class);
+
+ protected TcManager tcManager;
+
+ protected Store store;
+
+ protected EnhancementJobManager jobManager;
+
+ protected Serializer serializer;
+
+ protected UriInfo uriInfo;
+
+ protected int offset = 0;
+
+ protected int pageSize = 5;
+
+ protected List<RecentlyEnhanced> recentlyEnhanced;
+
+ protected TripleCollection entityCache;
+
+ public static class RecentlyEnhanced {
+
+ public final String localId;
+
+ public final String uri;
+
+ public final String mimetype;
+
+ public final long enhancements;
+
+ public RecentlyEnhanced(String uri, String mimetype, long enhancements) {
+ this.localId = uri.substring(uri.lastIndexOf("/") + 1);
+ this.uri = uri;
+ this.mimetype = mimetype;
+ this.enhancements = enhancements;
+ }
+
+ public String getLocalId() {
+ return localId;
+ }
+
+ public String getUri() {
+ return uri;
+ }
+
+ public String getMimetype() {
+ return mimetype;
+ }
+
+ public long getEnhancements() {
+ return enhancements;
+ }
+
+ }
+
+ public StoreRootResource(@Context ServletContext context,
+ @Context UriInfo uriInfo, @QueryParam(value = "offset") int offset,
+ @QueryParam(value = "pageSize") @DefaultValue("5") int pageSize)
+ throws ParseException {
+ tcManager = (TcManager) context.getAttribute(TcManager.class.getName());
+ store = (Store) context.getAttribute(Store.class.getName());
+ jobManager = (EnhancementJobManager) context.getAttribute(EnhancementJobManager.class.getName());
+ serializer = (Serializer) context.getAttribute(Serializer.class.getName());
+ EntityCacheProvider entityCacheProvider = (EntityCacheProvider) context.getAttribute(EntityCacheProvider.class.getName());
+ if (entityCacheProvider != null) {
+ entityCache = entityCacheProvider.getEntityCache();
+ }
+
+ if (store == null || tcManager == null) {
+ log.error("Missing either store={} or tcManager={}", store,
+ tcManager);
+ throw new WebApplicationException(404);
+ }
+ this.uriInfo = uriInfo;
+ this.offset = offset;
+ this.pageSize = pageSize;
+
+ // compute the latest: todo move some of this as OSGi parameters
+ // somewhere
+ String q = "PREFIX enhancer: <http://fise.iks-project.eu/ontology/> "
+ + "PREFIX dc: <http://purl.org/dc/terms/> "
+ + "SELECT DISTINCT ?content WHERE { "
+ + " ?enhancement enhancer:extracted-from ?content ."
+ + " ?enhancement dc:created ?extraction_time . } "
+ + "ORDER BY DESC(?extraction_time) LIMIT %d OFFSET %d";
+ q = String.format(q, pageSize, offset);
+
+ SelectQuery query = (SelectQuery) QueryParser.getInstance().parse(q);
+ ResultSet result = tcManager.executeSparqlQuery(query,
+ store.getEnhancementGraph());
+
+ recentlyEnhanced = new ArrayList<RecentlyEnhanced>();
+ while (result.hasNext()) {
+ SolutionMapping mapping = result.next();
+ UriRef content = (UriRef) mapping.get("content");
+ ContentItem ci = store.get(content.getUnicodeString());
+ String mimetype = null;
+ long enhancements = 0;
+ if (ci != null) {
+ mimetype = ci.getMimeType();
+ Iterator<Triple> it = ci.getMetadata().filter(null,
+ Properties.ENHANCER_EXTRACTED_FROM, content);
+ while (it.hasNext()) {
+ it.next();
+ enhancements++;
+ }
+ recentlyEnhanced.add(new RecentlyEnhanced(
+ content.getUnicodeString(), mimetype, enhancements));
+ }
+ }
+ }
+
+ public List<RecentlyEnhanced> getRecentlyEnhancedItems()
+ throws ParseException {
+ return recentlyEnhanced;
+ }
+
+ public URI getMoreRecentItemsUri() {
+ if (offset >= pageSize) {
+ return uriInfo.getBaseUriBuilder().path(getClass()).queryParam(
+ "offset", offset - pageSize).build();
+ } else {
+ return null;
+ }
+ }
+
+ public URI getOlderItemsUri() {
+ if (recentlyEnhanced.size() < pageSize) {
+ return null;
+ } else {
+ return uriInfo.getBaseUriBuilder().path(getClass()).queryParam(
+ "offset", offset + pageSize).build();
+ }
+ }
+
+ public UriRef makeContentItemUri(byte[] data) {
+ // TODO: factorize this logic out in a dedicated OSGi service
+ return ContentItemHelper.makeDefaultUri(uriInfo.getBaseUri()
+ + "store/content/", data);
+ }
+
+ public UriRef makeContentItemUri(String localId) {
+ // TODO: factorize this logic out in a dedicated OSGi service
+ return new UriRef(uriInfo.getBaseUri() + "store/content/" + localId);
+ }
+
+ @GET
+ @Produces(TEXT_HTML + ";qs=2")
+ public Viewable getView() {
+ return new Viewable("index", this);
+ }
+
+ /**
+ * Cool URI handler for the uploaded resource.
+ *
+ * @param localId the local id of the resource in the Stanbol Enhancer store
+ * @param headers
+ * @return a redirection to either a browser view, the RDF metadata or the
+ * raw binary content
+ */
+ @GET
+ @Path("/content/{localId}")
+ public Response getContent(@PathParam(value = "localId") String localId,
+ @Context HttpHeaders headers) {
+
+ UriRef uri = makeContentItemUri(localId);
+ ContentItem ci = store.get(uri.getUnicodeString());
+ if (ci == null) {
+ throw new WebApplicationException(404);
+ }
+
+ // handle smart redirection to browser view
+ for (MediaType mt : headers.getAcceptableMediaTypes()) {
+ if (mt.toString().startsWith(TEXT_HTML)) {
+ return Response.temporaryRedirect(
+ UriBuilder.fromPath("/store/page/" + localId).build()).build();
+ }
+ }
+
+ // handle smart redirection to RDF metadata view
+ for (MediaType mt : headers.getAcceptableMediaTypes()) {
+ if (RDF_MEDIA_TYPES.contains(mt.toString())) {
+ return Response.temporaryRedirect(
+ UriBuilder.fromPath("/store/metadata/" + localId).build()).build();
+ }
+ }
+ return Response.temporaryRedirect(
+ UriBuilder.fromPath("/store/raw/" + localId).build()).build();
+ }
+
+ @GET
+ @Path("/raw/{localId}")
+ public Response getRawContent(@PathParam(value = "localId") String localId)
+ throws IOException {
+ UriRef uri = makeContentItemUri(localId);
+ ContentItem ci = store.get(uri.getUnicodeString());
+ if (ci == null) {
+ throw new WebApplicationException(404);
+ }
+ return Response.ok(ci.getStream(), ci.getMimeType()).build();
+ }
+
+ @Path("/page/{localId}")
+ @Produces(TEXT_HTML)
+ public ContentItemResource getContentItemView(
+ @PathParam(value = "localId") String localId) throws IOException {
+ UriRef uri = makeContentItemUri(localId);
+ ContentItem ci = store.get(uri.getUnicodeString());
+ if (ci == null) {
+ throw new WebApplicationException(404);
+ }
+ return new ContentItemResource(localId, ci, entityCache, uriInfo,
+ tcManager, serializer);
+ }
+
+ @GET
+ @Path("/metadata/{localId}")
+ public MGraph getContentItemMetaData(
+ @PathParam(value = "localId") String localId) {
+ UriRef uri = makeContentItemUri(localId);
+ // TODO: rewrite me to perform a CONSTRUCT query on the TcManager
+ // instead
+ ContentItem ci = store.get(uri.getUnicodeString());
+ if (ci == null) {
+ throw new WebApplicationException(404);
+ }
+ return ci.getMetadata();
+ }
+
+ @POST
+ @Consumes(WILDCARD + ";qs=0.5")
+ public Response createContentItem(byte[] data, @Context HttpHeaders headers)
+ throws URISyntaxException, EngineException {
+ String uri = makeContentItemUri(data).getUnicodeString();
+ return createEnhanceAndRedirect(data, headers.getMediaType(), uri);
+ }
+
+ @POST
+ @Consumes( { APPLICATION_FORM_URLENCODED + ";qs=1.0",
+ MULTIPART_FORM_DATA + ";qs=0.9" })
+ public Response createContentItemFromForm(
+ @FormParam("content") String content, @FormParam("url") String url,
+ @FormParam("file") File file,
+ @FormParam("file") FormDataContentDisposition disposition,
+ @Context HttpHeaders headers) throws URISyntaxException,
+ EngineException, MalformedURLException, IOException {
+ byte[] data = null; // TODO: rewrite me in a streamable way to avoid
+ // buffering all the content in memory
+ MediaType mt = null;
+ if (content != null && !content.trim().isEmpty()) {
+ data = content.getBytes();
+ mt = TEXT_PLAIN_TYPE;
+ } else if (url != null && !url.trim().isEmpty()) {
+ try {
+ URLConnection uc = (new URL(url)).openConnection();
+ data = IOUtils.toByteArray(uc.getInputStream());
+ mt = MediaType.valueOf(uc.getContentType());
+ } catch (IOException e) {
+ // TODO: collect remote resource error message for user friendly
+ // feedback
+ }
+ } else if (file != null) {
+ data = FileUtils.readFileToByteArray(file);
+ String lowerFilename = disposition.getFileName().toLowerCase();
+ // TODO: use a mimetype sniffer lib instead
+ if (lowerFilename.matches(".*\\.jpe?g")) {
+ mt = MediaType.valueOf("image/jpeg");
+ } else {
+ mt = APPLICATION_OCTET_STREAM_TYPE;
+ }
+ }
+ if (data != null && mt != null) {
+ String uri = makeContentItemUri(data).getUnicodeString();
+ return createEnhanceAndRedirect(data, mt, uri, true);
+ } else {
+ // TODO: add user-friendly feedback on empty requests from a form
+ return Response.seeOther(new URI("/store")).build();
+ }
+ }
+
+ @PUT
+ @Path("/content/{localId}")
+ @Consumes(WILDCARD)
+ public Response createContentItemWithId(
+ @PathParam(value = "localId") String localId, byte[] data,
+ @Context HttpHeaders headers) throws URISyntaxException,
+ EngineException {
+ String uri = makeContentItemUri(localId).getUnicodeString();
+ return createEnhanceAndRedirect(data, headers.getMediaType(), uri);
+ }
+
+ protected Response createEnhanceAndRedirect(byte[] data,
+ MediaType mediaType, String uri) throws EngineException,
+ URISyntaxException {
+ return createEnhanceAndRedirect(data, mediaType, uri, false);
+ }
+
+ protected Response createEnhanceAndRedirect(byte[] data,
+ MediaType mediaType, String uri, boolean useExplicitRedirect)
+ throws EngineException, URISyntaxException {
+ ContentItem ci = store.create(uri, data, mediaType.toString());
+ jobManager.enhanceContent(ci);
+ store.put(ci);
+ if (useExplicitRedirect) {
+ // use an redirect to point browsers to newly created content
+ return Response.seeOther(new URI(uri)).build();
+ } else {
+ // use the correct way of notifying the RESTful client that the
+ // resource has been successfully created
+ return Response.created(new URI(uri)).build();
+ }
+ }
+
+ // TODO: implement GET handler for dereferencable Enhancement URIs using
+ // SPARQL DESCRIBE query
+}
Added: incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/GraphWriter.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/GraphWriter.java?rev=1086333&view=auto
==============================================================================
--- incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/GraphWriter.java (added)
+++ incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/GraphWriter.java Mon Mar 28 18:41:24 2011
@@ -0,0 +1,60 @@
+package org.apache.stanbol.enhancer.jersey.writers;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+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.TripleCollection;
+import org.apache.clerezza.rdf.core.serializedform.Serializer;
+import org.apache.clerezza.rdf.core.serializedform.SupportedFormat;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+import static org.apache.clerezza.rdf.core.serializedform.SupportedFormat.*;
+
+
+@Provider
+@Produces( { TEXT_PLAIN, N3, N_TRIPLE, RDF_XML, TURTLE, X_TURTLE,
+ RDF_JSON, APPLICATION_JSON })
+public class GraphWriter implements MessageBodyWriter<TripleCollection> {
+
+ @Context
+ protected ServletContext servletContext;
+
+ protected Serializer getSerializer() {
+ return (Serializer) servletContext.getAttribute(Serializer.class.getName());
+ }
+
+ public boolean isWriteable(Class<?> type, Type genericType,
+ Annotation[] annotations, MediaType mediaType) {
+ return TripleCollection.class.isAssignableFrom(type);
+ }
+
+ public long getSize(TripleCollection t, Class<?> type, Type genericType,
+ Annotation[] annotations, MediaType mediaType) {
+ return -1;
+ }
+
+ public void writeTo(TripleCollection t, Class<?> type, Type genericType,
+ Annotation[] annotations, MediaType mediaType,
+ MultivaluedMap<String, Object> httpHeaders,
+ OutputStream entityStream) throws IOException,
+ WebApplicationException {
+
+ if (mediaType == null || mediaType.isWildcardType() || TEXT_PLAIN.equals(mediaType.toString())) {
+ getSerializer().serialize(entityStream, t, APPLICATION_JSON);
+ } else {
+ getSerializer().serialize(entityStream, t, mediaType.toString());
+ }
+ }
+}
Added: incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/JsonLdSerializerProvider.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/JsonLdSerializerProvider.java?rev=1086333&view=auto
==============================================================================
--- incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/JsonLdSerializerProvider.java (added)
+++ incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/JsonLdSerializerProvider.java Mon Mar 28 18:41:24 2011
@@ -0,0 +1,156 @@
+package org.apache.stanbol.enhancer.jersey.writers;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+
+import org.apache.clerezza.rdf.core.BNode;
+import org.apache.clerezza.rdf.core.NonLiteral;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.TripleCollection;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.serializedform.SerializingProvider;
+import org.apache.clerezza.rdf.core.serializedform.SupportedFormat;
+import org.apache.stanbol.jsonld.JsonLd;
+import org.apache.stanbol.jsonld.JsonLdResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+
+/**
+ * Implements a <a href="http://json-ld.org/">JSON-LD</a> serialization of a Clerezza
+ * {@link TripleCollection}.<br>
+ * <br>
+ * Note: This implementation is based on <a href="http://json-ld.org/spec/">JSON-LD
+ * specification</a> draft from 25 October 2010.
+ *
+ * @author Fabian Christ
+ *
+ * @scr.component immediate="true"
+ * @scr.service
+ * interface="org.apache.clerezza.rdf.core.serializedform.SerializingProvider"
+ */
+@SupportedFormat(JsonLdSerializerProvider.SUPPORTED_FORMAT)
+public class JsonLdSerializerProvider implements SerializingProvider {
+
+ public static final String SUPPORTED_FORMAT = APPLICATION_JSON;
+
+ private static final String RDF_NS_TYPE="http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
+
+ private static final Logger logger = LoggerFactory.getLogger(JsonLdSerializerProvider.class);
+
+ // Map from Namespace -> to Prefix
+ private Map<String, String> namespacePrefixMap = new HashMap<String, String>();
+
+ private int indentation = 2;
+
+ @Override
+ public void serialize(OutputStream serializedGraph, TripleCollection tc, String formatIdentifier) {
+ if (!formatIdentifier.equals(SUPPORTED_FORMAT)) {
+ logger.info("serialize() the format '" + formatIdentifier + "' is not supported by this implementation");
+ return;
+ }
+
+ JsonLd jsonLd = new JsonLd();
+ jsonLd.setNamespacePrefixMap(this.namespacePrefixMap);
+
+ Map<NonLiteral, String> subjects = createSubjectsMap(tc);
+ for (NonLiteral subject : subjects.keySet()) {
+ JsonLdResource resource = new JsonLdResource();
+ resource.setSubject(subject.toString());
+
+ Iterator<Triple> triplesFromSubject = tc.filter(subject, null, null);
+ while (triplesFromSubject.hasNext()) {
+ Triple currentTriple = triplesFromSubject.next();
+ if (currentTriple.getPredicate().getUnicodeString().equals(RDF_NS_TYPE)) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("serialize() adding rdf:type: \"a\":" + currentTriple.getObject());
+ }
+ resource.addType(currentTriple.getObject().toString());
+ } else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("serializer() adding predicate " + currentTriple.getPredicate().toString() + " with object " + currentTriple.getObject().toString());
+ }
+
+ String property = currentTriple.getPredicate().getUnicodeString();
+ String value = currentTriple.getObject().toString();
+ resource.putProperty(property, value);
+ }
+ }
+
+ jsonLd.put(resource.getSubject(), resource);
+ }
+
+ try {
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(serializedGraph));
+ writer.write(jsonLd.toString(this.indentation));
+ writer.flush();
+ } catch (IOException ioe) {
+ logger.error(ioe.getMessage());
+ throw new RuntimeException(ioe.getMessage());
+ }
+ }
+
+ private Map<NonLiteral, String> createSubjectsMap(TripleCollection tc) {
+ Map<NonLiteral, String> subjects = new HashMap<NonLiteral, String>();
+ int bNodeCounter = 0;
+ for (Triple triple : tc) {
+ NonLiteral subject = triple.getSubject();
+ if (!subjects.containsKey(subject)) {
+ if (subject instanceof UriRef) {
+ subjects.put(subject, subject.toString());
+ } else if (subject instanceof BNode) {
+ bNodeCounter++;
+ subjects.put(subject, "_:bnode" + bNodeCounter);
+ }
+ }
+ }
+ return subjects;
+ }
+
+ /**
+ * Get the known namespace to prefix mapping.
+ *
+ * @return A {@link Map} from namespace String to prefix String.
+ */
+ public Map<String, String> getNamespacePrefixMap() {
+ return namespacePrefixMap;
+ }
+
+ /**
+ * Sets the known namespaces for the serializer.
+ *
+ * @param knownNamespaces A {@link Map} from namespace String to prefix String.
+ */
+ public void setNamespacePrefixMap(Map<String, String> knownNamespaces) {
+ this.namespacePrefixMap = knownNamespaces;
+ }
+
+ /**
+ * Returns the current number of space characters which are used
+ * to indent the serialized output.
+ *
+ * @return Number of space characters used for indentation.
+ */
+ public int getIndentation() {
+ return indentation;
+ }
+
+ /**
+ * Sets the number of characters used per indentation level for the serialized output.<br />
+ * Set this value to zero (0) if you don't want indentation. Default value is 2.
+ *
+ * @param indentation Number of space characters used for indentation.
+ */
+ public void setIndentation(int indentation) {
+ this.indentation = indentation;
+ }
+}
Added: incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ResultSetToXml.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ResultSetToXml.java?rev=1086333&view=auto
==============================================================================
--- incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ResultSetToXml.java (added)
+++ incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ResultSetToXml.java Mon Mar 28 18:41:24 2011
@@ -0,0 +1,97 @@
+package org.apache.stanbol.enhancer.jersey.writers;
+
+import java.util.Set;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.clerezza.rdf.core.BNode;
+import org.apache.clerezza.rdf.core.Language;
+import org.apache.clerezza.rdf.core.PlainLiteral;
+import org.apache.clerezza.rdf.core.Resource;
+import org.apache.clerezza.rdf.core.TypedLiteral;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.sparql.ResultSet;
+import org.apache.clerezza.rdf.core.sparql.SolutionMapping;
+import org.apache.clerezza.rdf.core.sparql.query.Variable;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+class ResultSetToXml {
+
+ private final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+
+ Document toDocument(ResultSet rs) throws ParserConfigurationException {
+ final Document doc = dbf.newDocumentBuilder().newDocument();
+
+ // root element
+ Element root = doc.createElement("sparql");
+ root.setAttribute("xmlns", "http://www.w3.org/2005/sparql-results#");
+ doc.appendChild(root);
+ Element head = doc.createElement("head");
+ root.appendChild(head);
+
+ // result set
+ Element results = doc.createElement("results");
+ SolutionMapping solutionMapping = null;
+ while (rs.hasNext()) {
+ solutionMapping = rs.next();
+ createResultElement(solutionMapping, results, doc);
+ }
+ createVariable(solutionMapping, head, doc);
+ root.appendChild(results);
+
+ return doc;
+ }
+
+ private void createResultElement(SolutionMapping solutionMap, Element results, Document doc) {
+ Set<Variable> keys = solutionMap.keySet();
+ Element result = doc.createElement("result");
+ results.appendChild(result);
+ for (Variable key : keys) {
+ Element bindingElement = doc.createElement("binding");
+ bindingElement.setAttribute("name", key.getName());
+ bindingElement.appendChild(createValueElement(
+ (Resource) solutionMap.get(key), doc));
+ result.appendChild(bindingElement);
+ }
+ }
+
+ private void createVariable(SolutionMapping solutionMap, Element head, Document doc) {
+ if(solutionMap != null) {
+ Set<Variable> keys = solutionMap.keySet();
+ for (Variable key : keys) {
+ Element varElement = doc.createElement("variable");
+ varElement.setAttribute("name", key.getName());
+ head.appendChild(varElement);
+ }
+ }
+ }
+
+ private Element createValueElement(Resource resource, Document doc) {
+ Element value;
+ if (resource instanceof UriRef) {
+ value = doc.createElement("uri");
+ value.appendChild(doc.createTextNode(((UriRef) resource)
+ .getUnicodeString()));
+ } else if (resource instanceof TypedLiteral) {
+ value = doc.createElement("literal");
+ value.appendChild(doc.createTextNode(((TypedLiteral) resource)
+ .getLexicalForm()));
+ value.setAttribute("datatype", (((TypedLiteral) resource)
+ .getDataType().getUnicodeString()));
+ } else if (resource instanceof PlainLiteral) {
+ value = doc.createElement("literal");
+ value.appendChild(doc.createTextNode(((PlainLiteral) resource)
+ .getLexicalForm()));
+ Language lang = ((PlainLiteral) resource).getLanguage();
+ if (lang != null) {
+ value.setAttribute("xml:lang", (lang.toString()));
+ }
+ } else {
+ value = doc.createElement("bnode");
+ value.appendChild(doc.createTextNode(((BNode) resource).toString()));
+ }
+ return value;
+ }
+}
Added: incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ResultSetWriter.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ResultSetWriter.java?rev=1086333&view=auto
==============================================================================
--- incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ResultSetWriter.java (added)
+++ incubator/stanbol/branches/http-endpoint-refactoring/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/writers/ResultSetWriter.java Mon Mar 28 18:41:24 2011
@@ -0,0 +1,70 @@
+package org.apache.stanbol.enhancer.jersey.writers;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+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 javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.clerezza.rdf.core.sparql.ResultSet;
+import org.w3c.dom.Document;
+
+/**
+ * MessageBodyWriter for a ResultSet.
+ * Clerezza does provide such a writer, but it seems to require
+ * quite a lot of Clerezza dependencies that we don't really need.
+ */
+@Provider
+@Produces({"application/sparql-results+xml", "application/xml", "text/xml"})
+public class ResultSetWriter implements MessageBodyWriter<ResultSet> {
+
+ public static final String ENCODING = "UTF-8";
+
+ @Override
+ public long getSize(ResultSet resultSet, Class<?> type, Type genericType,
+ Annotation[] annotations, MediaType mediaType) {
+ return -1;
+ }
+
+ @Override
+ public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ return ResultSet.class.isAssignableFrom(type);
+ }
+
+ @Override
+ public void writeTo(ResultSet resultSet, Class<?> type, Type genericType,
+ Annotation[] annotations, MediaType mediaType,
+ MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
+ throws IOException, WebApplicationException {
+
+ try {
+ Document doc = new ResultSetToXml().toDocument(resultSet);
+ DOMSource domSource = new DOMSource(doc);
+ StreamResult streamResult = new StreamResult(entityStream);
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer serializer = tf.newTransformer();
+ serializer.setOutputProperty(OutputKeys.ENCODING,ENCODING);
+ serializer.setOutputProperty(OutputKeys.INDENT,"yes");
+ serializer.transform(domSource, streamResult);
+ } catch(TransformerException te) {
+ throw new IOException("TransformerException in writeTo()", te);
+ } catch(ParserConfigurationException pce) {
+ throw new IOException("Exception in ResultSetToXml.toDocument()", pce);
+ }
+
+ entityStream.flush();
+ }
+}