jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ju...@apache.org
Subject svn commit: r1381214 - in /jackrabbit/oak/trunk: oak-core/ oak-core/src/main/java/org/apache/jackrabbit/oak/core/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/ oak-jcr/src/...
Date Wed, 05 Sep 2012 15:04:37 GMT
Author: jukka
Date: Wed Sep  5 15:04:36 2012
New Revision: 1381214

URL: http://svn.apache.org/viewvc?rev=1381214&view=rev
Log:
OAK-270: Enforce uniqueness of jcr:uuid

Basic commit hook for enforcing uniqueness constraints. Basic test case.

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexHook.java
  (with props)
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexValidator.java
  (with props)
Modified:
    jackrabbit/oak/trunk/oak-core/pom.xml
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/CompositeValidator.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/ValidatingHook.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java

Modified: jackrabbit/oak/trunk/oak-core/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/pom.xml?rev=1381214&r1=1381213&r2=1381214&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-core/pom.xml Wed Sep  5 15:04:36 2012
@@ -46,7 +46,9 @@
               org.apache.jackrabbit.oak.plugins.identifier,
               org.apache.jackrabbit.oak.plugins.name,
               org.apache.jackrabbit.oak.plugins.type,
+              org.apache.jackrabbit.oak.plugins.unique,
               org.apache.jackrabbit.oak.plugins.value,
+              org.apache.jackrabbit.oak.spi,
               org.apache.jackrabbit.oak.spi.commit,
               org.apache.jackrabbit.oak.spi.state,
               org.apache.jackrabbit.oak.spi.security.authentication,

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java?rev=1381214&r1=1381213&r2=1381214&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ContentRepositoryImpl.java
Wed Sep  5 15:04:36 2012
@@ -127,6 +127,7 @@ public class ContentRepositoryImpl imple
             microKernel.commit("/", "^\"jcr:primaryType\":\"nam:rep:root\"" +
                 "+\"jcr:system\":{" +
                     "\"jcr:primaryType\"    :\"nam:rep:system\"," +
+                    "\":unique\"            :{\"jcr:uuid\":{}}," +
                     "\"jcr:versionStorage\" :{\"jcr:primaryType\":\"nam:rep:versionStorage\"},"
+
                     "\"jcr:nodeTypes\"      :{\"jcr:primaryType\":\"nam:rep:nodeTypes\"},"
+
                     "\"jcr:activities\"     :{\"jcr:primaryType\":\"nam:rep:Activities\"},"
+

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexHook.java?rev=1381214&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexHook.java
(added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexHook.java
Wed Sep  5 15:04:36 2012
@@ -0,0 +1,72 @@
+/*
+ * 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.jackrabbit.oak.plugins.unique;
+
+import java.util.List;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.commit.ValidatingHook;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Commit hook for validating uniqueness constraints and maintaining
+ * indices of unique properties.
+ * <p>
+ * TODO: verify if enforcing uniqueness constraints is really
+ * feasible in oak-core taking potential clustering into account
+ * <p>
+ * TODO: check if constraint validation needs to take property
+ * definition into account e.g. a jcr:uuid property that isn't
+ * defined by mix:referenceable may not necessarily be subject
+ * to the validation.
+ */
+public class UniqueIndexHook implements CommitHook {
+
+    @Override
+    public NodeState processCommit(
+            NodeStore store, NodeState before, NodeState after)
+            throws CommitFailedException {
+        NodeBuilder builder = store.getBuilder(after);
+        NodeBuilder system = builder.getChildBuilder("jcr:system");
+        NodeBuilder unique = system.getChildBuilder(":unique");
+
+        final List<UniqueIndexValidator> validators = Lists.newArrayList();
+        NodeState state = unique.getNodeState();
+        for (ChildNodeEntry entry : state.getChildNodeEntries()) {
+            validators.add(new UniqueIndexValidator(
+                    entry.getName(), entry.getNodeState()));
+        }
+        if (validators.isEmpty()) {
+            return after; // shortcut
+        }
+
+        new ValidatingHook(validators).processCommit(store, before, after);
+
+        for (UniqueIndexValidator validator : validators) {
+            validator.apply(unique);
+        }
+
+        return builder.getNodeState();
+    }
+
+}
\ No newline at end of file

Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexHook.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexValidator.java?rev=1381214&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexValidator.java
(added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexValidator.java
Wed Sep  5 15:04:36 2012
@@ -0,0 +1,165 @@
+/*
+ * 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.jackrabbit.oak.plugins.unique;
+
+import java.util.Map;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.CoreValue;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.plugins.memory.StringValue;
+import org.apache.jackrabbit.oak.spi.commit.Validator;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+
+import com.google.common.collect.Maps;
+
+public class UniqueIndexValidator implements Validator {
+
+    private final String name;
+
+    private final NodeState index;
+
+    private final String path;
+
+    private final Map<String, String> insert;
+
+    private final Map<String, String> remove;
+
+    public UniqueIndexValidator(String name, NodeState index) {
+        this.name = name;
+        this.index = index;
+        this.path = "";
+        this.insert = Maps.newHashMap();
+        this.remove = Maps.newHashMap();
+    }
+
+    private UniqueIndexValidator(UniqueIndexValidator parent, String name) {
+        this.name = parent.name;
+        this.index = parent.index;
+        if (parent.path.isEmpty()) {
+            this.path = name;
+        } else {
+            this.path = parent.path + "/" + name;
+        }
+        this.insert = parent.insert;
+        this.remove = parent.remove;
+    }
+
+    public void apply(NodeBuilder unique) throws CommitFailedException {
+        NodeBuilder builder = unique.getChildBuilder(name);
+
+        for (Map.Entry<String, String> entry : remove.entrySet()) {
+            String value = encode(entry.getKey());
+            PropertyState property = builder.getProperty(value);
+            if (property != null) {
+                String path = entry.getValue();
+                if (property.isArray()
+                        || path.equals(property.getValue().getString())) {
+                    builder.removeProperty(value);
+                }
+            }
+        }
+
+        for (Map.Entry<String, String> entry : insert.entrySet()) {
+            String value = encode(entry.getKey());
+            String path = entry.getValue();
+            PropertyState property = builder.getProperty(value);
+            if (property != null) {
+                if (!property.isArray()
+                        && !path.equals(property.getValue().getString())) {
+                    throw new CommitFailedException(
+                            "Uniqueness constraint violation: "
+                            + name + " = " + entry.getKey());
+                }
+            }
+            builder.setProperty(value, new StringValue(path));
+        }
+    }
+
+    private String encode(String value) {
+        return value; // TODO: escape to valid name
+    }
+
+    private void insert(Iterable<CoreValue> values)
+            throws CommitFailedException {
+        for (CoreValue value : values) {
+            if (insert.put(value.getString(), path) != null) {
+                throw new CommitFailedException(
+                        "Uniqueness constraint violated: "
+                        + name + " = " + value.getString());
+            }
+        }
+    }
+
+    private void remove(Iterable<CoreValue> values) {
+        for (CoreValue value : values) {
+            remove.put(value.getString(), path);
+        }
+    }
+
+    @Override
+    public void propertyAdded(PropertyState after)
+            throws CommitFailedException {
+        if (name.equals(after.getName())) {
+            insert(after.getValues());
+        }
+    }
+
+    @Override
+    public void propertyChanged(PropertyState before, PropertyState after)
+            throws CommitFailedException {
+        if (name.equals(before.getName())) {
+            remove(before.getValues());
+            insert(after.getValues());
+        }
+    }
+
+    @Override
+    public void propertyDeleted(PropertyState before)
+            throws CommitFailedException {
+        if (name.equals(before.getName())) {
+            remove(before.getValues());
+        }
+    }
+
+    @Override
+    public Validator childNodeAdded(String name, NodeState after) {
+        return descend(name);
+    }
+
+    @Override
+    public Validator childNodeChanged(
+            String name, NodeState before, NodeState after) {
+        return descend(name);
+    }
+
+    @Override
+    public Validator childNodeDeleted(String name, NodeState before) {
+        return descend(name);
+    }
+
+    private Validator descend(String name) {
+        if (NodeStateUtils.isHidden(name)) {
+            return null;
+        } else {
+            return new UniqueIndexValidator(this, name);
+        }
+    }
+
+}
\ No newline at end of file

Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexValidator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/CompositeValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/CompositeValidator.java?rev=1381214&r1=1381213&r2=1381214&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/CompositeValidator.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/CompositeValidator.java
Wed Sep  5 15:04:36 2012
@@ -21,6 +21,7 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -28,12 +29,16 @@ import java.util.List;
  * a single validator.
  */
 public class CompositeValidator implements Validator {
-    private final List<Validator> validators;
+    private final List<? extends Validator> validators;
 
-    public CompositeValidator(List<Validator> validators) {
+    public CompositeValidator(List<? extends Validator> validators) {
         this.validators = validators;
     }
 
+    public CompositeValidator(Validator... validators) {
+        this(Arrays.asList(validators));
+    }
+
     @Override
     public void propertyAdded(PropertyState after) throws CommitFailedException {
         for (Validator validator : validators) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/ValidatingHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/ValidatingHook.java?rev=1381214&r1=1381213&r2=1381214&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/ValidatingHook.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/ValidatingHook.java
Wed Sep  5 15:04:36 2012
@@ -16,6 +16,9 @@
  */
 package org.apache.jackrabbit.oak.spi.commit;
 
+import java.util.Arrays;
+import java.util.List;
+
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -46,6 +49,24 @@ public class ValidatingHook implements C
         this(new CompositeValidatorProvider(providers));
     }
 
+    public ValidatingHook(final Validator validator) {
+        this(new ValidatorProvider() {
+            @Override
+            public Validator getRootValidator(
+                    NodeState before, NodeState after) {
+                return validator;
+            }
+        });
+    }
+
+    public ValidatingHook(List<? extends Validator> validators) {
+        this(new CompositeValidator(validators));
+    }
+
+    public ValidatingHook(Validator... validators) {
+        this(Arrays.asList(validators));
+    }
+
     @Override
     public NodeState processCommit(
             NodeStore store, NodeState before, NodeState after)

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java?rev=1381214&r1=1381213&r2=1381214&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java
(original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java
Wed Sep  5 15:04:36 2012
@@ -35,12 +35,15 @@ import org.apache.jackrabbit.oak.core.Co
 import org.apache.jackrabbit.oak.plugins.name.NameValidatorProvider;
 import org.apache.jackrabbit.oak.plugins.name.NamespaceValidatorProvider;
 import org.apache.jackrabbit.oak.plugins.type.TypeValidatorProvider;
+import org.apache.jackrabbit.oak.plugins.unique.UniqueIndexHook;
 import org.apache.jackrabbit.oak.plugins.value.ConflictValidatorProvider;
 import org.apache.jackrabbit.oak.security.authorization.AccessControlValidatorProvider;
 import org.apache.jackrabbit.oak.security.authorization.PermissionValidatorProvider;
 import org.apache.jackrabbit.oak.security.privilege.PrivilegeValidatorProvider;
 import org.apache.jackrabbit.oak.security.user.UserValidatorProvider;
+import org.apache.jackrabbit.oak.spi.commit.CompositeHook;
 import org.apache.jackrabbit.oak.spi.commit.CompositeValidatorProvider;
+import org.apache.jackrabbit.oak.spi.commit.ValidatingHook;
 import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
 import org.apache.jackrabbit.oak.spi.security.user.UserConfig;
 import org.slf4j.Logger;
@@ -82,7 +85,11 @@ public class RepositoryImpl implements R
 
     public RepositoryImpl(
             MicroKernel kernel, ScheduledExecutorService executor) {
-        this(new ContentRepositoryImpl(kernel, DEFAULT_VALIDATOR), executor);
+        this(new ContentRepositoryImpl(
+                kernel, null, new CompositeHook(
+                        new ValidatingHook(DEFAULT_VALIDATOR),
+                        new UniqueIndexHook())),
+                executor);
     }
 
     /**

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java?rev=1381214&r1=1381213&r2=1381214&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java
(original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java
Wed Sep  5 15:04:36 2012
@@ -27,6 +27,7 @@ import java.util.Calendar;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.UUID;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
@@ -1771,6 +1772,26 @@ public class RepositoryTest extends Abst
         assertTrue(c2.hasProperty("pc2"));
     }
 
+    @Test
+    public void testUniqueness() throws RepositoryException {
+        Session session = getAdminSession();
+
+        Node node = getNode("/foo");
+        node.addMixin("mix:referenceable");
+        node.setProperty("jcr:uuid", UUID.randomUUID().toString());
+        session.save();
+
+        Node node2 = node.addNode("foo2");
+        node2.addMixin("mix:referenceable");
+        node2.setProperty("jcr:uuid", node.getProperty("jcr:uuid").getValue());
+        try {
+            session.save();
+            fail();
+        } catch (RepositoryException e) {
+            // expected
+        }
+    }
+
     //------------------------------------------------------------< private >---
 
     private Node getNode(String path) throws RepositoryException {



Mime
View raw message