Author: thomasm
Date: Tue Sep  1 08:58:03 2015
New Revision: 1700425

URL: http://svn.apache.org/r1700425
Log:
OAK-3263 Support including and excluding paths for PropertyIndex

Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PathFilter.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexEditor.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexEditor.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/PathFilterTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/Oak2077QueriesTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PathFilter.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PathFilter.java?rev=1700425&r1=1700424&r2=1700425&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PathFilter.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PathFilter.java
 Tue Sep  1 08:58:03 2015
@@ -54,14 +54,17 @@ public class PathFilter {
     public static final String PROP_EXCLUDED_PATHS = "excludedPaths";
 
     public enum Result {
+
         /**
          * Include the path for processing
          */
         INCLUDE,
+
         /**
          * Exclude the path and subtree for processing
          */
         EXCLUDE,
+
         /**
          * Do not process the path but just perform traversal to
          * child nodes. For IndexEditor it means that such nodes
@@ -72,7 +75,7 @@ public class PathFilter {
 
     private static final PathFilter ALL = new PathFilter(INCLUDE_ROOT, 
Collections.<String>emptyList()) {
         @Override
-        public Result doFiler(@Nonnull String path) {
+        public Result filter(@Nonnull String path) {
             return Result.INCLUDE;
         }
     };
@@ -81,21 +84,23 @@ public class PathFilter {
     private final String[] excludedPaths;
 
     /**
-     * Constructs the predicate based on given definition state. It looks
-     * for multi value property with names {@link 
PathFilter#PROP_INCLUDED_PATHS}
-     * and {@link PathFilter#PROP_EXCLUDED_PATHS}. Both the properties
-     * are optional.
-     *
-     * @param defn nodestate representing the configuration. Generally it 
would be the nodestate
-     *             representing the index definition
+     * Constructs the predicate based on given definition state. It looks for
+     * multi value property with names {@link PathFilter#PROP_INCLUDED_PATHS}
+     * and {@link PathFilter#PROP_EXCLUDED_PATHS}. Both the properties are
+     * optional.
+     * 
+     * @param defn nodestate representing the configuration. Generally it would
+     *            be the nodestate representing the index definition
      * @return predicate based on the passed definition state
      */
-    public static PathFilter from(@Nonnull NodeBuilder defn){
-        if (!defn.hasProperty(PROP_EXCLUDED_PATHS) && 
!defn.hasProperty(PROP_INCLUDED_PATHS)){
+    public static PathFilter from(@Nonnull NodeBuilder defn) {
+        if (!defn.hasProperty(PROP_EXCLUDED_PATHS) &&
+                !defn.hasProperty(PROP_INCLUDED_PATHS)) {
             return ALL;
         }
-        return new PathFilter(getStrings(defn, PROP_INCLUDED_PATHS, 
INCLUDE_ROOT),
-                getStrings(defn, PROP_EXCLUDED_PATHS, 
Collections.<String>emptyList()));
+        return new PathFilter(getStrings(defn, PROP_INCLUDED_PATHS,
+                INCLUDE_ROOT), getStrings(defn, PROP_EXCLUDED_PATHS,
+                Collections.<String> emptyList()));
     }
 
     /**
@@ -123,21 +128,21 @@ public class PathFilter {
      * @param path path to check
      * @return result indicating if the path needs to be included, excluded or 
just traversed
      */
-    public Result doFiler(@Nonnull String path) {
-        for (String excludedPath : excludedPaths){
-            if (excludedPath.equals(path) || isAncestor(excludedPath, path)){
+    public Result filter(@Nonnull String path) {
+        for (String excludedPath : excludedPaths) {
+            if (excludedPath.equals(path) || isAncestor(excludedPath, path)) {
                 return Result.EXCLUDE;
             }
         }
 
-        for (String includedPath : includedPaths){
-            if (includedPath.equals(path) || isAncestor(includedPath, path)){
+        for (String includedPath : includedPaths) {
+            if (includedPath.equals(path) || isAncestor(includedPath, path)) {
                 return Result.INCLUDE;
             }
         }
 
-        for (String includedPath : includedPaths){
-            if (includedPath.startsWith(path)){
+        for (String includedPath : includedPaths) {
+            if (isAncestor(path, includedPath)) {
                 return Result.TRAVERSE;
             }
         }
@@ -153,12 +158,35 @@ public class PathFilter {
                 '}';
     }
 
-    private static Iterable<String> getStrings(NodeBuilder builder, String 
name, Collection<String> defaultVal) {
-        PropertyState property = builder.getProperty(name);
+    private static Iterable<String> getStrings(NodeBuilder builder, String 
propertyName, 
+            Collection<String> defaultVal) {
+        PropertyState property = builder.getProperty(propertyName);
         if (property != null && property.getType() == Type.STRINGS) {
             return property.getValue(Type.STRINGS);
         } else {
             return defaultVal;
         }
     }
+
+    /**
+     * Check whether this node and all descendants are included in this filter.
+     * 
+     * @param path the path
+     * @return true if this and all descendants of this path are included in 
the filter
+     */
+    public boolean areAllDescendantsIncluded(String path) {
+        for (String excludedPath : excludedPaths) {
+            if (excludedPath.equals(path) || isAncestor(excludedPath, path) || 
+                    isAncestor(path, excludedPath)) {
+                return false;
+            }
+        }
+        for (String includedPath : includedPaths) {
+            if (includedPath.equals(path) || isAncestor(includedPath, path)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
 }

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexEditor.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexEditor.java?rev=1700425&r1=1700424&r2=1700425&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexEditor.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexEditor.java
 Tue Sep  1 08:58:03 2015
@@ -27,6 +27,7 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
 import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
+import org.apache.jackrabbit.oak.plugins.index.PathFilter;
 import 
org.apache.jackrabbit.oak.plugins.index.property.OrderedIndex.OrderDirection;
 import 
org.apache.jackrabbit.oak.plugins.index.property.strategy.IndexStoreStrategy;
 import 
org.apache.jackrabbit.oak.plugins.index.property.strategy.OrderedContentMirrorStoreStrategy;
@@ -101,8 +102,8 @@ public class OrderedPropertyIndexEditor
         swl = new StopwatchLogger(OrderedPropertyIndexEditor.class);
     }
 
-    OrderedPropertyIndexEditor(OrderedPropertyIndexEditor parent, String name) 
{
-        super(parent, name);
+    OrderedPropertyIndexEditor(OrderedPropertyIndexEditor parent, String name, 
PathFilter.Result pathFilterResult) {
+        super(parent, name, pathFilterResult);
         this.propertyNames = parent.getPropertyNames();
         this.direction = parent.getDirection();
         this.swl = parent.swl;
@@ -133,8 +134,8 @@ public class OrderedPropertyIndexEditor
 
     @Override
     PropertyIndexEditor getChildIndexEditor(@Nonnull PropertyIndexEditor 
parent, 
-                                            @Nonnull String name) {
-        return new OrderedPropertyIndexEditor(this, name);
+                                            @Nonnull String name, 
PathFilter.Result pathFilterResult) {
+        return new OrderedPropertyIndexEditor(this, name, pathFilterResult);
     }
 
     /**

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexEditor.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexEditor.java?rev=1700425&r1=1700424&r2=1700425&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexEditor.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexEditor.java
 Tue Sep  1 08:58:03 2015
@@ -40,6 +40,7 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
 import org.apache.jackrabbit.oak.plugins.index.IndexEditor;
 import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
+import org.apache.jackrabbit.oak.plugins.index.PathFilter;
 import 
org.apache.jackrabbit.oak.plugins.index.property.strategy.ContentMirrorStoreStrategy;
 import 
org.apache.jackrabbit.oak.plugins.index.property.strategy.IndexStoreStrategy;
 import 
org.apache.jackrabbit.oak.plugins.index.property.strategy.UniqueEntryStoreStrategy;
@@ -110,6 +111,10 @@ class PropertyIndexEditor implements Ind
 
     private final IndexUpdateCallback updateCallback;
 
+    private final PathFilter pathFilter;
+
+    private final PathFilter.Result pathFilterResult;
+
     public PropertyIndexEditor(NodeBuilder definition, NodeState root,
             IndexUpdateCallback updateCallback) {
         this.parent = null;
@@ -117,6 +122,8 @@ class PropertyIndexEditor implements Ind
         this.path = "/";
         this.definition = definition;
         this.root = root;
+        pathFilter = PathFilter.from(definition);
+        pathFilterResult = getPathFilterResult();
 
         //initPropertyNames(definition);
 
@@ -147,7 +154,7 @@ class PropertyIndexEditor implements Ind
         this.updateCallback = updateCallback;
     }
     
-    PropertyIndexEditor(PropertyIndexEditor parent, String name) {
+    PropertyIndexEditor(PropertyIndexEditor parent, String name, 
PathFilter.Result pathFilterResult) {
         this.parent = parent;
         this.name = name;
         this.path = null;
@@ -157,6 +164,8 @@ class PropertyIndexEditor implements Ind
         this.typePredicate = parent.typePredicate;
         this.keysToCheckForUniqueness = parent.keysToCheckForUniqueness;
         this.updateCallback = parent.updateCallback;
+        this.pathFilter = parent.pathFilter;
+        this.pathFilterResult = pathFilterResult;
     }
     
     /**
@@ -228,6 +237,16 @@ class PropertyIndexEditor implements Ind
     @Override
     public void leave(NodeState before, NodeState after)
             throws CommitFailedException {
+
+        if (pathFilterResult == PathFilter.Result.INCLUDE) {
+            applyTypeRestrictions(before, after);
+            updateIndex(before, after);
+        }
+        checkUniquenessConstraints();
+        
+    }
+    
+    private void applyTypeRestrictions(NodeState before, NodeState after) {
         // apply the type restrictions
         if (typePredicate != null) {
             if (typeChanged) {
@@ -245,7 +264,9 @@ class PropertyIndexEditor implements Ind
                 afterKeys = null;
             }
         }
-
+    }
+    
+    private void updateIndex(NodeState before, NodeState after) throws 
CommitFailedException {
         // if any changes were detected, update the index accordingly
         if (beforeKeys != null || afterKeys != null) {
             // first make sure that both the before and after sets are non-null
@@ -276,13 +297,17 @@ class PropertyIndexEditor implements Ind
             }
         }
 
+        checkUniquenessConstraints();
+    }
+
+    private void checkUniquenessConstraints() throws CommitFailedException {
         if (parent == null) {
             // make sure that the index node exist, even with no content
             definition.child(INDEX_CONTENT_NODE_NAME);
 
             boolean uniqueIndex = keysToCheckForUniqueness != null;
             // check uniqueness constraints when leaving the root
-            if (uniqueIndex && 
+            if (uniqueIndex &&
                     !keysToCheckForUniqueness.isEmpty()) {
                 NodeState indexMeta = definition.getNodeState();
                 String failed = getFirstDuplicate(
@@ -292,12 +317,12 @@ class PropertyIndexEditor implements Ind
                             "Uniqueness constraint violated at path [%s] for 
one of the "
                                     + "property in %s having value %s",
                             getPath(), propertyNames, failed);
-                    throw new CommitFailedException(CONSTRAINT, 30, msg);      
          
+                    throw new CommitFailedException(CONSTRAINT, 30, msg);
                 }
             }
         }
     }
-    
+
     /**
      * From a set of keys, get those that already exist in the index.
      * 
@@ -378,24 +403,43 @@ class PropertyIndexEditor implements Ind
      * @param name the name of the child node
      * @return an instance of the PropertyIndexEditor
      */
-    PropertyIndexEditor getChildIndexEditor(@Nonnull PropertyIndexEditor 
parent, @Nonnull String name) {
-       return new PropertyIndexEditor(parent, name);
+    PropertyIndexEditor getChildIndexEditor(@Nonnull PropertyIndexEditor 
parent, @Nonnull String name, PathFilter.Result filterResult) {
+       return new PropertyIndexEditor(parent, name, filterResult);
     }
     
     @Override
     public Editor childNodeAdded(String name, NodeState after) {
-        return getChildIndexEditor(this, name);
+        PathFilter.Result filterResult = getPathFilterResult(name);
+        if (filterResult == PathFilter.Result.EXCLUDE) {
+            return null;
+        }
+        return getChildIndexEditor(this, name, filterResult);
     }
 
     @Override
     public Editor childNodeChanged(
             String name, NodeState before, NodeState after) {
-        return getChildIndexEditor(this, name);
+        PathFilter.Result filterResult = getPathFilterResult(name);
+        if (filterResult == PathFilter.Result.EXCLUDE) {
+            return null;
+        }
+        return getChildIndexEditor(this, name, filterResult);
     }
 
     @Override
     public Editor childNodeDeleted(String name, NodeState before) {
-        return getChildIndexEditor(this, name);
+        PathFilter.Result filterResult = getPathFilterResult(name);
+        if (filterResult == PathFilter.Result.EXCLUDE) {
+            return null;
+        }
+        return getChildIndexEditor(this, name, filterResult);
     }
 
+    private PathFilter.Result getPathFilterResult() {
+        return pathFilter.filter(getPath());
+    }
+
+    private PathFilter.Result getPathFilterResult(String childNodeName) {
+        return pathFilter.filter(concat(getPath(), childNodeName));
+    }
 }
\ No newline at end of file

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java?rev=1700425&r1=1700424&r2=1700425&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java
 Tue Sep  1 08:58:03 2015
@@ -18,7 +18,6 @@ package org.apache.jackrabbit.oak.plugin
 
 import static com.google.common.base.Predicates.in;
 import static com.google.common.collect.Iterables.any;
-import static com.google.common.collect.Iterables.isEmpty;
 import static com.google.common.collect.Sets.newHashSet;
 import static com.google.common.collect.Sets.newLinkedHashSet;
 import static java.util.Collections.emptySet;
@@ -31,6 +30,8 @@ import java.util.Set;
 
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.index.PathFilter;
+import org.apache.jackrabbit.oak.plugins.index.PathFilter.Result;
 import 
org.apache.jackrabbit.oak.plugins.index.property.strategy.ContentMirrorStoreStrategy;
 import 
org.apache.jackrabbit.oak.plugins.index.property.strategy.IndexStoreStrategy;
 import 
org.apache.jackrabbit.oak.plugins.index.property.strategy.UniqueEntryStoreStrategy;
@@ -94,11 +95,14 @@ public class PropertyIndexPlan {
 
     private final int depth;
 
+    private final PathFilter pathFilter;
+
     PropertyIndexPlan(String name, NodeState root, NodeState definition, 
Filter filter) {
         this.name = name;
         this.root = root;
         this.definition = definition;
         this.properties = newHashSet(definition.getNames(PROPERTY_NAMES));
+        pathFilter = PathFilter.from(definition.builder());
 
         if (definition.getBoolean(UNIQUE_PROPERTY_NAME)) {
             this.strategy = UNIQUE;
@@ -118,7 +122,8 @@ public class PropertyIndexPlan {
         Set<String> bestValues = emptySet();
         int bestDepth = 1;
 
-        if (matchesNodeTypes) {
+        if (matchesNodeTypes && 
+                pathFilter.areAllDescendantsIncluded(filter.getPath())) {
             for (String property : properties) {
                 PropertyRestriction restriction =
                         filter.getPropertyRestriction(property);

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/PathFilterTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/PathFilterTest.java?rev=1700425&r1=1700424&r2=1700425&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/PathFilterTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/PathFilterTest.java
 Tue Sep  1 08:58:03 2015
@@ -36,81 +36,84 @@ import static org.junit.Assert.fail;
 public class PathFilterTest {
 
     @Test
-    public void exclude() throws Exception{
+    public void exclude() throws Exception {
         PathFilter p = new PathFilter(of("/"), of("/etc"));
-        assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/"));
-        assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/a"));
-        assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/etc"));
-        assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/etc/workflow"));
+        assertEquals(PathFilter.Result.INCLUDE, p.filter("/"));
+        assertEquals(PathFilter.Result.INCLUDE, p.filter("/a"));
+        assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etc"));
+        assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etc/workflow"));
     }
 
     @Test
-    public void include() throws Exception{
+    public void include() throws Exception {
         PathFilter p = new PathFilter(of("/content", "/etc"), 
of("/etc/workflow/instance"));
-        assertEquals(PathFilter.Result.TRAVERSE, p.doFiler("/"));
-        assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/var"));
-        assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/content"));
-        assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/content/example"));
-        assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/etc"));
-        assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/etc/workflow"));
-        assertEquals(PathFilter.Result.EXCLUDE, 
p.doFiler("/etc/workflow/instance"));
-        assertEquals(PathFilter.Result.EXCLUDE, 
p.doFiler("/etc/workflow/instance/1"));
+        assertEquals(PathFilter.Result.TRAVERSE, p.filter("/"));
+        assertEquals(PathFilter.Result.EXCLUDE, p.filter("/var"));
+        assertEquals(PathFilter.Result.INCLUDE, p.filter("/content"));
+        assertEquals(PathFilter.Result.INCLUDE, p.filter("/content/example"));
+        assertEquals(PathFilter.Result.INCLUDE, p.filter("/etc"));
+        assertEquals(PathFilter.Result.INCLUDE, p.filter("/etc/workflow"));
+        assertEquals(PathFilter.Result.EXCLUDE, 
p.filter("/etc/workflow/instance"));
+        assertEquals(PathFilter.Result.EXCLUDE, 
p.filter("/etc/workflow/instance/1"));
+        assertEquals(PathFilter.Result.EXCLUDE, p.filter("/x"));
+        assertEquals(PathFilter.Result.EXCLUDE, p.filter("/e"));
+        assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etcx"));
     }
 
     @Test
-    public void emptyConfig() throws Exception{
+    public void emptyConfig() throws Exception {
         NodeBuilder root = EMPTY_NODE.builder();
         PathFilter p = PathFilter.from(root);
-        assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/"));
-        assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/a"));
+        assertEquals(PathFilter.Result.INCLUDE, p.filter("/"));
+        assertEquals(PathFilter.Result.INCLUDE, p.filter("/a"));
     }
 
     @Test
-    public void config() throws Exception{
+    public void config() throws Exception {
         NodeBuilder root = EMPTY_NODE.builder();
         root.setProperty(createProperty(PROP_INCLUDED_PATHS, of("/etc"), 
Type.STRINGS));
         root.setProperty(createProperty(PROP_EXCLUDED_PATHS, 
of("/etc/workflow"), Type.STRINGS));
         PathFilter p = PathFilter.from(root);
-        assertEquals(PathFilter.Result.TRAVERSE, p.doFiler("/"));
-        assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/etc"));
-        assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/etc/a"));
-        assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/etc/workflow"));
-        assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/etc/workflow/1"));
+        assertEquals(PathFilter.Result.TRAVERSE, p.filter("/"));
+        assertEquals(PathFilter.Result.INCLUDE, p.filter("/etc"));
+        assertEquals(PathFilter.Result.INCLUDE, p.filter("/etc/a"));
+        assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etc/workflow"));
+        assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etc/workflow/1"));
     }
 
     @Test
-    public void configOnlyExclude() throws Exception{
+    public void configOnlyExclude() throws Exception {
         NodeBuilder root = EMPTY_NODE.builder();
         root.setProperty(createProperty(PROP_EXCLUDED_PATHS, 
of("/etc/workflow"), Type.STRINGS));
         PathFilter p = PathFilter.from(root);
-        assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/"));
-        assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/etc"));
-        assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/etc/a"));
-        assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/etc/workflow"));
-        assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/etc/workflow/1"));
+        assertEquals(PathFilter.Result.INCLUDE, p.filter("/"));
+        assertEquals(PathFilter.Result.INCLUDE, p.filter("/etc"));
+        assertEquals(PathFilter.Result.INCLUDE, p.filter("/etc/a"));
+        assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etc/workflow"));
+        assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etc/workflow/1"));
     }
 
     @Test
-    public void invalid() throws Exception{
+    public void invalid() throws Exception {
         try {
             new PathFilter(Collections.<String>emptyList(), of("/etc"));
             fail();
-        } catch (IllegalStateException ignore){
-
+        } catch (IllegalStateException ignore) {
+            // expected
         }
 
         try {
             new PathFilter(of("/etc/workflow"), of("/etc"));
             fail();
-        } catch (IllegalStateException ignore){
-
+        } catch (IllegalStateException ignore) {
+            // expected
         }
 
         try {
             new PathFilter(Collections.<String>emptyList(), 
Collections.<String>emptyList());
             fail();
-        } catch (IllegalStateException ignore){
-
+        } catch (IllegalStateException ignore) {
+            // expected
         }
     }
 }

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/Oak2077QueriesTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/Oak2077QueriesTest.java?rev=1700425&r1=1700424&r2=1700425&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/Oak2077QueriesTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/Oak2077QueriesTest.java
 Tue Sep  1 08:58:03 2015
@@ -49,6 +49,7 @@ import org.apache.jackrabbit.oak.api.Res
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
 import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
+import org.apache.jackrabbit.oak.plugins.index.PathFilter;
 import 
org.apache.jackrabbit.oak.plugins.index.property.OrderedIndex.OrderDirection;
 import 
org.apache.jackrabbit.oak.plugins.index.property.strategy.IndexStoreStrategy;
 import 
org.apache.jackrabbit.oak.plugins.index.property.strategy.OrderedContentMirrorStoreStrategy;
@@ -169,8 +170,8 @@ public class Oak2077QueriesTest extends
             this.rnd = rnd;
         }
 
-        public SeededPropertyIndexEditor(SeededPropertyIndexEditor parent, 
String name) {
-            super(parent, name);
+        public SeededPropertyIndexEditor(SeededPropertyIndexEditor parent, 
String name, PathFilter.Result pathFilterResult) {
+            super(parent, name, pathFilterResult);
             this.rnd = parent.rnd;
         }
 
@@ -185,8 +186,8 @@ public class Oak2077QueriesTest extends
         }
 
         @Override
-        PropertyIndexEditor getChildIndexEditor(PropertyIndexEditor parent, 
String name) {
-            return new SeededPropertyIndexEditor(this, name);
+        PropertyIndexEditor getChildIndexEditor(PropertyIndexEditor parent, 
String name, PathFilter.Result pathFilterResult) {
+            return new SeededPropertyIndexEditor(this, name, pathFilterResult);
         }
     }
     
@@ -314,7 +315,7 @@ public class Oak2077QueriesTest extends
     /**
      * truncate the {@link AbstractQueryTest#TEST_INDEX_NAME} index at the 4th 
element of the
      * provided lane returning the previous value
-     * 
+     *
      * @param lane the desired lane. Must be 0 <= {@code lane} < {@link 
OrderedIndex#LANES}
      * @param inexistent the derired value to be injected
      * @return the value before the change

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java?rev=1700425&r1=1700424&r2=1700425&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java
 Tue Sep  1 08:58:03 2015
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.property;
 
+import static com.google.common.collect.ImmutableSet.of;
+import static java.util.Arrays.asList;
 import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
 import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
 import static org.apache.jackrabbit.JcrConstants.NT_BASE;
@@ -23,14 +25,19 @@ import static org.apache.jackrabbit.JcrC
 import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
 import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
 import static 
org.apache.jackrabbit.oak.plugins.index.IndexUtils.createIndexDefinition;
+import static 
org.apache.jackrabbit.oak.plugins.index.PathFilter.PROP_EXCLUDED_PATHS;
+import static 
org.apache.jackrabbit.oak.plugins.index.PathFilter.PROP_INCLUDED_PATHS;
 import static 
org.apache.jackrabbit.oak.plugins.index.counter.NodeCounterEditor.COUNT_PROPERTY_NAME;
 import static 
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static 
org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
 import static 
org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
 import static 
org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent.INITIAL_CONTENT;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.matchers.JUnitMatchers.containsString;
 
 import java.util.Arrays;
 import java.util.Set;
@@ -43,11 +50,13 @@ import ch.qos.logback.core.read.ListAppe
 import ch.qos.logback.core.spi.FilterReply;
 import com.google.common.collect.Iterables;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.index.IndexUpdateProvider;
 import 
org.apache.jackrabbit.oak.plugins.index.property.strategy.ContentMirrorStoreStrategy;
 import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
 import org.apache.jackrabbit.oak.query.QueryEngineSettings;
+import org.apache.jackrabbit.oak.query.ast.Operator;
 import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.query.index.TraversingIndex;
@@ -565,6 +574,165 @@ public class PropertyIndexTest {
         deregisterAppender(appender);
     }
 
+    @Test
+    public void testPathInclude() throws Exception {
+        NodeState root = INITIAL_CONTENT;
+
+        // Add index definition
+        NodeBuilder builder = root.builder();
+        NodeBuilder index = 
createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME), "foo",
+                true, false, ImmutableSet.of("foo"), null);
+        index.setProperty(createProperty(PROP_INCLUDED_PATHS, of("/test/a"), 
Type.STRINGS));
+        NodeState before = builder.getNodeState();
+
+        // Add some content and process it through the property index hook
+        builder.child("test").child("a").setProperty("foo", "abc");
+        builder.child("test").child("b").setProperty("foo", "abc");
+        NodeState after = builder.getNodeState();
+
+        NodeState indexed = HOOK.processCommit(before, after, 
CommitInfo.EMPTY);
+
+        FilterImpl f = createFilter(indexed, NT_BASE);
+
+        // Query the index
+        PropertyIndexLookup lookup = new PropertyIndexLookup(indexed);
+        assertEquals(ImmutableSet.of("test/a"), find(lookup, "foo", "abc", f));
+    }
+
+    @Test
+    public void testPathExclude() throws Exception {
+        NodeState root = INITIAL_CONTENT;
+
+        // Add index definition
+        NodeBuilder builder = root.builder();
+        NodeBuilder index = 
createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME), "foo",
+                true, false, ImmutableSet.of("foo"), null);
+        index.setProperty(createProperty(PROP_EXCLUDED_PATHS, of("/test/a"), 
Type.STRINGS));
+        NodeState before = builder.getNodeState();
+
+        // Add some content and process it through the property index hook
+        builder.child("test").child("a").setProperty("foo", "abc");
+        builder.child("test").child("b").setProperty("foo", "abc");
+        NodeState after = builder.getNodeState();
+
+        NodeState indexed = HOOK.processCommit(before, after, 
CommitInfo.EMPTY);
+
+        FilterImpl f = createFilter(indexed, NT_BASE);
+        f.restrictProperty("foo", Operator.EQUAL, 
PropertyValues.newString("abc"));
+
+        // Query the index
+        PropertyIndexLookup lookup = new PropertyIndexLookup(indexed);
+        assertEquals(ImmutableSet.of("test/b"), find(lookup, "foo", "abc", f));
+
+        //no path restriction, opt out
+        PropertyIndexPlan plan = new PropertyIndexPlan("plan", root, 
index.getNodeState(), f);
+        assertTrue(Double.POSITIVE_INFINITY == plan.getCost());
+
+        //path restriction is not an ancestor of excluded path, index may be 
used
+        f.setPath("/test2");
+        plan = new PropertyIndexPlan("plan", root, index.getNodeState(), f);
+        assertTrue(Double.POSITIVE_INFINITY != plan.getCost());
+
+        //path restriction is an ancestor of excluded path, opt out
+        f.setPath("/test");
+        plan = new PropertyIndexPlan("plan", root, index.getNodeState(), f);
+        assertTrue(Double.POSITIVE_INFINITY == plan.getCost());
+    }
+
+    @Test
+    public void testPathIncludeExclude() throws Exception {
+        NodeState root = INITIAL_CONTENT;
+
+        // Add index definition
+        NodeBuilder builder = root.builder();
+        NodeBuilder index = 
createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME), "foo",
+                true, false, ImmutableSet.of("foo"), null);
+        index.setProperty(createProperty(PROP_INCLUDED_PATHS, of("/test/a"), 
Type.STRINGS));
+        index.setProperty(createProperty(PROP_EXCLUDED_PATHS, of("/test/a/b"), 
Type.STRINGS));
+        NodeState before = builder.getNodeState();
+
+        // Add some content and process it through the property index hook
+        builder.child("test").child("a").setProperty("foo", "abc");
+        builder.child("test").child("a").child("b").setProperty("foo", "abc");
+        NodeState after = builder.getNodeState();
+
+        NodeState indexed = HOOK.processCommit(before, after, 
CommitInfo.EMPTY);
+
+        FilterImpl f = createFilter(indexed, NT_BASE);
+        f.restrictProperty("foo", Operator.EQUAL, 
PropertyValues.newString("abc"));
+
+        // Query the index
+        PropertyIndexLookup lookup = new PropertyIndexLookup(indexed);
+        assertEquals(ImmutableSet.of("test/a"), find(lookup, "foo", "abc", f));
+
+        //no path restriction, opt out
+        PropertyIndexPlan plan = new PropertyIndexPlan("plan", root, 
index.getNodeState(), f);
+        assertTrue(Double.POSITIVE_INFINITY == plan.getCost());
+
+        //path restriction is not an ancestor of excluded path, index may be 
used
+        f.setPath("/test/a/x");
+        plan = new PropertyIndexPlan("plan", root, index.getNodeState(), f);
+        assertTrue(Double.POSITIVE_INFINITY != plan.getCost());
+
+        //path restriction is an ancestor of excluded path but no included 
path, opt out
+        f.setPath("/test/a/b");
+        plan = new PropertyIndexPlan("plan", root, index.getNodeState(), f);
+        assertTrue(Double.POSITIVE_INFINITY == plan.getCost());
+
+        //path restriction is an ancestor of excluded path, opt out
+        f.setPath("/test/a");
+        plan = new PropertyIndexPlan("plan", root, index.getNodeState(), f);
+        assertTrue(Double.POSITIVE_INFINITY == plan.getCost());
+}
+
+    @Test
+    public void testPathExcludeInclude() throws Exception{
+        NodeState root = INITIAL_CONTENT;
+
+        // Add index definition
+        NodeBuilder builder = root.builder();
+        NodeBuilder index = 
createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME), "foo",
+                true, false, ImmutableSet.of("foo"), null);
+        index.setProperty(createProperty(PROP_INCLUDED_PATHS, of("/test/a/b"), 
Type.STRINGS));
+        index.setProperty(createProperty(PROP_EXCLUDED_PATHS, of("/test/a"), 
Type.STRINGS));
+        NodeState before = builder.getNodeState();
+
+        // Add some content and process it through the property index hook
+        builder.child("test").child("a").setProperty("foo", "abc");
+        builder.child("test").child("a").child("b").setProperty("foo", "abc");
+        NodeState after = builder.getNodeState();
+
+        try {
+            HOOK.processCommit(before, after, CommitInfo.EMPTY);
+            assertTrue(false);
+        } catch (IllegalStateException expected) {}
+    }
+
+    @Test
+    public void testPathMismatch() throws Exception {
+        NodeState root = INITIAL_CONTENT;
+
+        // Add index definition
+        NodeBuilder builder = root.builder();
+        NodeBuilder index = 
createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME), "foo",
+                true, false, ImmutableSet.of("foo"), null);
+        index.setProperty(createProperty(PROP_INCLUDED_PATHS, of("/test/a"), 
Type.STRINGS));
+        index.setProperty(createProperty(PROP_EXCLUDED_PATHS, of("/test/a/b"), 
Type.STRINGS));
+        NodeState before = builder.getNodeState();
+
+        // Add some content and process it through the property index hook
+        builder.child("test").child("a").setProperty("foo", "abc");
+        builder.child("test").child("a").child("b").setProperty("foo", "abc");
+        NodeState after = builder.getNodeState();
+
+        NodeState indexed = HOOK.processCommit(before, after, 
CommitInfo.EMPTY);
+
+        FilterImpl f = createFilter(indexed, NT_BASE);
+        f.restrictPath("/test2", Filter.PathRestriction.ALL_CHILDREN);
+        PropertyIndexPlan plan = new PropertyIndexPlan("plan", root, 
index.getNodeState(), f);
+        assertTrue(Double.POSITIVE_INFINITY == plan.getCost());
+    }
+
     private int getResultSize(NodeState indexed, String name, String value){
         FilterImpl f = createFilter(indexed, NT_BASE);
 


Reply via email to