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/04/08 17:30:20 UTC

svn commit: r1090299 - in /incubator/stanbol/trunk: contenthub/web/ contenthub/web/src/main/java/org/ contenthub/web/src/main/java/org/apache/ contenthub/web/src/main/java/org/apache/stanbol/ contenthub/web/src/main/java/org/apache/stanbol/contenthub/ ...

Author: ogrisel
Date: Fri Apr  8 15:30:19 2011
New Revision: 1090299

URL: http://svn.apache.org/viewvc?rev=1090299&view=rev
Log:
STANBOL-155: contenthub is now living in a separate bundle, no longer part of the lite launcher

Added:
    incubator/stanbol/trunk/contenthub/web/src/main/java/org/
    incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/
    incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/
    incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/
    incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/web/
    incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/web/fragment/
    incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/web/fragment/ContentHubWebFragment.java
    incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/web/resource/
    incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/web/resource/ContentHubRootResource.java
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/imports/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/imports/contenthubDescription.ftl
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/org/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/org/apache/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/org/apache/stanbol/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/org/apache/stanbol/contenthub/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/org/apache/stanbol/contenthub/web/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/org/apache/stanbol/contenthub/web/resource/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/org/apache/stanbol/contenthub/web/resource/ContentHubRootResource/
    incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/org/apache/stanbol/contenthub/web/resource/ContentHubRootResource/index.ftl
Removed:
    incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/resource/ContentHubRootResource.java
    incubator/stanbol/trunk/enhancer/jersey/src/main/resources/org/apache/stanbol/enhancer/jersey/templates/imports/contenthubDescription.ftl
    incubator/stanbol/trunk/enhancer/jersey/src/main/resources/org/apache/stanbol/enhancer/jersey/templates/org/apache/stanbol/enhancer/jersey/resource/ContentHubRootResource/
Modified:
    incubator/stanbol/trunk/contenthub/web/pom.xml
    incubator/stanbol/trunk/enhancer/engines/autotagging/src/main/java/org/apache/stanbol/enhancer/engines/autotagging/impl/RelatedTopicEnhancementEngine.java
    incubator/stanbol/trunk/enhancer/integration-tests/pom.xml
    incubator/stanbol/trunk/enhancer/integration-tests/src/test/java/org/apache/stanbol/enhancer/it/EnhancerTestBase.java
    incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/fragment/EnhancerWebFragment.java
    incubator/stanbol/trunk/enhancer/launchers/full/src/main/bundles/list.xml
    incubator/stanbol/trunk/parent/pom.xml

Modified: incubator/stanbol/trunk/contenthub/web/pom.xml
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/contenthub/web/pom.xml?rev=1090299&r1=1090298&r2=1090299&view=diff
==============================================================================
--- incubator/stanbol/trunk/contenthub/web/pom.xml (original)
+++ incubator/stanbol/trunk/contenthub/web/pom.xml Fri Apr  8 15:30:19 2011
@@ -65,6 +65,12 @@
       <groupId>org.apache.stanbol</groupId>
       <artifactId>org.apache.stanbol.commons.web.base</artifactId>
     </dependency>
+
+    <!-- needed for the ContentItem resource -->
+    <dependency>
+      <groupId>org.apache.stanbol</groupId>
+      <artifactId>org.apache.stanbol.enhancer.jersey</artifactId>
+    </dependency>
     <!-- Clerezza dependencies -->
     <dependency>
       <groupId>org.apache.clerezza</groupId>
@@ -74,6 +80,10 @@
     <!-- Jersey -->
     <dependency>
       <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-server</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
       <artifactId>jersey-core</artifactId>
     </dependency>
     <dependency>

Added: incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/web/fragment/ContentHubWebFragment.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/web/fragment/ContentHubWebFragment.java?rev=1090299&view=auto
==============================================================================
--- incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/web/fragment/ContentHubWebFragment.java (added)
+++ incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/web/fragment/ContentHubWebFragment.java Fri Apr  8 15:30:19 2011
@@ -0,0 +1,91 @@
+package org.apache.stanbol.contenthub.web.fragment;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.stanbol.commons.web.base.LinkResource;
+import org.apache.stanbol.commons.web.base.NavigationLink;
+import org.apache.stanbol.commons.web.base.ScriptResource;
+import org.apache.stanbol.commons.web.base.WebFragment;
+import org.apache.stanbol.contenthub.web.resource.ContentHubRootResource;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+
+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 ContentHubWebFragment implements WebFragment {
+
+    private static final String NAME = "contenthub";
+
+    private static final String TEMPLATE_PATH = "/org/apache/stanbol/contenthub/web/templates";
+
+    private BundleContext bundleContext;
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Activate
+    protected void activate(ComponentContext ctx) {
+        this.bundleContext = ctx.getBundleContext();
+    }
+
+    @Override
+    public Set<Class<?>> getJaxrsResourceClasses() {
+        Set<Class<?>> classes = new HashSet<Class<?>>();
+        classes.add(ContentHubRootResource.class);
+        return classes;
+    }
+
+    @Override
+    public Set<Object> getJaxrsResourceSingletons() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public String getStaticResourceClassPath() {
+        return null;
+    }
+
+    @Override
+    public TemplateLoader getTemplateLoader() {
+        return new ClassTemplateLoader(getClass(), TEMPLATE_PATH);
+    }
+
+    @Override
+    public List<LinkResource> getLinkResources() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<ScriptResource> getScriptResources() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<NavigationLink> getNavigationLinks() {
+        List<NavigationLink> links = new ArrayList<NavigationLink>();
+        links.add(new NavigationLink("contenthub", "/contenthub", "/imports/contenthubDescription.ftl", 20));
+        return links;
+    }
+
+    @Override
+    public BundleContext getBundleContext() {
+        return bundleContext;
+    }
+
+}

Added: incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/web/resource/ContentHubRootResource.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/web/resource/ContentHubRootResource.java?rev=1090299&view=auto
==============================================================================
--- incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/web/resource/ContentHubRootResource.java (added)
+++ incubator/stanbol/trunk/contenthub/web/src/main/java/org/apache/stanbol/contenthub/web/resource/ContentHubRootResource.java Fri Apr  8 15:30:19 2011
@@ -0,0 +1,413 @@
+package org.apache.stanbol.contenthub.web.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.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.base.ContextHelper;
+import org.apache.stanbol.commons.web.base.resource.BaseStanbolResource;
+import org.apache.stanbol.enhancer.jersey.cache.EntityCacheProvider;
+import org.apache.stanbol.enhancer.jersey.resource.ContentItemResource;
+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("/contenthub")
+public class ContentHubRootResource extends BaseStanbolResource {
+
+    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(ContentHubRootResource.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 ContentHubRootResource(@Context ServletContext context,
+                             @Context UriInfo uriInfo,
+                             @QueryParam(value = "offset") int offset,
+                             @QueryParam(value = "pageSize") @DefaultValue("5") int pageSize) throws ParseException {
+        store = ContextHelper.getServiceFromContext(Store.class, context);
+        jobManager = ContextHelper.getServiceFromContext(EnhancementJobManager.class, context);
+        tcManager = ContextHelper.getServiceFromContext(TcManager.class, context);
+        serializer = ContextHelper.getServiceFromContext(Serializer.class, context);
+        EntityCacheProvider entityCacheProvider = ContextHelper.getServiceFromContext(
+            EntityCacheProvider.class, context);
+        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()
+                + "contenthub/content/", data);
+    }
+
+    public UriRef makeContentItemUri(String localId) {
+        // TODO: factorize this logic out in a dedicated OSGi service
+        return new UriRef(uriInfo.getBaseUri() + "contenthub/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)) {
+                URI pageUri = uriInfo.getBaseUriBuilder().path("/contenthub/page").path(localId).build();
+                return Response.temporaryRedirect(pageUri).build();
+            }
+        }
+
+        // handle smart redirection to RDF metadata view
+        for (MediaType mt : headers.getAcceptableMediaTypes()) {
+            if (RDF_MEDIA_TYPES.contains(mt.toString())) {
+                URI metadataUri = uriInfo.getBaseUriBuilder().path("/contenthub/metadata").path(localId).build();
+                return Response.temporaryRedirect(metadataUri).build();
+            }
+        }
+        URI rawUri = uriInfo.getBaseUriBuilder().path("/contenthub/raw").path(localId).build();
+        return Response.temporaryRedirect(rawUri).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, servletContext);
+    }
+
+    @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/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/imports/contenthubDescription.ftl
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/imports/contenthubDescription.ftl?rev=1090299&view=auto
==============================================================================
--- incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/imports/contenthubDescription.ftl (added)
+++ incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/imports/contenthubDescription.ftl Fri Apr  8 15:30:19 2011
@@ -0,0 +1,4 @@
+This is a <strong>stateful interface</strong> to submit content to <strong>
+analyze and store the results</strong> on the server. It is then possible
+to browse the resulting enhanced content items. The longer-term goal of this
+endpoint is to implement faceted semantic search of the enhanced content items.
\ No newline at end of file

Added: incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/org/apache/stanbol/contenthub/web/resource/ContentHubRootResource/index.ftl
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/org/apache/stanbol/contenthub/web/resource/ContentHubRootResource/index.ftl?rev=1090299&view=auto
==============================================================================
--- incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/org/apache/stanbol/contenthub/web/resource/ContentHubRootResource/index.ftl (added)
+++ incubator/stanbol/trunk/contenthub/web/src/main/resources/org/apache/stanbol/contenthub/web/templates/org/apache/stanbol/contenthub/web/resource/ContentHubRootResource/index.ftl Fri Apr  8 15:30:19 2011
@@ -0,0 +1,155 @@
+<#import "/imports/common.ftl" as common>
+<#escape x as x?html>
+<@common.page title="Content Hub" hasrestapi=true> 
+
+<div class="panel" id="webview">
+
+<em><strong>Disclaimer</strong>: this endpoint is a proof of concept /
+<strong>experimental</strong> feature. It does not actually store the content
+on the disk, just in memory.</em>
+
+<h3>Recently uploaded Content Items</h3>
+
+<div class="storeContents">
+<table>
+  <tr>
+    <th>Local ID</th>
+    <th>Media type</th>
+    <th>Enhancements <img src="${it.staticRootUrl}/images/rdf.png"
+       alt="Format: RDF"/></th>
+  </tr>
+  <#list it.recentlyEnhancedItems as item>
+  <tr>
+    <td><a href="${item.uri}" title="${item.uri}">${item.localId}</a></td>
+    <td>${item.mimetype}</td>
+    <td><a href="${it.rootUrl}/contenthub/metadata/${item.localId}">${item.enhancements}</a></td>
+  </tr>
+  </#list>
+</ul>
+</table>
+<ul class="previousNext">
+  <#if it.moreRecentItemsUri?exists>
+    <li class="moreRecent"><a href="${it.moreRecentItemsUri}">More recent items</a></li>
+  </#if>
+  <#if it.olderItemsUri?exists>
+    <li class="older"><a href="${it.olderItemsUri}">Older items</a></li>
+  </#if>
+</ul>
+</div>
+
+
+<h3>Submit a new Content Item for analysis</h3>
+
+<form method="POST" accept-charset="utf-8">
+  <fieldset>
+  <legend>Submit raw text content</legend>
+  <p><textarea rows="15" name="content"></textarea></p>
+  <p><input type="submit" value="Submit text"></p>
+  </fieldset>
+</form>
+
+<form method="POST" accept-charset="utf-8">
+  <fieldset>
+  <legend>Submit a remote public resource by URL</legend>
+  <p><input name="url" type="text" class="url" />
+     <input type="submit" value="Submit URL"></p>
+  </fieldset>
+</form>
+
+<form method="POST" accept-charset="utf-8"  enctype="multipart/form-data">
+  <fieldset>
+  <legend>Upload a local file</legend>
+  <p><input name="file" type="file"/>
+     <input type="submit" value="Submit file"></p>
+  </fieldset>
+</form>
+
+
+</div>
+
+<div class="panel" id="restapi" style="display: none;">
+<h3>Uploading new content to the Content Hub</h3>
+
+  <p>You can upload content to the Content Hub for analysis with or without providing the content
+   id at your option:<p>
+  <ol>
+    <li><code>PUT</code> content to <code>${it.publicBaseUri}contenthub/content/<strong>content-id</strong></code>
+     with <code>Content-Type: text/plain</code>.</li>
+    <li><code>GET</code> enhancements from the same URL with
+     header <code>Accept: application/rdf+xml</code>.</li>
+  </ol>
+  
+  <p><code><strong>content-id</strong></code> can be any valid path and
+   will be used to fetch your item back later.</p>
+
+  <p>On a unix-ish box you can use run the following command from
+   the top-level source directory to populate the Stanbol enhancer service with
+    sample content items:</p>
+
+<pre>
+for file in enhancer/data/text-examples/*.txt;
+do
+  curl -i -X PUT -H "Content-Type:text/plain" -T $file ${it.publicBaseUri}contenthub/content/$(basename $file) ;
+done
+</pre> 
+
+  Alternatively you can let the Stanbol enhancer automatically build an id base on the SHA1
+  hash of the content by posting it at the root of the Content Hub.
+  <ol>
+    <li><code>POST</code> content to <code>${it.publicBaseUri}contenthub/</code>
+     with <code>Content-Type: text/plain</code>.</li>
+    <li><code>GET</code> enhancements from the URL in the response along with
+       header <code>Accept: application/rdf+xml</code>.</li>
+  </ol>
+  
+  <p>For instance:</p>
+<pre>
+curl -i -X POST -H "Content-Type:text/plain" \
+     --data "The Stanbol enhancer can detect famous cities such as Paris." \
+     ${it.publicBaseUri}contenthub
+    
+HTTP/1.1 201 Created
+Location: ${it.publicBaseUri}contenthub/content/sha1-84854eb6802a601ca2349ba28cc55f0b930ac96d
+Content-Length: 0
+Server: Jetty(6.1.x)
+</pre>
+
+
+<h3>Fetching back the original content item and the related enhancements from the Content Hub</h3>
+
+<p>Once the content is created in the Content Hub, you can fetch back either the original content, a HTML summary view or
+the extracted RDF metadata by dereferencing the URL using the <code>Accept</code> header
+as selection switch:<p>
+
+<pre>
+curl -i <strong>-H "Accept: text/plain"</strong> ${it.publicBaseUri}contenthub/content/sha1-84854eb6802a601ca2349ba28cc55f0b930ac96d
+
+HTTP/1.1 307 TEMPORARY_REDIRECT
+Location: ${it.publicBaseUri}contenthub/<strong>raw</strong>/sha1-84854eb6802a601ca2349ba28cc55f0b930ac96d
+Content-Length: 0
+Server: Jetty(6.1.x)
+</pre>
+
+<pre>
+curl -i <strong>-H "Accept: text/html"</strong> ${it.publicBaseUri}contenthub/content/sha1-84854eb6802a601ca2349ba28cc55f0b930ac96d
+
+HTTP/1.1 307 TEMPORARY_REDIRECT
+Location: ${it.publicBaseUri}contenthub/<strong>page</strong>/sha1-84854eb6802a601ca2349ba28cc55f0b930ac96d
+Content-Length: 0
+Server: Jetty(6.1.x)
+</pre>
+
+<pre>
+curl -i <strong>-H "Accept: application/rdf+xml"</strong> ${it.publicBaseUri}contenthub/content/sha1-84854eb6802a601ca2349ba28cc55f0b930ac96d
+
+HTTP/1.1 307 TEMPORARY_REDIRECT
+Location: ${it.publicBaseUri}contenthub/<strong>metadata</strong>/sha1-84854eb6802a601ca2349ba28cc55f0b930ac96d
+Content-Length: 0
+Server: Jetty(6.1.x)
+</pre>
+
+</div>
+
+
+</...@common.page>
+</#escape>

Modified: incubator/stanbol/trunk/enhancer/engines/autotagging/src/main/java/org/apache/stanbol/enhancer/engines/autotagging/impl/RelatedTopicEnhancementEngine.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/enhancer/engines/autotagging/src/main/java/org/apache/stanbol/enhancer/engines/autotagging/impl/RelatedTopicEnhancementEngine.java?rev=1090299&r1=1090298&r2=1090299&view=diff
==============================================================================
--- incubator/stanbol/trunk/enhancer/engines/autotagging/src/main/java/org/apache/stanbol/enhancer/engines/autotagging/impl/RelatedTopicEnhancementEngine.java (original)
+++ incubator/stanbol/trunk/enhancer/engines/autotagging/src/main/java/org/apache/stanbol/enhancer/engines/autotagging/impl/RelatedTopicEnhancementEngine.java Fri Apr  8 15:30:19 2011
@@ -48,8 +48,8 @@ import org.slf4j.LoggerFactory;
  *
  * @author ogrisel
  */
-@Component(immediate = false, metatype = true)
-@Service
+//@Component(immediate = false, metatype = true)
+//@Service
 public class RelatedTopicEnhancementEngine implements EnhancementEngine {
 
     protected static final String TEXT_PLAIN_MIMETYPE = "text/plain";

Modified: incubator/stanbol/trunk/enhancer/integration-tests/pom.xml
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/enhancer/integration-tests/pom.xml?rev=1090299&r1=1090298&r2=1090299&view=diff
==============================================================================
--- incubator/stanbol/trunk/enhancer/integration-tests/pom.xml (original)
+++ incubator/stanbol/trunk/enhancer/integration-tests/pom.xml Fri Apr  8 15:30:19 2011
@@ -134,7 +134,7 @@
             <server.ready.timeout.seconds>180</server.ready.timeout.seconds>
             <server.ready.path.1>/:stanbol.css</server.ready.path.1>
             <server.ready.path.2>/engines:There are currently</server.ready.path.2>
-            <server.ready.path.3>/store:Recently uploaded Content Items</server.ready.path.3>
+            <server.ready.path.3>/contenthub:Recently uploaded Content Items</server.ready.path.3>
           </systemPropertyVariables>
         </configuration>
       </plugin>

Modified: incubator/stanbol/trunk/enhancer/integration-tests/src/test/java/org/apache/stanbol/enhancer/it/EnhancerTestBase.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/enhancer/integration-tests/src/test/java/org/apache/stanbol/enhancer/it/EnhancerTestBase.java?rev=1090299&r1=1090298&r2=1090299&view=diff
==============================================================================
--- incubator/stanbol/trunk/enhancer/integration-tests/src/test/java/org/apache/stanbol/enhancer/it/EnhancerTestBase.java (original)
+++ incubator/stanbol/trunk/enhancer/integration-tests/src/test/java/org/apache/stanbol/enhancer/it/EnhancerTestBase.java Fri Apr  8 15:30:19 2011
@@ -73,9 +73,7 @@ public class EnhancerTestBase extends St
                     "org.apache.stanbol.*NamedEntityExtractionEnhancementEngine",
                     "org.apache.stanbol.*OpenCalaisEngine",
                     "org.apache.stanbol.*EntityMentionEnhancementEngine",
-                    "org.apache.stanbol.*RelatedTopicEnhancementEngine",
                     "org.apache.stanbol.*CachingDereferencerEngine",
-                    //added by rwesten
                     "org.apache.stanbol.*ReferencedSiteEntityTaggingEnhancementEngine"
                 );
                 

Modified: incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/fragment/EnhancerWebFragment.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/fragment/EnhancerWebFragment.java?rev=1090299&r1=1090298&r2=1090299&view=diff
==============================================================================
--- incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/fragment/EnhancerWebFragment.java (original)
+++ incubator/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/fragment/EnhancerWebFragment.java Fri Apr  8 15:30:19 2011
@@ -14,7 +14,6 @@ import org.apache.stanbol.commons.web.ba
 import org.apache.stanbol.commons.web.base.ScriptResource;
 import org.apache.stanbol.commons.web.base.WebFragment;
 import org.apache.stanbol.enhancer.jersey.resource.EnginesRootResource;
-import org.apache.stanbol.enhancer.jersey.resource.ContentHubRootResource;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.component.ComponentContext;
 
@@ -52,7 +51,6 @@ public class EnhancerWebFragment impleme
         Set<Class<?>> classes = new HashSet<Class<?>>();
         // resources
         classes.add(EnginesRootResource.class);
-        classes.add(ContentHubRootResource.class);
         return classes;
     }
 
@@ -92,7 +90,6 @@ public class EnhancerWebFragment impleme
     public List<NavigationLink> getNavigationLinks() {
         List<NavigationLink> links = new ArrayList<NavigationLink>();
         links.add(new NavigationLink("engines", "/engines", "/imports/enginesDescription.ftl", 10));
-        links.add(new NavigationLink("contenthub", "/contenthub", "/imports/contenthubDescription.ftl", 20));
         return links;
     }
 

Modified: incubator/stanbol/trunk/enhancer/launchers/full/src/main/bundles/list.xml
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/enhancer/launchers/full/src/main/bundles/list.xml?rev=1090299&r1=1090298&r2=1090299&view=diff
==============================================================================
--- incubator/stanbol/trunk/enhancer/launchers/full/src/main/bundles/list.xml (original)
+++ incubator/stanbol/trunk/enhancer/launchers/full/src/main/bundles/list.xml Fri Apr  8 15:30:19 2011
@@ -357,6 +357,11 @@
         </bundle>
 		<bundle>
 			<groupId>org.apache.stanbol</groupId>
+			<artifactId>org.apache.stanbol.contenthub.web</artifactId>
+			<version>0.9-SNAPSHOT</version>
+		</bundle>
+		<bundle>
+			<groupId>org.apache.stanbol</groupId>
 			<artifactId>org.apache.stanbol.enhancer.engines.metaxa</artifactId>
 			<version>0.9-SNAPSHOT</version>
 		</bundle>

Modified: incubator/stanbol/trunk/parent/pom.xml
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/parent/pom.xml?rev=1090299&r1=1090298&r2=1090299&view=diff
==============================================================================
--- incubator/stanbol/trunk/parent/pom.xml (original)
+++ incubator/stanbol/trunk/parent/pom.xml Fri Apr  8 15:30:19 2011
@@ -290,6 +290,12 @@
       </dependency>
       <dependency>
         <groupId>org.apache.stanbol</groupId>
+        <artifactId>org.apache.stanbol.enhancer.jersey</artifactId>
+        <version>${stanbol-version}</version>
+        <scope>provided</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.stanbol</groupId>
         <artifactId>org.apache.stanbol.autotagging</artifactId>
         <version>${stanbol-version}</version>
         <scope>provided</scope>