marmotta-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ja...@apache.org
Subject [11/17] git commit: MARMOTT-514: Only one test is now failing, and that one is only a SHOULD!
Date Wed, 10 Sep 2014 09:39:02 GMT
MARMOTT-514: Only one test is now failing, and that one is only a SHOULD!

This solves MARMOTTA-515, MARMOTTA-516, MARMOTTA-517, MARMOTTA-518, MARMOTTA-519, MARMOTTA-520


Project: http://git-wip-us.apache.org/repos/asf/marmotta/repo
Commit: http://git-wip-us.apache.org/repos/asf/marmotta/commit/30227f31
Tree: http://git-wip-us.apache.org/repos/asf/marmotta/tree/30227f31
Diff: http://git-wip-us.apache.org/repos/asf/marmotta/diff/30227f31

Branch: refs/heads/ldp
Commit: 30227f31c12babe6716bc3e43df68b3aba53a20a
Parents: 13d8e64
Author: Jakob Frank <jakob@apache.org>
Authored: Fri Sep 5 09:55:41 2014 +0200
Committer: Jakob Frank <jakob@apache.org>
Committed: Fri Sep 5 10:22:48 2014 +0200

----------------------------------------------------------------------
 .../commons/http/MarmottaHttpUtils.java         |   2 +
 .../platform/ldp/services/LdpServiceImpl.java   |  14 +-
 .../marmotta/platform/ldp/util/LdpUtils.java    |  24 +-
 .../platform/ldp/webservices/LdpWebService.java | 371 +++++++++++++------
 4 files changed, 282 insertions(+), 129 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/marmotta/blob/30227f31/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/http/MarmottaHttpUtils.java
----------------------------------------------------------------------
diff --git a/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/http/MarmottaHttpUtils.java
b/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/http/MarmottaHttpUtils.java
index 568829d..d1e070c 100644
--- a/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/http/MarmottaHttpUtils.java
+++ b/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/http/MarmottaHttpUtils.java
@@ -105,6 +105,8 @@ public class MarmottaHttpUtils {
 
 
     public static ContentType parseContentType(String c) {
+        if (StringUtils.isBlank(c)) return null;
+
         String mt[] = c.split(";");
 
         String[] tst = mt[0].split("/");

http://git-wip-us.apache.org/repos/asf/marmotta/blob/30227f31/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 c592dea..cdb48cc 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
@@ -108,7 +108,7 @@ public class LdpServiceImpl implements LdpService {
         uriBuilder.path(uriInfo.getPathParameters().getFirst("local"));
         // uriBuilder.path(uriInfo.getPath().replaceFirst("/$", ""));
         String uri = uriBuilder.build().toString();
-        log.debug("Request URI: {}", uri);
+        log.debug("=== Request URI: {}", uri);
         return uri;
     }
 
@@ -197,7 +197,7 @@ public class LdpServiceImpl implements LdpService {
             } else {
                 return null;
             }
-        }finally {
+        } finally {
             it.close();
         }
     }
@@ -228,7 +228,7 @@ public class LdpServiceImpl implements LdpService {
             } else {
                 return null;
             }
-        }finally {
+        } finally {
             it.close();
         }
     }
@@ -323,6 +323,7 @@ public class LdpServiceImpl implements LdpService {
         connection.add(container, DCTERMS.modified, now, ldpContext);
 
         connection.add(resource, RDF.TYPE, LDP.Resource, ldpContext);
+        connection.add(resource, RDF.TYPE, LDP.RDFSource, ldpContext);
         connection.add(resource, ldpInteractionModelProperty, interactionModel.getUri(),
ldpContext);
         connection.add(resource, DCTERMS.created, now, ldpContext);
         connection.add(resource, DCTERMS.modified, now, ldpContext);
@@ -331,9 +332,11 @@ public class LdpServiceImpl implements LdpService {
         // 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));
         if (rdfFormat == null) {
-            log.debug("POST creates new LDP-NR, because no suitable RDF parser found for
type {}", type);
+            log.debug("Creating new LDP-NR, because no suitable RDF parser found for type
{}", type);
             final Literal format = valueFactory.createLiteral(type);
             final URI binaryResource = valueFactory.createURI(resource.stringValue() + LdpUtils.getExtension(type));
+            log.debug("LDP-NR is <{}>", binaryResource);
+            log.debug("Corresponding LDP-RS is <{}>", resource);
 
             connection.add(container, LDP.contains, binaryResource, ldpContext);
 
@@ -354,8 +357,7 @@ public class LdpServiceImpl implements LdpService {
 
             return binaryResource.stringValue();
         } else {
-            log.debug("POST creates new LDP-RS, data provided as {}", rdfFormat.getName());
-            connection.add(resource, RDF.TYPE, LDP.RDFSource, ldpContext);
+            log.debug("Creating new LDP-RS, data provided as {}", rdfFormat.getName());
             connection.add(container, LDP.contains, resource, ldpContext);
 
             // FIXME: We are (are we?) allowed to filter out server-managed properties here

http://git-wip-us.apache.org/repos/asf/marmotta/blob/30227f31/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 4ec9fe7..9a81086 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
@@ -33,6 +33,7 @@ import org.openrdf.rio.RDFFormat;
 import org.openrdf.rio.RDFHandlerException;
 import org.openrdf.rio.RDFParserRegistry;
 import org.openrdf.rio.RDFWriter;
+import org.slf4j.Logger;
 
 import javax.ws.rs.core.MediaType;
 import java.io.File;
@@ -48,6 +49,8 @@ import java.util.Set;
  */
 public class LdpUtils {
 
+    private static Logger log = org.slf4j.LoggerFactory.getLogger(LdpUtils.class);
+
     /**
      * Urify the Slug: header value, i.e. replace all non-url chars with a single dash.
      *
@@ -78,12 +81,19 @@ public class LdpUtils {
      * @return file extension (already including '.')
      */
     public static String getExtension(String mimeType) {
-        MimeTypes allTypes = MimeTypes.getDefaultMimeTypes();
+        final String defaultExt = ".bin";
+        final MimeTypes allTypes = MimeTypes.getDefaultMimeTypes();
         try {
-            return allTypes.forName(mimeType).getExtension();
+            final String ext = allTypes.forName(mimeType).getExtension();
+            log.trace("Tika's file-extension for {} is '{}'", mimeType, ext);
+            if (StringUtils.isNotBlank(ext)) {
+                return ext;
+            }
         } catch (MimeTypeException e) {
-            return null; //FIXME
+            log.trace("MimeTypeException: {}. Not critical, recovering...", e.getMessage());
         }
+        log.trace("Using fallback file-extension '{}' for {}", defaultExt, mimeType);
+        return defaultExt;
     }
 
     /**
@@ -137,14 +147,18 @@ public class LdpUtils {
         return sb.toString();
     }
 
-    public static URI getContainer(String resource) throws MalformedURLException, URISyntaxException
{
+    public static String getContainer(String resource) throws MalformedURLException, URISyntaxException
{
         java.net.URI uri = new java.net.URI(resource);
         java.net.URI parent = uri.getPath().endsWith("/") ? uri.resolve("..") : uri.resolve(".");
-        return new URIImpl(parent.toASCIIString());
+        return parent.toASCIIString();
     }
 
     public static URI getContainer(URI resource) throws MalformedURLException, URISyntaxException
{
         return new URIImpl(resource.getNamespace());
     }
 
+    private LdpUtils() {
+        // Static access only
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/marmotta/blob/30227f31/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 7a8e772..29c9ca9 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
@@ -43,7 +43,6 @@ import org.openrdf.repository.RepositoryException;
 import org.openrdf.rio.*;
 import org.slf4j.Logger;
 
-import javax.annotation.PostConstruct;
 import javax.enterprise.context.ApplicationScoped;
 import javax.enterprise.event.Observes;
 import javax.inject.Inject;
@@ -53,6 +52,8 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 
@@ -85,6 +86,39 @@ public class LdpWebService {
     @Inject
     private SesameService sesameService;
 
+    private final List<ContentType> producedRdfTypes;
+
+    public LdpWebService() {
+        producedRdfTypes = new ArrayList<>();
+
+        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 {
+                primaryQ = ";q=0.5";
+            }
+            final String secondaryQ = ";q=0.3";
+            final List<String> mimeTypes = format.getMIMETypes();
+            for (int i = 0; i < mimeTypes.size(); i++) {
+                final String mime = mimeTypes.get(i);
+                if (i == 0) {
+                    // first mimetype is the default
+                    producedRdfTypes.add(MarmottaHttpUtils.parseContentType(mime + primaryQ));
+                } else {
+                    producedRdfTypes.add(MarmottaHttpUtils.parseContentType(mime + secondaryQ));
+                }
+            }
+        }
+        Collections.sort(producedRdfTypes);
+
+        log.debug("Available RDF Serializer: {}", producedRdfTypes);
+    }
+
     protected void initialize(@Observes SesameStartupEvent event) {
         log.info("Starting up LDP WebService Endpoint");
         String root = UriBuilder.fromUri(configurationService.getBaseUri()).path(LdpWebService.PATH).build().toASCIIString();
@@ -105,23 +139,25 @@ public class LdpWebService {
 
     @GET
     public Response GET(@Context final UriInfo uriInfo, @Context Request r,
-                        @HeaderParam(HttpHeaders.ACCEPT) @DefaultValue(MediaType.WILDCARD)
MediaType type)
+                        @HeaderParam(HttpHeaders.ACCEPT) @DefaultValue(MediaType.WILDCARD)
String type)
             throws RepositoryException {
         final String resource = ldpService.getResourceUri(uriInfo);
         log.debug("GET to LDPR <{}>", resource);
-        return buildGetResponse(resource, r, type).build();
+        return buildGetResponse(resource, r, MarmottaHttpUtils.parseAcceptHeader(type)).build();
     }
 
     @HEAD
     public Response HEAD(@Context final UriInfo uriInfo, @Context Request r,
-                         @HeaderParam(HttpHeaders.ACCEPT) @DefaultValue(MediaType.WILDCARD)
MediaType type)
+                         @HeaderParam(HttpHeaders.ACCEPT) @DefaultValue(MediaType.WILDCARD)
String type)
             throws RepositoryException {
         final String resource = ldpService.getResourceUri(uriInfo);
         log.debug("HEAD to LDPR <{}>", resource);
-        return buildGetResponse(resource, r, type).entity(null).build();
+        return buildGetResponse(resource, r, MarmottaHttpUtils.parseAcceptHeader(type)).entity(null).build();
     }
 
-    private Response.ResponseBuilder buildGetResponse(final String resource, Request r, MediaType
type) throws RepositoryException {
+    private Response.ResponseBuilder buildGetResponse(final String resource, Request r, List<ContentType>
acceptedContentTypes) throws RepositoryException {
+        log.trace("LDPR requested media type {}", acceptedContentTypes);
+        MediaType type = MediaType.valueOf(acceptedContentTypes.get(0).toString());
         final RepositoryConnection conn = sesameService.getConnection();
         try {
             conn.begin();
@@ -136,75 +172,59 @@ public class LdpWebService {
                 log.trace("{} exists, continuing", resource);
             }
 
-            final RDFFormat format;
-            final RDFFormat fallback = (ldpService.isNonRdfSourceResource(conn, resource)
? null : RDFFormat.TURTLE);
-            final String mimeType = LdpUtils.getMimeType(type);
-            if (StringUtils.isBlank(mimeType) || "text/plain".equals(mimeType)) {
-                // TODO: find a better way to support n-triples (text/plain)
-                //       while still supporting regular text files
-                format = null;
-            } else if (type.isWildcardSubtype() && "text".equals(type.getType()))
{
-                format = RDFFormat.TURTLE;
-            } else {
-                ContentType contentType = MarmottaHttpUtils.performContentNegotiation(mimeType,
exportService.getProducedTypes());
-                format = (contentType != null ? Rio.getWriterFormatForMIMEType(contentType.getMime(),
fallback) : fallback);
-            }
-
-            if (format == null) {
-                log.debug("GET to <{}> with non-RDF format {} of a LDP-NR", resource,
type);
-                final StreamingOutput entity = new StreamingOutput() {
-                    @Override
-                    public void write(OutputStream out) throws IOException, WebApplicationException
{
-                        try {
-                            final RepositoryConnection outputConn = sesameService.getConnection();
-                            try {
-                                outputConn.begin();
-                                ldpService.exportBinaryResource(outputConn, resource, out);
-                                outputConn.commit();
-                            } catch (RepositoryException | IOException e) {
-                                outputConn.rollback();
-                                throw new WebApplicationException(e, createResponse(Response.status(Response.Status.INTERNAL_SERVER_ERROR)).entity(e).build());
-                            } finally {
-                                outputConn.close();
-                            }
-                        } catch (RepositoryException e) {
-                            throw new WebApplicationException(e, createResponse(Response.status(Response.Status.INTERNAL_SERVER_ERROR)).entity(e).build());
+            // Content-Neg
+            if (ldpService.isNonRdfSourceResource(conn, resource)) {
+                log.trace("<{}> is marked as LDP-NR", resource);
+                // LDP-NR
+                final ContentType realType = MarmottaHttpUtils.parseContentType(ldpService.getMimeType(conn,
resource));
+                if (realType == null) {
+                    // Fallback to related LDP-RS
+                    log.trace("<{}> does not look like a LDP-NR (no format found),
trying the corresponding LDP-RS", resource);
+                    final URI ldpRS = ldpService.getRdfSourceForNonRdfSource(conn, resource);
+                    if (ldpRS == null) {
+                        log.debug("No corresponding LDP-RS found for <{}>, sending
406", resource);
+                        final Response.ResponseBuilder resp = build406Response(conn, resource,
Collections.<ContentType>emptyList());
+                        conn.commit();
+                        return resp;
+                    } else {
+                        // Sending back the corresponding LDP-RS
+                        log.trace("Using corresponding LDP-RS <{}> for LDP-NR <{}>",
ldpRS, resource);
+                        final ContentType bestType = MarmottaHttpUtils.bestContentType(producedRdfTypes,
acceptedContentTypes);
+                        if (bestType == null) {
+                            log.trace("Available formats {} do not match any of the requested
formats {} for <{}>, sending 406", producedRdfTypes, acceptedContentTypes, resource);
+                            final Response.ResponseBuilder resp = build406Response(conn,
resource, producedRdfTypes);
+                            conn.commit();
+                            return resp;
+                        } else {
+                            log.trace("Sending corresponding LDP-RS <{}> for requested
LDP-NR <{}> using {}", ldpRS, resource, bestType);
+                            final Response.ResponseBuilder resp = buildGetResponseSourceResource(conn,
ldpRS.stringValue(), Rio.getWriterFormatForMIMEType(bestType.getMime(), RDFFormat.TURTLE));
+                            conn.commit();
+                            return resp;
                         }
                     }
-                };
-                final String realType = ldpService.getMimeType(conn, resource);
-                final Response.ResponseBuilder resp = createResponse(conn, Response.Status.OK,
resource).entity(entity).type(realType != null ? MediaType.valueOf(realType) : type);
-                conn.commit();
-                return resp;
+                } else if (MarmottaHttpUtils.bestContentType(Collections.singletonList(realType),
acceptedContentTypes) == null) {
+                    log.debug("Can't send <{}> ({}) in any of the accepted formats:
{}, sending 406");
+                    final Response.ResponseBuilder resp = build406Response(conn, resource,
Collections.singletonList(realType));
+                    conn.commit();
+                    return resp;
+                } else {
+                    final Response.ResponseBuilder resp = buildGetResponseBinaryResource(conn,
resource);
+                    conn.commit();
+                    return resp;
+                }
             } else {
-                // Deliver all triples from the <subject> context.
-                log.debug("GET to <{}> with RDF format {} of a LPD-R", resource, format.getDefaultMIMEType());
-                final StreamingOutput entity = new StreamingOutput() {
-                    @Override
-                    public void write(OutputStream output) throws IOException, WebApplicationException
{
-                        try {
-                            final RepositoryConnection outputConn = sesameService.getConnection();
-                            try {
-                                outputConn.begin();
-                                ldpService.exportResource(outputConn, resource, output, format);
-                                outputConn.commit();
-                            } catch (RDFHandlerException e) {
-                                outputConn.rollback();
-                                throw new NoLogWebApplicationException(e, createResponse(Response.status(Response.Status.INTERNAL_SERVER_ERROR)).entity(e.getMessage()).build());
-                            } catch (final Throwable t) {
-                                outputConn.rollback();
-                                throw t;
-                            } finally {
-                                outputConn.close();
-                            }
-                        } catch (RepositoryException e) {
-                            throw new WebApplicationException(e, createResponse(Response.status(Response.Status.INTERNAL_SERVER_ERROR)).entity(e).build());
-                        }
-                    }
-                };
-                final Response.ResponseBuilder resp = createResponse(conn, Response.Status.OK,
resource).entity(entity).type(format.getDefaultMIMEType());
-                conn.commit();
-                return resp;
+                // Requested Resource is a LDP-RS
+                final ContentType bestType = MarmottaHttpUtils.bestContentType(producedRdfTypes,
acceptedContentTypes);
+                if (bestType == null) {
+                    log.trace("Available formats {} do not match any of the requested formats
{} for <{}>, sending 406", producedRdfTypes, acceptedContentTypes, resource);
+                    final Response.ResponseBuilder resp = build406Response(conn, resource,
producedRdfTypes);
+                    conn.commit();
+                    return resp;
+                } else {
+                    final Response.ResponseBuilder resp = buildGetResponseSourceResource(conn,
resource, Rio.getWriterFormatForMIMEType(bestType.getMime(), RDFFormat.TURTLE));
+                    conn.commit();
+                    return resp;
+                }
             }
         } catch (final Throwable t) {
             conn.rollback();
@@ -214,6 +234,74 @@ public class LdpWebService {
         }
     }
 
+    private Response.ResponseBuilder build406Response(RepositoryConnection connection, String
resource, List<ContentType> availableContentTypes) throws RepositoryException {
+        final Response.ResponseBuilder response = createResponse(connection, Response.Status.NOT_ACCEPTABLE,
resource);
+        if (availableContentTypes.isEmpty()) {
+            response.entity(String.format("%s is not available in the requested format%n",
resource));
+        } else {
+            response.entity(String.format("%s is only available in the following formats:
%s%n", resource, availableContentTypes));
+        }
+        // Sec. 4.2.2.2
+        return addOptionsHeader(connection, resource, response);
+    }
+
+    private Response.ResponseBuilder buildGetResponseBinaryResource(RepositoryConnection
connection, final String resource) throws RepositoryException {
+        final String realType = ldpService.getMimeType(connection, resource);
+        log.debug("Building response for LDP-NR <{}> with format {}", resource, realType);
+        final StreamingOutput entity = new StreamingOutput() {
+            @Override
+            public void write(OutputStream out) throws IOException, WebApplicationException
{
+                try {
+                    final RepositoryConnection outputConn = sesameService.getConnection();
+                    try {
+                        outputConn.begin();
+                        ldpService.exportBinaryResource(outputConn, resource, out);
+                        outputConn.commit();
+                    } catch (RepositoryException | IOException e) {
+                        outputConn.rollback();
+                        throw new WebApplicationException(e, createResponse(Response.status(Response.Status.INTERNAL_SERVER_ERROR)).entity(e).build());
+                    } finally {
+                        outputConn.close();
+                    }
+                } catch (RepositoryException e) {
+                    throw new WebApplicationException(e, createResponse(Response.status(Response.Status.INTERNAL_SERVER_ERROR)).entity(e).build());
+                }
+            }
+        };
+        // Sec. 4.2.2.2
+        return addOptionsHeader(connection, resource, createResponse(connection, Response.Status.OK,
resource).entity(entity).type(realType));
+    }
+
+    private Response.ResponseBuilder buildGetResponseSourceResource(RepositoryConnection
conn, final String resource, final RDFFormat format) throws RepositoryException {
+        // Deliver all triples from the <subject> context.
+        log.debug("Building response for LDP-RS <{}> with RDF format {}", resource,
format.getDefaultMIMEType());
+        final StreamingOutput entity = new StreamingOutput() {
+            @Override
+            public void write(OutputStream output) throws IOException, WebApplicationException
{
+                try {
+                    final RepositoryConnection outputConn = sesameService.getConnection();
+                    try {
+                        outputConn.begin();
+                        ldpService.exportResource(outputConn, resource, output, format);
+                        outputConn.commit();
+                    } catch (RDFHandlerException e) {
+                        outputConn.rollback();
+                        throw new NoLogWebApplicationException(e, createResponse(Response.status(Response.Status.INTERNAL_SERVER_ERROR)).entity(e.getMessage()).build());
+                    } catch (final Throwable t) {
+                        outputConn.rollback();
+                        throw t;
+                    } finally {
+                        outputConn.close();
+                    }
+                } catch (RepositoryException e) {
+                    throw new WebApplicationException(e, createResponse(Response.status(Response.Status.INTERNAL_SERVER_ERROR)).entity(e).build());
+                }
+            }
+        };
+        // Sec. 4.2.2.2
+        return addOptionsHeader(conn, resource, createResponse(conn, Response.Status.OK,
resource).entity(entity).type(format.getDefaultMIMEType()));
+    }
+
     /**
      * LDP Post Request
      *
@@ -222,7 +310,7 @@ public class LdpWebService {
      */
     @POST
     public Response POST(@Context UriInfo uriInfo, @HeaderParam("Slug") String slug,
-                         @HeaderParam("Link") List<Link> linkHeaders,
+                         @HeaderParam(HttpHeaders.LINK) List<Link> linkHeaders,
                          InputStream postBody, @HeaderParam(HttpHeaders.CONTENT_TYPE) MediaType
type)
             throws RepositoryException {
 
@@ -281,25 +369,8 @@ public class LdpWebService {
             }
 
             log.debug("POST to <{}> will create new LDP-R <{}>", container, newResource);
-            final String mimeType = LdpUtils.getMimeType(type);
-            //checking if resource (container) exists is done later in the service
-            try {
-                String location = ldpService.addResource(conn, container, newResource, ldpInteractionModel,
mimeType, postBody);
-                final Response.ResponseBuilder response = createResponse(conn, Response.Status.CREATED,
container).location(java.net.URI.create(location));
-                if (newResource.compareTo(location) != 0) {
-                    response.link(newResource, "describedby"); //FIXME: Sec. 5.2.3.12, see
also http://www.w3.org/2012/ldp/track/issues/15
-                }
-                conn.commit();
-                return response.build();
-            } catch (IOException | RDFParseException e) {
-                final Response.ResponseBuilder resp = createResponse(conn, Response.Status.BAD_REQUEST,
container).entity(e.getClass().getSimpleName() + ": " + e.getMessage());
-                conn.rollback();
-                return resp.build();
-            } catch (UnsupportedRDFormatException e) {
-                final Response.ResponseBuilder resp = createResponse(conn, Response.Status.UNSUPPORTED_MEDIA_TYPE,
container).entity(e);
-                conn.rollback();
-                return resp.build();
-            }
+            // connection is closed by buildPostResponse
+            return buildPostResponse(conn, container, newResource, ldpInteractionModel, postBody,
type);
         } catch (InvalidInteractionModelException e) {
             log.debug("POST with invalid interaction model <{}> to <{}>", e.getHref(),
container);
             final Response.ResponseBuilder response = createResponse(conn, Response.Status.BAD_REQUEST,
container);
@@ -314,10 +385,37 @@ public class LdpWebService {
     }
 
     /**
+     * @param connection the RepositoryConnection (with active transaction) to read extra
data from. WILL BE COMMITTED OR ROLLBACKED
+     * @throws RepositoryException
+     */
+    private Response buildPostResponse(RepositoryConnection connection, String container,
String newResource, LdpService.InteractionModel interactionModel, InputStream requestBody,
MediaType type) throws RepositoryException {
+        final String mimeType = LdpUtils.getMimeType(type);
+        //checking if resource (container) exists is done later in the service
+        try {
+            String location = ldpService.addResource(connection, container, newResource,
interactionModel, mimeType, requestBody);
+            final Response.ResponseBuilder response = createResponse(connection, Response.Status.CREATED,
container).location(java.net.URI.create(location));
+            if (newResource.compareTo(location) != 0) {
+                response.link(newResource, "describedby"); //FIXME: Sec. 5.2.3.12, see also
http://www.w3.org/2012/ldp/track/issues/15
+            }
+            connection.commit();
+            return response.build();
+        } catch (IOException | RDFParseException e) {
+            final Response.ResponseBuilder resp = createResponse(connection, Response.Status.BAD_REQUEST,
container).entity(e.getClass().getSimpleName() + ": " + e.getMessage());
+            connection.rollback();
+            return resp.build();
+        } catch (UnsupportedRDFormatException e) {
+            final Response.ResponseBuilder resp = createResponse(connection, Response.Status.UNSUPPORTED_MEDIA_TYPE,
container).entity(e);
+            connection.rollback();
+            return resp.build();
+        }
+    }
+
+    /**
      * Handle PUT (Sec. 4.2.4, Sec. 5.2.4)
      */
     @PUT
     public Response PUT(@Context UriInfo uriInfo, @Context Request request,
+                        @HeaderParam(HttpHeaders.LINK) List<Link> linkHeaders,
                         @HeaderParam(HttpHeaders.IF_MATCH) EntityTag eTag,
                         @HeaderParam(HttpHeaders.CONTENT_TYPE) MediaType type, InputStream
postBody)
             throws RepositoryException, IOException, InvalidModificationException, RDFParseException,
IncompatibleResourceTypeException, URISyntaxException {
@@ -332,7 +430,7 @@ public class LdpWebService {
             final Response.ResponseBuilder resp;
             final String newResource;  // NOTE: newResource == resource for now, this might
change in the future
             if (ldpService.exists(conn, resource)) {
-                log.debug("updating resource <{}>", resource);
+                log.debug("<{}> exists, so this is an UPDATE", resource);
 
                 if (eTag == null) {
                     // check for If-Match header (ETag) -> 428 Precondition Required (Sec.
4.2.4.5)
@@ -355,17 +453,42 @@ public class LdpWebService {
                 newResource = ldpService.updateResource(conn, resource, postBody, mimeType);
                 log.info("PUT update for <{}> successful", newResource);
                 resp = createResponse(conn, Response.Status.OK, resource);
+                conn.commit();
+                return resp.build();
             } else {
-                log.debug("creating resource <{}>", resource);
+                log.debug("<{}> does not exist, so this is a CREATE", resource);
                 //LDP servers may allow resource creation using PUT (Sec. 4.2.4.6)
+
+                final String container = LdpUtils.getContainer(resource);
+                try {
+                    // Check that the target container supports the LDPC Interaction Model
+                    final LdpService.InteractionModel containerModel = ldpService.getInteractionModel(conn,
container);
+                    if (containerModel != LdpService.InteractionModel.LDPC) {
+                        final Response.ResponseBuilder response = createResponse(conn, Response.Status.METHOD_NOT_ALLOWED,
container);
+                        conn.commit();
+                        return response.entity(String.format("%s only supports %s Interaction
Model", container, containerModel)).build();
+                    }
+
+                    // Get the LDP-Interaction Model (Sec. 5.2.3.4 and Sec. 4.2.1.4)
+                    final LdpService.InteractionModel ldpInteractionModel = ldpService.getInteractionModel(linkHeaders);
+
+                    // connection is closed by buildPostResponse
+                    return buildPostResponse(conn, container, resource, ldpInteractionModel,
postBody, type);
+                } catch (InvalidInteractionModelException e) {
+                    log.debug("PUT with invalid interaction model <{}> to <{}>",
e.getHref(), container);
+                    final Response.ResponseBuilder response = createResponse(conn, Response.Status.BAD_REQUEST,
container);
+                    conn.commit();
+                    return response.entity(e.getMessage()).build();
+                }
+                /*
                 URI uri = conn.getValueFactory().createURI(resource);
                 newResource = ldpService.addResource(conn, LdpUtils.getContainer(uri), uri,
LdpService.InteractionModel.LDPR, mimeType, postBody);
                 log.info("PUT on <{}> created new resource", newResource);
                 resp = createResponse(conn, Response.Status.CREATED, newResource).location(java.net.URI.create(newResource));
+                conn.commit();
+                return resp.build();
+                */
             }
-            conn.commit();
-
-            return resp.build();
         } catch (IOException | RDFParseException e) {
             final Response.ResponseBuilder resp = createResponse(conn, Response.Status.BAD_REQUEST,
resource).entity(e.getClass().getSimpleName() + ": " + e.getMessage());
             conn.rollback();
@@ -477,6 +600,7 @@ public class LdpWebService {
      * Handle OPTIONS (Sec. 4.2.8, Sec. 5.2.8)
      */
     @OPTIONS
+    @Produces("text/plain")
     public Response OPTIONS(@Context final UriInfo uriInfo) throws RepositoryException {
         final String resource = ldpService.getResourceUri(uriInfo);
         log.debug("OPTIONS to <{}>", resource);
@@ -489,22 +613,7 @@ public class LdpWebService {
 
             Response.ResponseBuilder builder = createResponse(con, Response.Status.OK, resource);
 
-            if (ldpService.isNonRdfSourceResource(con, resource)) {
-                // Sec. 4.2.8.2
-                builder.allow("GET", "HEAD", "OPTIONS");
-            } else if (ldpService.isRdfSourceResource(con, resource)) {
-                if (ldpService.getInteractionModel(con, resource) == LdpService.InteractionModel.LDPR)
{
-                    // Sec. 4.2.8.2
-                    builder.allow("GET", "HEAD", "PATCH", "OPTIONS");
-                } else {
-                    // Sec. 4.2.8.2
-                    builder.allow("GET", "HEAD", "POST", "PATCH", "OPTIONS");
-                    // Sec. 4.2.3 / Sec. 5.2.3
-                    builder.header("Accept-Post", LdpUtils.getAcceptPostHeader("*/*"));
-                }
-                // Sec. 4.2.7.1
-                builder.header("Accept-Patch", RdfPatchParser.MIME_TYPE);
-            }
+            addOptionsHeader(con, resource, builder);
 
             con.commit();
             return builder.build();
@@ -517,10 +626,35 @@ public class LdpWebService {
 
     }
 
+    private Response.ResponseBuilder addOptionsHeader(RepositoryConnection connection, String
resource, Response.ResponseBuilder builder) throws RepositoryException {
+        log.debug("Adding required LDP Headers (OPTIONS, GET); see Sec. 8.2.8 and Sec. 4.2.2.2");
+        if (ldpService.isNonRdfSourceResource(connection, resource)) {
+            // Sec. 4.2.8.2
+            log.trace("<{}> is an LDP-NR: GET, HEAD, PUT and OPTIONS allowed", resource);
+            builder.allow("GET", "HEAD", "PUT", "OPTIONS");
+        } else if (ldpService.isRdfSourceResource(connection, resource)) {
+            if (ldpService.getInteractionModel(connection, resource) == LdpService.InteractionModel.LDPR)
{
+                log.trace("<{}> is a LDP-RS (LDPR interaction model): GET, HEAD, PUT,
PATCH and OPTIONS allowed", resource);
+                // Sec. 4.2.8.2
+                builder.allow("GET", "HEAD", "PUT", "PATCH", "OPTIONS");
+            } else {
+                // Sec. 4.2.8.2
+                log.trace("<{}> is a LDP-RS (LDPC interaction model): GET, HEAD, POST,
PUT, PATCH and OPTIONS allowed", resource);
+                builder.allow("GET", "HEAD", "POST", "PUT", "PATCH", "OPTIONS");
+                // Sec. 4.2.3 / Sec. 5.2.3
+                builder.header("Accept-Post", LdpUtils.getAcceptPostHeader("*/*"));
+            }
+            // Sec. 4.2.7.1
+            builder.header("Accept-Patch", RdfPatchParser.MIME_TYPE);
+        }
+
+        return builder;
+    }
+
     /**
      * Add all the default headers specified in LDP to the Response
      *
-     * @param connection
+     * @param connection the RepositoryConnection (with active transaction) to read extra
data from
      * @param status the StatusCode
      * @param resource the iri/uri/url of the resouce
      * @return the provided ResponseBuilder for chaining
@@ -532,7 +666,7 @@ public class LdpWebService {
     /**
      * Add all the default headers specified in LDP to the Response
      *
-     * @param connection
+     * @param connection the RepositoryConnection (with active transaction) to read extra
data from
      * @param status the status code
      * @param resource the uri/url of the resouce
      * @return the provided ResponseBuilder for chaining
@@ -544,9 +678,9 @@ public class LdpWebService {
     /**
      * Add all the default headers specified in LDP to the Response
      *
-     * @param connection
+     * @param connection the RepositoryConnection (with active transaction) to read extra
data from
      * @param rb the ResponseBuilder
-     * @param resource the uri/url of the resouce
+     * @param resource the uri/url of the resource
      * @return the provided ResponseBuilder for chaining
      */
     protected Response.ResponseBuilder createResponse(RepositoryConnection connection, Response.ResponseBuilder
rb, String resource) throws RepositoryException {
@@ -566,8 +700,9 @@ public class LdpWebService {
             if (rdfSource != null) {
                 // Sec. 5.2.8.1 and 5.2.3.12
                 // FIXME: Sec. 5.2.3.12, see also http://www.w3.org/2012/ldp/track/issues/15
-                rb.link(rdfSource.stringValue(), "meta");
                 rb.link(rdfSource.stringValue(), "describedby");
+                // TODO: Propose to LDP-WG?
+                rb.link(rdfSource.stringValue(), "meta");
             }
             final URI nonRdfSource = ldpService.getNonRdfSourceForRdfSource(connection, resource);
             if (nonRdfSource != null) {


Mime
View raw message