You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by th...@apache.org on 2015/09/01 10:58:04 UTC
svn commit: r1700425 - in /jackrabbit/oak/trunk/oak-core/src:
main/java/org/apache/jackrabbit/oak/plugins/index/
main/java/org/apache/jackrabbit/oak/plugins/index/property/
test/java/org/apache/jackrabbit/oak/plugins/index/
test/java/org/apache/jackrab...
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);
Re: svn commit: r1700425 - in /jackrabbit/oak/trunk/oak-core/src:
main/java/org/apache/jackrabbit/oak/plugins/index/ main/java/org/apache/jackrabbit/oak/plugins/index/property/
test/java/org/apache/jackrabbit/oak/plugins/index/ test/java/org/apache/jackrab...
Posted by Amit Jain <am...@ieee.org>.
Get test failures in oak-lucene after this
[INFO] [ERROR]
C:\Data\Source\oak_svn\trunk\oak-lucene\src\main\java\org\apache\jackrabbit\oak\plugins\index\lucene\LuceneIndexEditor.java:[
39,71] error: cannot find symbol
[INFO] [ERROR] symbol: method doFiler(String)
[INFO] location: class PathFilter
[INFO]
C:\Data\Source\oak_svn\trunk\oak-lucene\src\main\java\org\apache\jackrabbit\oak\plugins\index\lucene\LuceneIndexEditor.java:[837,54]
rror: cannot find symbol
[INFO] [INFO] 2 errors
On Tue, Sep 1, 2015 at 2:28 PM, <th...@apache.org> wrote:
> 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);
>
>
>
>