MARMOTTA-570: Fixed handling of LDP-RS Content-Types for POST/PUT
Project: http://git-wip-us.apache.org/repos/asf/marmotta/repo Commit: http://git-wip-us.apache.org/repos/asf/marmotta/commit/92704fcb Tree: http://git-wip-us.apache.org/repos/asf/marmotta/tree/92704fcb Diff: http://git-wip-us.apache.org/repos/asf/marmotta/diff/92704fcb Branch: refs/heads/master Commit: 92704fcb2cb180904c51d63f09b1ec1ba62edf49 Parents: 1711fca Author: Jakob Frank <[email protected]> Authored: Thu Nov 13 14:05:33 2014 +0100 Committer: Jakob Frank <[email protected]> Committed: Thu Nov 13 14:05:33 2014 +0100 ---------------------------------------------------------------------- .../platform/core/test/ld/LinkedDataTest.java | 26 +++---- .../marmotta/platform/ldp/api/LdpService.java | 1 + .../platform/ldp/services/LdpServiceImpl.java | 5 +- .../marmotta/platform/ldp/util/LdpUtils.java | 80 ++++++++++++++++++-- .../platform/ldp/webservices/LdpWebService.java | 17 +++-- 5 files changed, 97 insertions(+), 32 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/marmotta/blob/92704fcb/platform/marmotta-core/src/test/java/org/apache/marmotta/platform/core/test/ld/LinkedDataTest.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-core/src/test/java/org/apache/marmotta/platform/core/test/ld/LinkedDataTest.java b/platform/marmotta-core/src/test/java/org/apache/marmotta/platform/core/test/ld/LinkedDataTest.java index ce50ab2..cd62f51 100644 --- a/platform/marmotta-core/src/test/java/org/apache/marmotta/platform/core/test/ld/LinkedDataTest.java +++ b/platform/marmotta-core/src/test/java/org/apache/marmotta/platform/core/test/ld/LinkedDataTest.java @@ -17,14 +17,8 @@ package org.apache.marmotta.platform.core.test.ld; -import static com.jayway.restassured.RestAssured.expect; -import static com.jayway.restassured.RestAssured.given; - -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.Random; - +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.restassured.RestAssured; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.RandomStringUtils; import org.apache.marmotta.platform.core.api.triplestore.ContextService; @@ -33,11 +27,7 @@ import org.apache.marmotta.platform.core.test.base.JettyMarmotta; import org.apache.marmotta.platform.core.webservices.resource.ContentWebService; import org.apache.marmotta.platform.core.webservices.resource.MetaWebService; import org.apache.marmotta.platform.core.webservices.resource.ResourceWebService; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.*; import org.openrdf.model.Statement; import org.openrdf.model.URI; import org.openrdf.repository.Repository; @@ -50,8 +40,13 @@ import org.openrdf.rio.RDFParseException; import org.openrdf.rio.Rio; import org.openrdf.sail.memory.MemoryStore; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.jayway.restassured.RestAssured; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.Random; + +import static com.jayway.restassured.RestAssured.expect; +import static com.jayway.restassured.RestAssured.given; /** * This test verifies the functionality of the Linked Data endpoint @@ -228,6 +223,7 @@ public class LinkedDataTest { String body = data.toString(); given() + .log().ifValidationFails() .header("Content-Type", format.getDefaultMIMEType()) .body(body.getBytes()) .expect() http://git-wip-us.apache.org/repos/asf/marmotta/blob/92704fcb/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/api/LdpService.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/api/LdpService.java b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/api/LdpService.java index 306cfa3..cb52bfa 100644 --- a/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/api/LdpService.java +++ b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/api/LdpService.java @@ -49,6 +49,7 @@ import java.util.*; public interface LdpService { public static final Set<URI> SERVER_MANAGED_PROPERTIES = new HashSet<>(Arrays.asList(LDP.contains)); + public static final List<RDFFormat> SERVER_PREFERED_RDF_FORMATS = Arrays.asList(RDFFormat.TURTLE, RDFFormat.JSONLD, RDFFormat.RDFXML, RDFFormat.N3, RDFFormat.NTRIPLES); public static enum InteractionModel { LDPR(LDP.Resource), http://git-wip-us.apache.org/repos/asf/marmotta/blob/92704fcb/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/services/LdpServiceImpl.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/services/LdpServiceImpl.java b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/services/LdpServiceImpl.java index 80ddc25..500b77b 100644 --- a/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/services/LdpServiceImpl.java +++ b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/services/LdpServiceImpl.java @@ -380,8 +380,7 @@ public class LdpServiceImpl implements LdpService { connection.add(resource, DCTERMS.modified, now, ldpContext); // Add the bodyContent - // TODO: find a better way to ingest n-triples (text/plain) while still supporting regular text files - final RDFFormat rdfFormat = ("text/plain".equals(type) ? null : Rio.getParserFormatForMIMEType(type)); + final RDFFormat rdfFormat = LdpUtils.matchDefaultMIMEType(type, LdpUtils.filterAvailableParsers(SERVER_PREFERED_RDF_FORMATS), null); if (rdfFormat == null) { log.debug("Creating new LDP-NR, because no suitable RDF parser found for type {}", type); final Literal format = valueFactory.createLiteral(type); @@ -477,7 +476,7 @@ public class LdpServiceImpl implements LdpService { public boolean add(RepositoryConnection conn, Resource subject, URI predicate, Value object, Resource... contexts) { try { if (connection.hasStatement(subject, predicate, object, true, ldpContext)) { - // Ignore/Strip any triple that is already present in the mgnt-context (i.e. "unchanged" props). + // Ignore/Strip any triple that is already present in the mgmt-context (i.e. "unchanged" props). return true; } else if (resource.equals(subject) && SERVER_MANAGED_PROPERTIES.contains(predicate)) { // We do NOT allow changing server-managed properties. http://git-wip-us.apache.org/repos/asf/marmotta/blob/92704fcb/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/LdpUtils.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/LdpUtils.java b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/LdpUtils.java index 326f55f..fca8187 100644 --- a/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/LdpUtils.java +++ b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/LdpUtils.java @@ -18,9 +18,11 @@ package org.apache.marmotta.platform.ldp.util; import info.aduna.iteration.CloseableIteration; +import info.aduna.lang.FileFormat; import org.apache.commons.lang3.StringUtils; import org.apache.marmotta.commons.vocabulary.LDP; import org.apache.marmotta.commons.vocabulary.XSD; +import org.apache.marmotta.platform.ldp.api.LdpService; import org.apache.marmotta.platform.ldp.api.Preference; import org.apache.marmotta.platform.ldp.webservices.PreferHeader; import org.apache.tika.mime.MimeTypeException; @@ -31,16 +33,15 @@ import org.openrdf.model.impl.URIImpl; import org.openrdf.model.vocabulary.DCTERMS; import org.openrdf.model.vocabulary.RDF; import org.openrdf.repository.RepositoryException; -import org.openrdf.rio.RDFFormat; -import org.openrdf.rio.RDFHandlerException; -import org.openrdf.rio.RDFParserRegistry; -import org.openrdf.rio.RDFWriter; +import org.openrdf.rio.*; import org.slf4j.Logger; import javax.ws.rs.core.MediaType; import java.net.MalformedURLException; import java.net.URISyntaxException; -import java.util.Set; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; /** * Various Util-Methods for the {@link org.apache.marmotta.platform.ldp.api.LdpService}. @@ -133,7 +134,7 @@ public class LdpUtils { } public static String getAcceptPostHeader(String extraFormats) { - final Set<RDFFormat> rdfFormats = RDFParserRegistry.getInstance().getKeys(); + final Collection<RDFFormat> rdfFormats = filterAvailableParsers(LdpService.SERVER_PREFERED_RDF_FORMATS); final StringBuilder sb = new StringBuilder(); for (RDFFormat rdfFormat : rdfFormats) { sb.append(rdfFormat.getDefaultMIMEType()); @@ -147,6 +148,50 @@ public class LdpUtils { return sb.toString(); } + /** + * Tries to match the specified MIME type with the MIME types of the supplied + * file formats. + * This method does exactly the same as {@link info.aduna.lang.FileFormat#matchMIMEType(String, Iterable)} + * but only considers the <strong>default</strong> mimeTypes. + * + * @param mimeType A MIME type, e.g. "text/plain". + * @param fileFormats The file formats to match the MIME type against. + * @return A FileFormat object if the MIME type was recognized, or {@code null} otherwise. + * + * @see #matchDefaultMIMEType(String, Iterable, info.aduna.lang.FileFormat) + * @see info.aduna.lang.FileFormat#matchMIMEType(String, Iterable) + * + */ + public static <FF extends FileFormat> FF matchDefaultMIMEType(String mimeType, Iterable<FF> fileFormats) { + return matchDefaultMIMEType(mimeType, fileFormats, null); + } + + /** + * Tries to match the specified MIME type with the default MIME types of the supplied + * file formats. The supplied fallback format will be returned when no + * matching format was found. + * This method does exactly the same as {@link info.aduna.lang.FileFormat#matchMIMEType(String, Iterable, info.aduna.lang.FileFormat)} + * but only considers the <strong>default</strong> mimeTypes. + * + * @param mimeType A MIME type, e.g. "text/plain". + * @param fileFormats The file formats to match the MIME type against. + * @param fallback The file format to return if no matching format can be found. + * @return A FileFormat that matches the MIME type, or the fallback format if the extension was not recognized. + * + * @see info.aduna.lang.FileFormat#matchMIMEType(String, Iterable, info.aduna.lang.FileFormat) + * + */ + public static <FF extends FileFormat> FF matchDefaultMIMEType(String mimeType, Iterable<FF> fileFormats, + FF fallback) { + // Try to match with the default MIME type + for (FF fileFormat : fileFormats) { + if (fileFormat.hasDefaultMIMEType(mimeType)) { + return fileFormat; + } + } + return fallback; + } + public static String getContainer(String resource) throws MalformedURLException, URISyntaxException { final int fragmentIndex = resource.indexOf('#'); if (fragmentIndex >= 0) { @@ -190,6 +235,29 @@ public class LdpUtils { return null; } + public static List<RDFFormat> filterAvailableParsers(List<RDFFormat> rdfFormats) { + final List<RDFFormat> result = new ArrayList<>(); + final RDFParserRegistry parserRegistry = RDFParserRegistry.getInstance(); + for (RDFFormat f: rdfFormats) { + if (parserRegistry.has(f)) { + result.add(f); + } + } + return result; + } + + public static List<RDFFormat> filterAvailableWriters(List<RDFFormat> rdfFormats) { + final List<RDFFormat> result = new ArrayList<>(); + final RDFWriterRegistry writerRegistry = RDFWriterRegistry.getInstance(); + for (RDFFormat f: rdfFormats) { + if (writerRegistry.has(f)) { + result.add(f); + } + } + return result; + } + + private LdpUtils() { // Static access only } http://git-wip-us.apache.org/repos/asf/marmotta/blob/92704fcb/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/webservices/LdpWebService.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/webservices/LdpWebService.java b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/webservices/LdpWebService.java index 92a799e..46b9cde 100644 --- a/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/webservices/LdpWebService.java +++ b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/webservices/LdpWebService.java @@ -58,7 +58,7 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.UUID; +import java.util.Locale; /** * Linked Data Platform web services. @@ -107,17 +107,18 @@ public class LdpWebService { public LdpWebService() { producedRdfTypes = new ArrayList<>(); + final List<RDFFormat> availableWriters = LdpUtils.filterAvailableWriters(LdpService.SERVER_PREFERED_RDF_FORMATS); for(RDFFormat format : RDFWriterRegistry.getInstance().getKeys()) { final String primaryQ; - if (format == RDFFormat.TURTLE) { - primaryQ = ";q=1.0"; - } else if (format == RDFFormat.JSONLD) { - primaryQ = ";q=0.9"; - } else if (format == RDFFormat.RDFXML) { - primaryQ = ";q=0.8"; - } else { + final int idx = availableWriters.indexOf(format); + if (idx < 0) { + // not a prefered format primaryQ = ";q=0.5"; + } else { + // a prefered format + primaryQ = String.format(Locale.ENGLISH, ";q=%.1f", Math.max(1.0-(idx*0.1), 0.55)); } + final String secondaryQ = ";q=0.3"; final List<String> mimeTypes = format.getMIMETypes(); for (int i = 0; i < mimeTypes.size(); i++) {
