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;
* <p>
* To define a property index on a subtree you have to add an <code>oak:index</code>
node.
*
- * Under it follows the index definition node that:
+ * Next (as a child node) follows the index definition node that:
* <ul>
* <li>must be of type <code>oak:queryIndexDefinition</code></li>
* <li>must have the <code>type</code> property set to <b><code>p2</code></b></li>
@@ -46,10 +46,12 @@ import com.google.common.base.Charsets;
* </ul>
* </p>
* <p>
- * Optionally you can specify the uniqueness constraint on a property index by
- * setting the <code>unique</code> flag to <code>true</code>.
+ * Optionally you can specify
+ * <ul>
+ * <li> a uniqueness constraint on a property index by setting the <code>unique</code>
flag to <code>true</code></li>
+ * <li> that the property index only applies to a certain node type by setting the
<code>declaringNodeTypes</code> property</li>
+ * </ul>
* </p>
- *
* <p>
* Note: <code>propertyNames</code> 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
* </p>
@@ -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<Property2IndexUpdate> getIndexes(String name) {
List<Property2IndexUpdate> indexes = updates.get(name);
- if (indexes != null) {
- return indexes;
- } else {
+ if (indexes == null) {
return ImmutableList.of();
}
+ List<Property2IndexUpdate> filtered = new ArrayList<Property2IndexUpdate>();
+ 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<String> typeNames = ImmutableList.of();
+ PropertyState appliesTo = builder.getProperty(declaringNodeTypes);
+ if (appliesTo != null) {
+ typeNames = newArrayList(appliesTo.getValue(Type.STRINGS));
+ }
+ PropertyState ps = builder.getProperty(propertyNames);
+
Iterable<String> propertyNames = ps != null ? ps.getValue(Type.STRINGS)
: ImmutableList.of(indexName);
for (String pname : propertyNames) {
List<Property2IndexUpdate> 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 <code>null</code> or
+ * <code>empty</code> then the node type of the indexed node is ignored
+ *
+ */
+ private final List<String> nodeTypeNames;
+
+ /**
* The node where the index definition is stored.
*/
private final NodeBuilder node;
@@ -69,18 +76,29 @@ class Property2IndexUpdate {
*/
private final Map<String, Set<String>> 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<String> 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<String> 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();
+ }
+ }
}
|