Repository: marmotta
Updated Branches:
  refs/heads/develop 4daf7bdf7 -> bf7ee37eb


MARMOTTA-558: Improved Generation of new URIs when resources are POSTed.


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

Branch: refs/heads/develop
Commit: bf7ee37ebd6d85fdea746199fd4cd1dda1961f77
Parents: 406ce98
Author: Jakob Frank <[email protected]>
Authored: Thu Oct 30 17:15:41 2014 +0100
Committer: Jakob Frank <[email protected]>
Committed: Fri Oct 31 09:56:38 2014 +0100

----------------------------------------------------------------------
 .../ldp/util/AbstractResourceUriGenerator.java  | 63 ++++++++++++++++
 .../platform/ldp/util/RandomUriGenerator.java   | 77 ++++++++++++++++++++
 .../platform/ldp/util/SlugUriGenerator.java     | 50 +++++++++++++
 .../platform/ldp/util/UuidUriGenerator.java     | 38 ++++++++++
 .../platform/ldp/webservices/LdpWebService.java | 46 ++++--------
 5 files changed, 244 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/marmotta/blob/bf7ee37e/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/AbstractResourceUriGenerator.java
----------------------------------------------------------------------
diff --git 
a/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/AbstractResourceUriGenerator.java
 
b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/AbstractResourceUriGenerator.java
new file mode 100644
index 0000000..c3fe05f
--- /dev/null
+++ 
b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/AbstractResourceUriGenerator.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.platform.ldp.util;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.marmotta.platform.ldp.api.LdpService;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract baseclass to generate new URIs for a created resource.
+ */
+public abstract class AbstractResourceUriGenerator {
+
+    protected final Logger log = LoggerFactory.getLogger(this.getClass());
+    
+    private final LdpService ldpService;
+    private final String container;
+    private final RepositoryConnection connection;
+
+    protected AbstractResourceUriGenerator(LdpService ldpService, String 
container, RepositoryConnection connection) {
+        this.ldpService = ldpService;
+        this.container = StringUtils.removeEnd(container, "/");
+        this.connection = connection;
+    }
+    
+    public String generateResourceUri() throws RepositoryException {
+        String newResource = String.format("%s/%s", container, 
generateNextLocalName());
+        log.trace("Checking possible name clash for new resource <{}>", 
newResource);
+        if (ldpService.exists(connection, newResource) || 
ldpService.isReusedURI(connection, newResource)) {
+            do {
+                final String candidate = String.format("%s/%s", container, 
generateNextLocalName());
+                log.trace("<{}> already exists, trying <{}>", newResource, 
candidate);
+                newResource = candidate;
+            } while (ldpService.exists(connection, newResource) || 
ldpService.isReusedURI(connection, newResource));
+            log.debug("resolved name clash, new resource will be <{}>", 
newResource);
+        } else {
+            log.debug("no name clash for <{}>", newResource);
+        }
+
+        return newResource;
+    }
+
+    protected abstract String generateNextLocalName();
+
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/bf7ee37e/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/RandomUriGenerator.java
----------------------------------------------------------------------
diff --git 
a/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/RandomUriGenerator.java
 
b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/RandomUriGenerator.java
new file mode 100644
index 0000000..fe5ef6d
--- /dev/null
+++ 
b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/RandomUriGenerator.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.platform.ldp.util;
+
+import org.apache.marmotta.platform.ldp.api.LdpService;
+import org.openrdf.repository.RepositoryConnection;
+
+import java.util.Random;
+
+/**
+ * Random-Based URI Generator
+ */
+public class RandomUriGenerator extends AbstractResourceUriGenerator {
+
+    private static final char[] symbols;
+
+    static {
+        StringBuilder sb = new StringBuilder();
+        for (char ch = '0'; ch <= '9'; ++ch) {
+            sb.append(ch);
+        }
+        for (char ch = 'a'; ch <= 'z'; ++ch) {
+            sb.append(ch);
+        }
+        for (char ch = 'A'; ch <= 'Z'; ++ch) {
+            sb.append(ch);
+        }
+        symbols = sb.toString().toCharArray();
+    }
+
+    private final StringBuilder builder;
+    private final Random random;
+
+
+    public RandomUriGenerator(LdpService ldpService, String container, 
RepositoryConnection connection) {
+        super(ldpService, container, connection);
+        builder = new StringBuilder();
+        random = new Random();
+    }
+
+    @Override
+    protected String generateNextLocalName() {
+        return 
builder.append(symbols[random.nextInt(symbols.length)]).toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/bf7ee37e/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/SlugUriGenerator.java
----------------------------------------------------------------------
diff --git 
a/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/SlugUriGenerator.java
 
b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/SlugUriGenerator.java
new file mode 100644
index 0000000..e07a10f
--- /dev/null
+++ 
b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/SlugUriGenerator.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.platform.ldp.util;
+
+import org.apache.marmotta.platform.ldp.api.LdpService;
+import org.openrdf.repository.RepositoryConnection;
+
+/**
+ * Slug-Header based Generator for resource URIs.
+ */
+public class SlugUriGenerator extends AbstractResourceUriGenerator {
+
+    private final String slug;
+    private int i = 0;
+
+    public SlugUriGenerator(LdpService ldpService, String container, String 
slug, RepositoryConnection connection) {
+        super(ldpService, container, connection);
+
+        String localName = LdpUtils.urify(slug);
+        log.trace("Slug urified: {}", localName);
+
+        this.slug = localName;
+    }
+
+    @Override
+    protected String generateNextLocalName() {
+        if (i < 1) {
+            i++;
+            return slug;
+        } else {
+            return String.format("%s-%d", slug, i++);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/bf7ee37e/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/UuidUriGenerator.java
----------------------------------------------------------------------
diff --git 
a/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/UuidUriGenerator.java
 
b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/UuidUriGenerator.java
new file mode 100644
index 0000000..75860cb
--- /dev/null
+++ 
b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/util/UuidUriGenerator.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.platform.ldp.util;
+
+import org.apache.marmotta.platform.ldp.api.LdpService;
+import org.openrdf.repository.RepositoryConnection;
+
+import java.util.UUID;
+
+/**
+ * UUID-based URI generator.
+ */
+public class UuidUriGenerator extends AbstractResourceUriGenerator {
+
+    public UuidUriGenerator(LdpService ldpService, String container, 
RepositoryConnection connection) {
+        super(ldpService, container, connection);
+    }
+
+    @Override
+    protected String generateNextLocalName() {
+        return UUID.randomUUID().toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/bf7ee37e/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 f504885..98b5883 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
@@ -33,7 +33,10 @@ import 
org.apache.marmotta.platform.ldp.exceptions.InvalidModificationException;
 import org.apache.marmotta.platform.ldp.patch.InvalidPatchDocumentException;
 import org.apache.marmotta.platform.ldp.patch.parser.ParseException;
 import org.apache.marmotta.platform.ldp.patch.parser.RdfPatchParser;
+import org.apache.marmotta.platform.ldp.util.AbstractResourceUriGenerator;
 import org.apache.marmotta.platform.ldp.util.LdpUtils;
+import org.apache.marmotta.platform.ldp.util.RandomUriGenerator;
+import org.apache.marmotta.platform.ldp.util.SlugUriGenerator;
 import org.jboss.resteasy.spi.NoLogWebApplicationException;
 import org.openrdf.model.Statement;
 import org.openrdf.model.URI;
@@ -386,21 +389,6 @@ public class LdpWebService {
             // Get the LDP-Interaction Model (Sec. 5.2.3.4 and Sec. 4.2.1.4)
             final LdpService.InteractionModel ldpInteractionModel = 
ldpService.getInteractionModel(linkHeaders);
 
-            final String localName;
-            if (StringUtils.isBlank(slug)) {
-                /* Sec. 5.2.3.8) */
-                // FIXME: Maybe us a shorter uid?
-                localName = UUID.randomUUID().toString();
-            } else {
-                // Honor client wishes from Slug-header (Sec. 5.2.3.10)
-                //    http://www.ietf.org/rfc/rfc5023.txt
-                log.trace("Slug-Header is '{}'", slug);
-                localName = LdpUtils.urify(slug);
-                log.trace("Slug-Header urified: {}", localName);
-            }
-
-            String newResource = 
uriInfo.getRequestUriBuilder().path(localName).build().toString();
-
             if (ldpService.isNonRdfSourceResource(conn, container)) {
                 log.info("POSTing to a NonRdfSource is not allowed ({})", 
container);
                 final Response.ResponseBuilder response = createResponse(conn, 
Response.Status.METHOD_NOT_ALLOWED, container).entity("POST to NonRdfSource is 
not allowed\n");
@@ -408,20 +396,19 @@ public class LdpWebService {
                 return response.build();
             }
 
-            log.trace("Checking possible name clash for new resource <{}>", 
newResource);
-            if (ldpService.exists(conn, newResource) || 
ldpService.isReusedURI(conn, newResource)) {
-                int i = 0;
-                final String base = newResource;
-                do {
-                    final String candidate = base + "-" + (++i);
-                    log.trace("<{}> already exists, trying <{}>", newResource, 
candidate);
-                    newResource = candidate;
-                } while (ldpService.exists(conn, newResource) || 
ldpService.isReusedURI(conn, newResource));
-                log.debug("resolved name clash, new resource will be <{}>", 
newResource);
+            final AbstractResourceUriGenerator uriGenerator;
+            if (StringUtils.isBlank(slug)) {
+                /* Sec. 5.2.3.8) */
+                uriGenerator = new RandomUriGenerator(ldpService, container, 
conn);
             } else {
-                log.debug("no name clash for <{}>", newResource);
+                // Honor client wishes from Slug-header (Sec. 5.2.3.10)
+                //    http://www.ietf.org/rfc/rfc5023.txt
+                log.trace("Slug-Header is '{}'", slug);
+                uriGenerator = new SlugUriGenerator(ldpService, container, 
slug, conn);
             }
 
+            String newResource = uriGenerator.generateResourceUri();
+
             log.debug("POST to <{}> will create new LDP-R <{}>", container, 
newResource);
             // connection is closed by buildPostResponse
             return buildPostResponse(conn, container, newResource, 
ldpInteractionModel, postBody, type);
@@ -449,7 +436,7 @@ public class LdpWebService {
             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.links(Link.fromUri(newResource).rel(LINK_REL_DESCRIBEDBY).param(LINK_PARAM_ANCHOR,
 location).build()); //FIXME: Sec. 5.2.3.12, see also 
http://www.w3.org/2012/ldp/track/issues/15
+                
response.links(Link.fromUri(newResource).rel(LINK_REL_DESCRIBEDBY).param(LINK_PARAM_ANCHOR,
 location).build());
             }
             connection.commit();
             return response.build();
@@ -769,14 +756,13 @@ public class LdpWebService {
             final URI rdfSource = 
ldpService.getRdfSourceForNonRdfSource(connection, resource);
             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(), LINK_REL_DESCRIBEDBY);
-                // TODO: Propose to LDP-WG?
+                // This is not covered by the Spec, but is very convenient to 
have
                 rb.link(rdfSource.stringValue(), LINK_REL_META);
             }
             final URI nonRdfSource = 
ldpService.getNonRdfSourceForRdfSource(connection, resource);
             if (nonRdfSource != null) {
-                // TODO: Propose to LDP-WG?
+                // This is not covered by the Spec, but is very convenient to 
have
                 rb.link(nonRdfSource.stringValue(), LINK_REL_CONTENT);
             }
 

Reply via email to