MARMOTTA-556: added web service tier
Project: http://git-wip-us.apache.org/repos/asf/marmotta/repo Commit: http://git-wip-us.apache.org/repos/asf/marmotta/commit/205d4c12 Tree: http://git-wip-us.apache.org/repos/asf/marmotta/tree/205d4c12 Diff: http://git-wip-us.apache.org/repos/asf/marmotta/diff/205d4c12 Branch: refs/heads/MARMOTTA-556 Commit: 205d4c12dc40cf94515ba48b46015ff89e161773 Parents: 374d381 Author: Sergio Fernández <[email protected]> Authored: Fri Oct 24 20:23:39 2014 +0200 Committer: Sergio Fernández <[email protected]> Committed: Fri Oct 24 20:23:39 2014 +0200 ---------------------------------------------------------------------- .../marmotta/platform/ldf/api/LdfService.java | 27 +++++ .../platform/ldf/services/LdfServiceImpl.java | 60 +++++++++++ .../platform/ldf/sesame/LdfRDFHandler.java | 9 +- .../platform/ldf/webservices/LdfWebService.java | 106 +++++++++++++++++++ 4 files changed, 197 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/marmotta/blob/205d4c12/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/api/LdfService.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/api/LdfService.java b/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/api/LdfService.java index 1652818..9496589 100644 --- a/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/api/LdfService.java +++ b/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/api/LdfService.java @@ -45,6 +45,19 @@ public interface LdfService { * @param format RDF serialization * @param out output stream where write the fragment */ + void writeFragment(String subject, String predicate, String object, int page, RDFFormat format, OutputStream out) throws RepositoryException; + + /** + * Writes a fragment matching the specified triple fragment pattern + * specified (null values are wildcards). + * + * @param subject fragment subject + * @param predicate fragmnent predicate + * @param object fragment object + * @param page number of page (starting with 1) + * @param format RDF serialization + * @param out output stream where write the fragment + */ void writeFragment(URI subject, URI predicate, Value object, int page, RDFFormat format, OutputStream out) throws RepositoryException; /** @@ -59,6 +72,20 @@ public interface LdfService { * @param format RDF serialization * @param out output stream where write the fragment */ + void writeFragment(String subject, String predicate, String object, String context, int page, RDFFormat format, OutputStream out) throws RepositoryException; + + /** + * Writes a fragment matching the specified quad fragment pattern + * specified (null values are wildcards). + * + * @param subject fragment subject + * @param predicate fragmnent predicate + * @param object fragment object + * @param context named graph + * @param page number of page (starting with 1) + * @param format RDF serialization + * @param out output stream where write the fragment + */ void writeFragment(URI subject, URI predicate, Value object, Resource context, int page, RDFFormat format, OutputStream out) throws RepositoryException; } http://git-wip-us.apache.org/repos/asf/marmotta/blob/205d4c12/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/services/LdfServiceImpl.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/services/LdfServiceImpl.java b/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/services/LdfServiceImpl.java index 9da59b8..dc8fd7c 100644 --- a/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/services/LdfServiceImpl.java +++ b/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/services/LdfServiceImpl.java @@ -17,18 +17,23 @@ */ package org.apache.marmotta.platform.ldf.services; +import org.apache.commons.lang3.StringUtils; import org.apache.marmotta.commons.sesame.repository.ResultUtils; import org.apache.marmotta.platform.core.api.triplestore.SesameService; import org.apache.marmotta.platform.ldf.api.LdfService; import org.apache.marmotta.platform.ldf.sesame.LdfRDFHandler; import org.openrdf.model.*; +import org.openrdf.model.impl.ValueFactoryImpl; import org.openrdf.repository.RepositoryConnection; import org.openrdf.repository.RepositoryException; import org.openrdf.repository.RepositoryResult; import org.openrdf.rio.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.inject.Inject; import java.io.OutputStream; +import java.net.URISyntaxException; /** * Linked Media Fragments service implementation @@ -37,15 +42,70 @@ import java.io.OutputStream; */ public class LdfServiceImpl implements LdfService { + private static final Logger log = LoggerFactory.getLogger(LdfServiceImpl.class); + @Inject private SesameService sesameService; @Override + public void writeFragment(String subjectStr, String predicateStr, String objectStr, int page, RDFFormat format, OutputStream out) throws RepositoryException { + writeFragment(subjectStr, predicateStr, objectStr, null, page, format, out); + } + + @Override public void writeFragment(URI subject, URI predicate, Value object, int page, RDFFormat format, OutputStream out) throws RepositoryException { writeFragment(subject, predicate, object, null, page, format, out); } @Override + public void writeFragment(String subjectStr, String predicateStr, String objectStr, String contextStr, int page, RDFFormat format, OutputStream out) throws RepositoryException { + final ValueFactoryImpl vf = new ValueFactoryImpl(); + + URI subject = null; + if (StringUtils.isNotBlank(subjectStr)) { + try { + new java.net.URI(subjectStr); + subject = vf.createURI(subjectStr); + } catch (URISyntaxException e) { + log.error("invalid subject '{}': {}", subjectStr, e.getMessage()); + } + } + + URI predicate = null; + if (StringUtils.isNotBlank(predicateStr)) { + try { + new java.net.URI(predicateStr); + predicate = vf.createURI(predicateStr); + } catch (URISyntaxException e) { + log.error("invalid predicate '{}': {}", predicateStr, e.getMessage()); + } + } + + Value object = null; + if (StringUtils.isNotBlank(objectStr)) { + try { + new java.net.URI(objectStr); + object = vf.createURI(objectStr); + } catch (URISyntaxException e) { + object = vf.createLiteral(objectStr); + } + } + + URI context = null; + if (StringUtils.isNotBlank(contextStr)) { + try { + new java.net.URI(contextStr); + context = vf.createURI(contextStr); + } catch (URISyntaxException e) { + log.error("invalid context '{}': {}", contextStr, e.getMessage()); + } + } + + writeFragment(subject, predicate, object, context, page, format, out); + } + + + @Override public void writeFragment(URI subject, URI predicate, Value object, Resource context, int page, RDFFormat format, OutputStream out) throws RepositoryException { final RepositoryConnection conn = sesameService.getConnection(); try { http://git-wip-us.apache.org/repos/asf/marmotta/blob/205d4c12/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/sesame/LdfRDFHandler.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/sesame/LdfRDFHandler.java b/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/sesame/LdfRDFHandler.java index dcafb3a..2ba0e21 100644 --- a/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/sesame/LdfRDFHandler.java +++ b/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/sesame/LdfRDFHandler.java @@ -20,6 +20,7 @@ package org.apache.marmotta.platform.ldf.sesame; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import org.apache.marmotta.commons.vocabulary.XSD; +import org.apache.marmotta.platform.ldf.api.LdfService; import org.apache.marmotta.platform.ldf.vocab.HYDRA; import org.apache.marmotta.platform.ldf.vocab.VOID; import org.openrdf.model.Literal; @@ -47,8 +48,6 @@ import java.util.List; */ public class LdfRDFHandler implements RDFHandler { - public final static int PAGE_SIZE = 100; - private List<Statement> statements; private final RDFHandler handler; private final Resource context; @@ -127,11 +126,11 @@ public class LdfRDFHandler implements RDFHandler { //then filter final int size = statements.size(); - final int offset = PAGE_SIZE * (page - 1); + final int offset = LdfService.PAGE_SIZE * (page - 1); if (offset > size) { throw new IllegalArgumentException("page " + page + " can't be generated"); } - final int limit = PAGE_SIZE < size-offset ? PAGE_SIZE : size-offset; + final int limit = LdfService.PAGE_SIZE < size-offset ? LdfService.PAGE_SIZE : size-offset; List<Statement> filteredStatements = statements.subList(offset, limit); //send statements to delegate writer @@ -152,7 +151,7 @@ public class LdfRDFHandler implements RDFHandler { if (offset != 0 && limit != size) handler.handleStatement(new StatementImpl(fragment, RDF.TYPE, HYDRA.PagedCollection)); handler.handleStatement(new StatementImpl(fragment, VOID.triples, vf.createLiteral(Integer.toString(filteredStatements.size()), XSD.Integer))); handler.handleStatement(new StatementImpl(fragment, HYDRA.totalItems, vf.createLiteral(Integer.toString(filteredStatements.size()), XSD.Integer))); - handler.handleStatement(new StatementImpl(fragment, HYDRA.itemsPerPage, vf.createLiteral(Integer.toString(PAGE_SIZE), XSD.Integer))); + handler.handleStatement(new StatementImpl(fragment, HYDRA.itemsPerPage, vf.createLiteral(Integer.toString(LdfService.PAGE_SIZE), XSD.Integer))); //TODO: HYDRA_FIRSTPAGE, HYDRA_PREVIOUSPAGE, HYDRA_NEXTPAGE //TODO: hydra controls http://git-wip-us.apache.org/repos/asf/marmotta/blob/205d4c12/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/webservices/LdfWebService.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/webservices/LdfWebService.java b/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/webservices/LdfWebService.java new file mode 100644 index 0000000..dbfcb96 --- /dev/null +++ b/platform/marmotta-ldf/src/main/java/org/apache/marmotta/platform/ldf/webservices/LdfWebService.java @@ -0,0 +1,106 @@ +package org.apache.marmotta.platform.ldf.webservices; + +import org.apache.commons.lang3.StringUtils; +import org.apache.marmotta.commons.http.ContentType; +import org.apache.marmotta.commons.http.MarmottaHttpUtils; +import org.apache.marmotta.platform.core.api.config.ConfigurationService; +import org.apache.marmotta.platform.core.api.exporter.ExportService; +import org.apache.marmotta.platform.core.util.WebServiceUtil; +import org.apache.marmotta.platform.ldf.api.LdfService; +import org.openrdf.repository.RepositoryException; +import org.openrdf.rio.RDFFormat; +import org.openrdf.rio.Rio; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Linked Data Fragments web service implementation + * + * @author Sergio Fernández + */ +@ApplicationScoped +@Path(LdfWebService.PATH) +public class LdfWebService { + + public static final String PATH = "/fragments"; + + @Inject + private LdfService ldfService; + + @Inject + private ConfigurationService configurationService; + + @Inject + private ExportService exportService; + + private static final String UUID_PATTERN = "{uuid:[^#?]+}"; + + @GET + public Response getFragment(@QueryParam("subject") String subject, + @QueryParam("predicate") String predicate, + @QueryParam("object") String object, + @QueryParam("page") String page, + @HeaderParam("Accept") String accept) { + return getFragment(subject, predicate, object, null, Integer.parseInt(StringUtils.defaultString(page, "1")), accept); + } + + @GET + @Path(UUID_PATTERN) + public Response getFragment(@QueryParam("subject") String subject, + @QueryParam("predicate") String predicate, + @QueryParam("object") String object, + @QueryParam("page") String page, + @PathParam("uuid") String uuid, + @HeaderParam("Accept") String accept) { + final String context = buildContextUri(uuid); + return getFragment(subject, predicate, object, context, Integer.parseInt(StringUtils.defaultString(page, "1")), accept); + } + + private Response getFragment(final String subject, + final String predicate, + final String object, + final String context, + final int page, + final String accept) { + final RDFFormat format = getFormat(accept); + + StreamingOutput stream = new StreamingOutput() { + @Override + public void write(OutputStream outputStream) throws IOException, WebApplicationException { + try { + ldfService.writeFragment(subject, predicate, object, context, page, format, outputStream); + } catch (RepositoryException e) { + throw new WebApplicationException(e); + } + } + }; + return Response.ok(stream).build(); + } + + private RDFFormat getFormat(String accept) { + List<ContentType> acceptedTypes = MarmottaHttpUtils.parseAcceptHeader(accept); + List<ContentType> offeredTypes = MarmottaHttpUtils.parseStringList(exportService.getProducedTypes()); + offeredTypes.removeAll(Collections.unmodifiableList(Arrays.asList(new ContentType("text", "html"), new ContentType("application", "xhtml+xml")))); + final ContentType bestType = MarmottaHttpUtils.bestContentType(offeredTypes, acceptedTypes); + return Rio.getWriterFormatForMIMEType(bestType.getMime()); + } + + private String buildContextUri(String uuid) { + if (StringUtils.isNotBlank(uuid)) { + String root = configurationService.getBaseUri(); + return root.substring(0, root.length() - 1) + WebServiceUtil.getResourcePath(this) + "/" + uuid; + } else { + return null; + } + } + +}
