From oak-commits-return-2660-apmail-jackrabbit-oak-commits-archive=jackrabbit.apache.org@jackrabbit.apache.org Mon Jan 28 10:24:06 2013 Return-Path: X-Original-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Delivered-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 5A5A9E786 for ; Mon, 28 Jan 2013 10:24:06 +0000 (UTC) Received: (qmail 34667 invoked by uid 500); 28 Jan 2013 10:24:06 -0000 Delivered-To: apmail-jackrabbit-oak-commits-archive@jackrabbit.apache.org Received: (qmail 34636 invoked by uid 500); 28 Jan 2013 10:24:05 -0000 Mailing-List: contact oak-commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: oak-dev@jackrabbit.apache.org Delivered-To: mailing list oak-commits@jackrabbit.apache.org Received: (qmail 34608 invoked by uid 99); 28 Jan 2013 10:24:04 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 28 Jan 2013 10:24:04 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 28 Jan 2013 10:24:02 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id D8C4723888FE; Mon, 28 Jan 2013 10:23:43 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1439331 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/index/p2/ test/java/org/apache/jackrabbit/oak/plugins/index/p2/ Date: Mon, 28 Jan 2013 10:23:43 -0000 To: oak-commits@jackrabbit.apache.org From: alexparvulescu@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130128102343.D8C4723888FE@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: alexparvulescu Date: Mon Jan 28 10:23:43 2013 New Revision: 1439331 URL: http://svn.apache.org/viewvc?rev=1439331&view=rev Log: OAK-396 Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2Index.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexDiff.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexUpdate.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2Index.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2Index.java?rev=1439331&r1=1439330&r2=1439331&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2Index.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2Index.java Mon Jan 28 10:23:43 2013 @@ -38,7 +38,7 @@ import com.google.common.base.Charsets; *

* To define a property index on a subtree you have to add an oak:index node. * - * Under it follows the index definition node that: + * Next (as a child node) follows the index definition node that: *

    *
  • must be of type oak:queryIndexDefinition
  • *
  • must have the type property set to p2
  • @@ -46,10 +46,12 @@ import com.google.common.base.Charsets; *
*

*

- * Optionally you can specify the uniqueness constraint on a property index by - * setting the unique flag to true. + * Optionally you can specify + *

    + *
  • a uniqueness constraint on a property index by setting the unique flag to true
  • + *
  • that the property index only applies to a certain node type by setting the declaringNodeTypes property
  • + *
*

- * *

* Note: propertyNames can be a list of properties, and it is optional.in case it is missing, the node name will be used as a property name reference value *

@@ -66,6 +68,7 @@ import com.google.common.base.Charsets; * .setProperty("jcr:primaryType", "oak:queryIndexDefinition", Type.NAME) * .setProperty("type", "p2") * .setProperty("propertyNames", "jcr:uuid") + * .setProperty("declaringNodeTypes", "mix:referenceable") * .setProperty("unique", true) * .setProperty("reindex", true); * } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexDiff.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexDiff.java?rev=1439331&r1=1439330&r2=1439331&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexDiff.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexDiff.java Mon Jan 28 10:23:43 2013 @@ -22,14 +22,16 @@ import static org.apache.jackrabbit.oak. import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE; import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME; import static org.apache.jackrabbit.oak.plugins.index.p2.Property2Index.TYPE; +import static com.google.common.collect.Lists.newArrayList; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; + import org.apache.jackrabbit.oak.api.CommitFailedException; import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Type; @@ -54,6 +56,11 @@ import org.apache.jackrabbit.oak.spi.sta */ class Property2IndexDiff implements IndexHook { + protected static String propertyNames = "propertyNames"; + + protected static String declaringNodeTypes = "declaringNodeTypes"; + + private final IndexStoreStrategy store = new ContentMirrorStoreStrategy(); /** @@ -138,21 +145,45 @@ class Property2IndexDiff implements Inde */ private Iterable getIndexes(String name) { List indexes = updates.get(name); - if (indexes != null) { - return indexes; - } else { + if (indexes == null) { return ImmutableList.of(); } + List filtered = new ArrayList(); + for (Property2IndexUpdate pi : indexes) { + if (pi.getNodeTypeNames() == null + || pi.getNodeTypeNames().isEmpty()) { + filtered.add(pi); + continue; + } + PropertyState ps = node.getProperty(JCR_PRIMARYTYPE); + String type = ps != null && !ps.isArray() ? ps + .getValue(Type.STRING) : null; + if (type != null) { + for (String typeName : pi.getNodeTypeNames()) { + if (typeName.equals(type)) { + filtered.add(pi); + break; + } + } + } + } + return filtered; } private void update(NodeBuilder builder, String indexName) { - PropertyState ps = builder.getProperty("propertyNames"); + List typeNames = ImmutableList.of(); + PropertyState appliesTo = builder.getProperty(declaringNodeTypes); + if (appliesTo != null) { + typeNames = newArrayList(appliesTo.getValue(Type.STRINGS)); + } + PropertyState ps = builder.getProperty(propertyNames); + Iterable propertyNames = ps != null ? ps.getValue(Type.STRINGS) : ImmutableList.of(indexName); for (String pname : propertyNames) { List list = this.updates.get(pname); if (list == null) { - list = Lists.newArrayList(); + list = newArrayList(); this.updates.put(pname, list); } boolean exists = false; @@ -163,7 +194,7 @@ class Property2IndexDiff implements Inde } } if (!exists) { - list.add(new Property2IndexUpdate(getPath(), builder, store)); + list.add(new Property2IndexUpdate(getPath(), builder, store, typeNames)); } } } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexUpdate.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexUpdate.java?rev=1439331&r1=1439330&r2=1439331&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexUpdate.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexUpdate.java Mon Jan 28 10:23:43 2013 @@ -51,6 +51,13 @@ class Property2IndexUpdate { private final String path; /** + * The node types that this index applies to. If null or + * empty then the node type of the indexed node is ignored + * + */ + private final List nodeTypeNames; + + /** * The node where the index definition is stored. */ private final NodeBuilder node; @@ -69,18 +76,29 @@ class Property2IndexUpdate { */ private final Map> remove; - public Property2IndexUpdate(String path, NodeBuilder node, IndexStoreStrategy store) { + public Property2IndexUpdate(String path, NodeBuilder node, + IndexStoreStrategy store) { + this(path, node, store, null); + } + + public Property2IndexUpdate(String path, NodeBuilder node, + IndexStoreStrategy store, List nodeTypeNames) { this.path = path; this.node = node; this.store = store; this.insert = Maps.newHashMap(); this.remove = Maps.newHashMap(); + this.nodeTypeNames = nodeTypeNames; } String getPath() { return path; } + public List getNodeTypeNames() { + return nodeTypeNames; + } + /** * A property value was added at the given path. * Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java?rev=1439331&r1=1439330&r2=1439331&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java Mon Jan 28 10:23:43 2013 @@ -23,6 +23,7 @@ import static org.junit.Assert.fail; import java.util.Arrays; import java.util.Set; +import org.apache.jackrabbit.oak.api.CommitFailedException; import org.apache.jackrabbit.oak.api.Type; import org.apache.jackrabbit.oak.plugins.index.IndexHook; import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeState; @@ -130,8 +131,105 @@ public class Property2IndexTest { } catch (IllegalArgumentException e) { // expected: no index for "pqr" } + } + + @Test + public void testUnique() throws Exception { + + NodeState root = MemoryNodeState.EMPTY_NODE; + + // Add index definition + NodeBuilder builder = root.builder(); + builder.child("oak:index") + .child("fooIndex") + .setProperty("jcr:primaryType", "oak:queryIndexDefinition", + Type.NAME) + .setProperty("type", "p2") + .setProperty("unique", "true") + .setProperty("propertyNames", Arrays.asList("foo"), + Type.STRINGS); + + NodeState before = builder.getNodeState(); + builder = before.builder(); + builder.child("a").setProperty("foo", "abc"); + builder.child("b").setProperty("foo", Arrays.asList("abc", "def"), + Type.STRINGS); + NodeState after = builder.getNodeState(); + IndexHook p = new Property2IndexDiff(builder); + after.compareAgainstBaseState(before, p); + try { + p.apply(); + fail("Unique constraint should be respected"); + } catch (CommitFailedException e) { + // expected + } finally { + p.close(); + } } + @Test + public void testUniqueByTypeOK() throws Exception { + + NodeState root = MemoryNodeState.EMPTY_NODE; + + // Add index definition + NodeBuilder builder = root.builder(); + builder.child("oak:index").child("fooIndex") + .setProperty("jcr:primaryType", "oak:queryIndexDefinition", Type.NAME) + .setProperty("type", "p2") + .setProperty("unique", "true") + .setProperty("propertyNames", Arrays.asList("foo"), Type.STRINGS) + .setProperty(Property2IndexDiff.declaringNodeTypes, Arrays.asList("typeFoo"), Type.STRINGS); + NodeState before = builder.getNodeState(); + builder = before.builder(); + builder.child("a") + .setProperty("jcr:primaryType", "typeFoo", Type.NAME) + .setProperty("foo", "abc"); + builder.child("b") + .setProperty("jcr:primaryType", "typeBar", Type.NAME) + .setProperty("foo", "abc"); + NodeState after = builder.getNodeState(); + + IndexHook p = new Property2IndexDiff(builder); + after.compareAgainstBaseState(before, p); + p.apply(); + p.close(); + } + + @Test + public void testUniqueByTypeKO() throws Exception { + + NodeState root = MemoryNodeState.EMPTY_NODE; + + // Add index definition + NodeBuilder builder = root.builder(); + builder.child("oak:index").child("fooIndex") + .setProperty("jcr:primaryType", "oak:queryIndexDefinition", Type.NAME) + .setProperty("type", "p2") + .setProperty("unique", "true") + .setProperty("propertyNames", Arrays.asList("foo"), Type.STRINGS) + .setProperty(Property2IndexDiff.declaringNodeTypes, Arrays.asList("typeFoo"), Type.STRINGS); + NodeState before = builder.getNodeState(); + builder = before.builder(); + builder.child("a") + .setProperty("jcr:primaryType", "typeFoo", Type.NAME) + .setProperty("foo", "abc"); + builder.child("b") + .setProperty("jcr:primaryType", "typeFoo", Type.NAME) + .setProperty("foo", "abc"); + NodeState after = builder.getNodeState(); + + IndexHook p = new Property2IndexDiff(builder); + after.compareAgainstBaseState(before, p); + try { + p.apply(); + fail("Unique constraint should be respected"); + } catch (CommitFailedException e) { + // expected + } finally { + p.close(); + } + } }