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 st...@apache.org on 2017/02/13 16:24:41 UTC

svn commit: r1782801 - in /jackrabbit/oak/branches/1.6/oak-jcr/src: main/java/org/apache/jackrabbit/oak/jcr/observation/ main/java/org/apache/jackrabbit/oak/jcr/observation/filter/ test/java/org/apache/jackrabbit/oak/jcr/observation/

Author: stefanegli
Date: Mon Feb 13 16:24:41 2017
New Revision: 1782801

URL: http://svn.apache.org/viewvc?rev=1782801&view=rev
Log:
OAK-5619 : merged from trunk : fixing withIncludeAncestorsRemove which reported /unrelated parent NODE_REMOVEs

Modified:
    jackrabbit/oak/branches/1.6/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/OakEventFilterImpl.java
    jackrabbit/oak/branches/1.6/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/filter/OakEventFilter.java
    jackrabbit/oak/branches/1.6/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/OakEventFilterImplTest.java
    jackrabbit/oak/branches/1.6/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/ObservationTest.java

Modified: jackrabbit/oak/branches/1.6/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/OakEventFilterImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.6/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/OakEventFilterImpl.java?rev=1782801&r1=1782800&r2=1782801&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.6/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/OakEventFilterImpl.java (original)
+++ jackrabbit/oak/branches/1.6/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/OakEventFilterImpl.java Mon Feb 13 16:24:41 2017
@@ -384,35 +384,47 @@ public class OakEventFilterImpl extends
         return includeAncestorRemove;
     }
 
+    /**
+     * This helper method goes through the provided globPath and adds
+     * each parent (ancestor)'s path to the ancestorPaths set.
+     * <p>
+     * OAK-5619 : this used to add "${parent}/*" type ancestor paths, however
+     * that was wrong: we must only take the actual "${parent}"s to which we want
+     * to listen to. Also, the glob case looks slightly different than originally
+     * implemented:
+     * <ul>
+     *  <li>* : we treat this as a normal name, ie as a normal parent and continue normally</li>
+     *  <li>**: when a ** is hit, the loop through the elements can be stopped,
+     *  as ** includes all children already, so no further paths are needed.</li>
+     * </ul>
+     * @param ancestorPaths the set to which the ancestors of globPath will
+     * be added to
+     * @param globPath the input path that may contain globs
+     */
     static void addAncestorPaths(Set<String> ancestorPaths, String globPath) {
         if (globPath == null || !globPath.contains("/")) {
             return;
         }
-        // from /a/b/c         => add /*, /a/* and /a/b/*
-        // from /a/b/**        => add /*, /a/*
-        // from /a             => add /*, nothing
+        // from /a/b/c         => add /a, /a/b, /a/b/c
+        // from /a/b/**        => add /a, /a/b, /a/b/**
+        // from /a             => add /a
         // from /              => add nothing
-        // from /a/b/**/*.html => add /*, /a/*
-        // from /a/b/*/*.html  => add /*, /a/*
+        // from /a/b/**/*.html => add /a, /a/b, /a/b/**
+        // from /a/b/*/*.html  => add /a, /a/b, /a/b/*, /a/b/*/*.html
+        // from /a/b/*/d       => add /a, /a/b, /a/b/*, /a/b/*/d
+        // from /a/b/*/d/e     => add /a, /a/b, /a/b/*, /a/b/*/d, /a/b/*/d/e
 
         Iterator<String> it = PathUtils.elements(globPath).iterator();
         StringBuffer sb = new StringBuffer();
-        if (it.hasNext()) {
-            ancestorPaths.add("/*");
-        }
         while(it.hasNext()) {
             String element = it.next();
-            if (element.contains("*")) {
-                if (ancestorPaths.size() > 0) {
-                    ancestorPaths.remove(ancestorPaths.size()-1);
-                }
-                break;
-            } else if (!it.hasNext()) {
-                break;
-            }
             sb.append("/");
             sb.append(element);
-            ancestorPaths.add(sb.toString() + "/*");
+            ancestorPaths.add(sb.toString());
+            if (element.equals("**")) {
+                // then we can stop as ** contains everything already
+                break;
+            }
         }
     }
 

Modified: jackrabbit/oak/branches/1.6/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/filter/OakEventFilter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.6/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/filter/OakEventFilter.java?rev=1782801&r1=1782800&r2=1782801&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.6/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/filter/OakEventFilter.java (original)
+++ jackrabbit/oak/branches/1.6/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/filter/OakEventFilter.java Mon Feb 13 16:24:41 2017
@@ -61,7 +61,14 @@ public abstract class OakEventFilter ext
      * <li>include path /a/b/c/d results in additional !deep NODE_REMOVED
      * filters on /a/b/c, on /a/b and on /a</li>
      * <li>include path /a/b/** results in additional !deep NODE_REMOVED
-     * filter on /a</li>
+     * filter on /a, /a/b and /a/b/**</li>
+     * <li>include path /a/b/**{@code /}*.jsp results in additional 
+     * deep NODE_REMOVED filter on /a, /a/b and /a/b/** <br/>
+     * Note that this and the above result in the same additional
+     * include paths since all this includeAncestorsRemove flag 
+     * does is include potential ancestors, it doesn't guarantee 
+     * that there are children matching the given paths (eg it doesn't
+     * traverse down)</li>
      * <li>additionally for paths with globs (eg /a/b/**{@code /}*.jsp)
      * it adds a deep NODE_REMOVED filter explicitly for that path
      * using the same method as withIncludeSubtreeOnRemove does, but only

Modified: jackrabbit/oak/branches/1.6/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/OakEventFilterImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.6/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/OakEventFilterImplTest.java?rev=1782801&r1=1782800&r2=1782801&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.6/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/OakEventFilterImplTest.java (original)
+++ jackrabbit/oak/branches/1.6/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/OakEventFilterImplTest.java Mon Feb 13 16:24:41 2017
@@ -33,17 +33,20 @@ public class OakEventFilterImplTest {
         assertMatches(new String[] {}, "/");
         
         assertMatches(new String[] {"/*"}, "/*");
-        assertMatches(new String[] {"/*"}, "/**");
-        assertMatches(new String[] {"/*"}, "/a");
-        assertMatches(new String[] {"/*", "/a/*"}, "/a/b");
-        assertMatches(new String[] {"/*", "/a/*"}, "/a/*");
-        assertMatches(new String[] {"/*", "/a/*"}, "/a/**");
-        assertMatches(new String[] {"/*", "/a/*", "/a/b/*"}, "/a/b/c");
-        assertMatches(new String[] {"/*", "/a/*", "/a/b/*"}, "/a/b/*");
-        assertMatches(new String[] {"/*", "/a/*", "/a/b/*"}, "/a/b/**");
-        assertMatches(new String[] {"/*", "/a/*", "/a/b/*", "/a/b/c/*"}, "/a/b/c/d");
-        assertMatches(new String[] {"/*", "/a/*", "/a/b/*", "/a/b/c/*"}, "/a/b/c/*");
-        assertMatches(new String[] {"/*", "/a/*", "/a/b/*", "/a/b/c/*"}, "/a/b/c/**");
+        assertMatches(new String[] {"/**"}, "/**");
+        assertMatches(new String[] {"/a"}, "/a");
+        assertMatches(new String[] {"/a", "/a/b"}, "/a/b");
+        assertMatches(new String[] {"/a", "/a/*"}, "/a/*");
+        assertMatches(new String[] {"/a", "/a/**"}, "/a/**");
+        assertMatches(new String[] {"/a", "/a/b", "/a/b/c"}, "/a/b/c");
+        assertMatches(new String[] {"/a", "/a/b", "/a/b/*"}, "/a/b/*");
+        assertMatches(new String[] {"/a", "/a/b", "/a/b/**"}, "/a/b/**");
+        assertMatches(new String[] {"/a", "/a/b", "/a/b/**"}, "/a/b/**/d");
+        assertMatches(new String[] {"/a", "/a/b", "/a/b/**"}, "/a/b/**/d/**");
+        assertMatches(new String[] {"/a", "/a/b", "/a/b/**"}, "/a/b/**/d/**/f");
+        assertMatches(new String[] {"/a", "/a/b", "/a/b/c", "/a/b/c/d"}, "/a/b/c/d");
+        assertMatches(new String[] {"/a", "/a/b", "/a/b/c", "/a/b/c/*"}, "/a/b/c/*");
+        assertMatches(new String[] {"/a", "/a/b", "/a/b/c", "/a/b/c/**"}, "/a/b/c/**");
     }
 
     private void assertMatches(String[] expectedPaths, String globPath) {

Modified: jackrabbit/oak/branches/1.6/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/ObservationTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.6/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/ObservationTest.java?rev=1782801&r1=1782800&r2=1782801&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.6/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/ObservationTest.java (original)
+++ jackrabbit/oak/branches/1.6/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/observation/ObservationTest.java Mon Feb 13 16:24:41 2017
@@ -42,6 +42,7 @@ import static org.junit.Assert.assertArr
 import static org.junit.Assume.assumeTrue;
 
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -1539,6 +1540,179 @@ public class ObservationTest extends Abs
         testNode.getNode("a").remove();
         testNode.getSession().save();
     }
+    
+    /**
+     * This tests a filter which registers a few paths and then expects
+     * NOT to get any event if an unrelated parent is removed
+     */
+    @Test
+    public void includeAncestorsRemove_Unrelated() throws Exception {
+        doIncludeAncestorsRemove_Unrelated(
+                new String[] {"/a/b/c/d"}, 
+                new String[] {"/unrelated/child", "/unrelated", "/a/b/c/unrelated/child", "/a/b/c/unrelated", 
+                        "/a/b/unrelated/child", "/a/b/unrelated", "/a/unrelated/child", "/a/unrelated", 
+                        "/a"},
+                new String[] {"/a"},
+                new String[] {});
+        doIncludeAncestorsRemove_Unrelated(
+                new String[] {"/a/b/c/d"}, 
+                new String[] {"/unrelated/child", "/unrelated", "/a/b/c/unrelated/child", "/a/b/c/unrelated", 
+                        "/a/b/unrelated/child", "/a/b/unrelated", "/a/unrelated/child", "/a/unrelated", 
+                        "/a/b"},
+                new String[] {"/a/b"},
+                new String[] {});
+        doIncludeAncestorsRemove_Unrelated(
+                new String[] {"/a/b/c/d"}, 
+                new String[] {"/unrelated/child", "/unrelated", "/a/b/c/unrelated/child", "/a/b/c/unrelated", 
+                        "/a/b/unrelated/child", "/a/b/unrelated", "/a/unrelated/child", "/a/unrelated", 
+                        "/a/b/c"},
+                new String[] {"/a/b/c"},
+                new String[] {});
+        doIncludeAncestorsRemove_Unrelated(
+                new String[] {"/a/b/c/d"}, 
+                new String[] {"/unrelated/child", "/unrelated", "/a/b/c/unrelated/child", "/a/b/c/unrelated", 
+                        "/a/b/unrelated/child", "/a/b/unrelated", "/a/unrelated/child", "/a/unrelated", 
+                        "/a/b/c/d"},
+                new String[] {"/a/b/c/d"},
+                new String[] {"/a/b/c/d/jcr:primaryType"});
+        doIncludeAncestorsRemove_Unrelated(
+                new String[] {"/a/b/c/d/*.html"}, 
+                new String[] {"/unrelated/child", "/unrelated", "/a/b/c/unrelated/child", "/a/b/c/unrelated", 
+                        "/a/b/unrelated/child", "/a/b/unrelated", "/a/unrelated/child", "/a/unrelated", 
+                        "/a/b/c/d"},
+                new String[] {"/a/b/c/d"},
+                new String[] {});
+
+        // and some glob tests:
+        doIncludeAncestorsRemove_Unrelated(
+                new String[] {"/a/b/*/d"}, 
+                new String[] {"/unrelated/child", "/unrelated", "/a/b/c/unrelated/child", "/a/b/c/unrelated", 
+                        "/a/b/related/unrelatedchild", "/a/b/related", "/a/unrelated/child", "/a/unrelated", 
+                        "/a"},
+                new String[] {"/a", "/a/b/related"},
+                new String[] {});
+        doIncludeAncestorsRemove_Unrelated(
+                new String[] {"/a/b/**/d"}, 
+                new String[] {"/unrelated/child", "/unrelated", "/a/b/c/related/child", "/a/b/c/related", 
+                        "/a/b/related/child", "/a/b/related", "/a/unrelated/child", "/a/unrelated", 
+                        "/a"},
+                new String[] {"/a", "/a/b/related", "/a/b/related/child", "/a/b/c/related/child", "/a/b/c/related"},
+                new String[] {});
+        doIncludeAncestorsRemove_Unrelated(
+                new String[] {"/a/b/**/d/*.html"}, 
+                new String[] {"/unrelated/child", "/unrelated", "/a/b/c/related/child", "/a/b/c/related", 
+                        "/a/b/related/child", "/a/b/related", "/a/unrelated/child", "/a/unrelated", 
+                        "/a"},
+                new String[] {"/a", "/a/b/related", "/a/b/related/child", "/a/b/c/related/child", "/a/b/c/related"},
+                new String[] {});
+
+        doIncludeAncestorsRemove_Unrelated(
+                new String[] {"/a/*/c/d"}, 
+                new String[] {"/unrelated/child", "/unrelated", "/a/b/c/unrelated/child", "/a/b/c/unrelated", 
+                        "/a/b/unrelated/child", "/a/b/unrelated", "/a/related/unrelatedchild", "/a/related", 
+                        "/a/b"},
+                new String[] {"/a/b", "/a/related"},
+                new String[] {});
+        doIncludeAncestorsRemove_Unrelated(
+                new String[] {"/a/**/c/d"}, 
+                new String[] {"/unrelated/child", "/unrelated", "/a/b/c/related/child", "/a/b/c/related", 
+                        "/a/b/related/child", "/a/b/related", "/a/related/relatedchild", "/a/related", 
+                        "/a/b"},
+                new String[] {"/a/b", "/a/related/relatedchild", "/a/related", "/a/b/related/child", "/a/b/related", "/a/b/c/related/child", "/a/b/c/related"},
+                new String[] {});
+        doIncludeAncestorsRemove_Unrelated(
+                new String[] {"/a/*/c/*.html"}, 
+                new String[] {"/unrelated/child", "/unrelated", "/a/b/c/unrelated/child", "/a/b/c/unrelated", 
+                        "/a/b/unrelated/child", "/a/b/unrelated", "/a/related/unrelatedchild", "/a/related", 
+                        "/a/b/c/x.html", "/a/b"},
+                new String[] {"/a/b", "/a/related", "/a/b/c/x.html"},
+                new String[] {"/a/b/c/x.html/jcr:primaryType"});
+        doIncludeAncestorsRemove_Unrelated(
+                new String[] {"/a/**/c/*.html"}, 
+                new String[] {"/unrelated/child", "/unrelated", "/a/b/c/related/child", "/a/b/c/related", 
+                        "/a/b/related/child", "/a/b/related", "/a/related/child", "/a/related", 
+                        "/a/b"},
+                new String[] {"/a/b", "/a/related/child", "/a/related", "/a/b/related/child", "/a/b/related", "/a/b/c/related/child", "/a/b/c/related", "/a/b/c/related/child", "/a/b/c/related"},
+                new String[] {});
+    }
+    
+    private void doIncludeAncestorsRemove_Unrelated(String[] absPaths, 
+            String[] createAndRemoveNodes, String[] expectedRemoveNodeEvents, String[] expectedRemovePropertyEvents) throws Exception {
+        assumeTrue(observationManager instanceof ObservationManagerImpl);
+        ObservationManagerImpl oManager = (ObservationManagerImpl) observationManager;
+
+        OakEventFilter filterWithAncestorsRemove = FilterFactory.wrap(new JackrabbitEventFilter());
+        filterWithAncestorsRemove.setEventTypes(NODE_REMOVED | PROPERTY_REMOVED);
+        assertTrue(absPaths.length >= 1);
+        String[] additionalPaths = new String[absPaths.length];
+        System.arraycopy(absPaths, 0, additionalPaths, 0, absPaths.length);
+        if (!absPaths[0].contains("*")) {
+            filterWithAncestorsRemove.setAbsPath(absPaths[0]);
+            if (absPaths.length > 1) {
+                additionalPaths = new String[absPaths.length - 1];
+                System.arraycopy(absPaths, 1, additionalPaths, 0, absPaths.length - 1);
+            }
+        }
+        filterWithAncestorsRemove.withIncludeGlobPaths(additionalPaths);
+        filterWithAncestorsRemove.setIsDeep(true);
+        filterWithAncestorsRemove = filterWithAncestorsRemove.withIncludeAncestorsRemove();
+        ExpectationListener listenerWithAncestorsRemove = new ExpectationListener();
+        oManager.addEventListener(listenerWithAncestorsRemove, filterWithAncestorsRemove);
+
+        OakEventFilter filterWithoutAncestorsRemove = FilterFactory.wrap(new JackrabbitEventFilter());
+        filterWithoutAncestorsRemove.setEventTypes(NODE_REMOVED);
+        if (!absPaths[0].contains("*")) {
+            filterWithoutAncestorsRemove.setAbsPath(absPaths[0]);
+        }
+        filterWithoutAncestorsRemove.withIncludeGlobPaths(additionalPaths);
+        filterWithoutAncestorsRemove.setIsDeep(true);
+        ExpectationListener listenerWithoutAncestorsRemove = new ExpectationListener();
+        oManager.addEventListener(listenerWithoutAncestorsRemove, filterWithoutAncestorsRemove);
+
+        Session session = getAdminSession();
+        for (String path : createAndRemoveNodes) {
+            Iterator<String> it = PathUtils.elements(path).iterator();
+            Node node = session.getRootNode();
+            while(it.hasNext()) {
+                String elem = it.next();
+                if (!node.hasNode(elem)) {
+                    node = node.addNode(elem);
+                } else {
+                    node = node.getNode(elem);
+                }
+            }
+        }
+        session.save();
+
+        for (String nodePath : expectedRemoveNodeEvents) {
+            listenerWithAncestorsRemove.expect(nodePath, NODE_REMOVED);
+        }
+        for (String propertyPath : expectedRemovePropertyEvents) {
+            listenerWithAncestorsRemove.expect(propertyPath, PROPERTY_REMOVED);
+        }
+
+        for (String path : createAndRemoveNodes) {
+            Iterator<String> it = PathUtils.elements(path).iterator();
+            Node node = session.getRootNode();
+            while(it.hasNext()) {
+                String elem = it.next();
+                node = node.getNode(elem);
+            }
+            node.remove();
+            session.save();
+        }
+        
+        Thread.sleep(1000);
+        List<Expectation> missing = listenerWithoutAncestorsRemove.getMissing(TIME_OUT, TimeUnit.SECONDS);
+        List<Event> unexpected = listenerWithoutAncestorsRemove.getUnexpected();
+        assertTrue("Unexpected events (listenerWithoutAncestorsRemove): " + unexpected, unexpected.isEmpty());
+        assertTrue("Missing events (listenerWithoutAncestorsRemove): " + missing, missing.isEmpty());
+
+        missing = listenerWithAncestorsRemove.getMissing(TIME_OUT, TimeUnit.SECONDS);
+        unexpected = listenerWithAncestorsRemove.getUnexpected();
+        assertTrue("Unexpected events (listenerWithAncestorsRemove): " + unexpected, unexpected.isEmpty());
+        assertTrue("Missing events (listenerWithAncestorsRemove): " + missing, missing.isEmpty());
+    }
 
     @Test
     public void includeAncestorsRemove() throws Exception {
@@ -2123,7 +2297,7 @@ public class ObservationTest extends Abs
         oef.withIncludeAncestorsRemove()
                 .withNodeTypeAggregate(new String[] { "oak:Unstructured" }, new String[] { "", "jcr:content" } )
                 .withIncludeGlobPaths("/**/*.jsp");
-        doTestAggregate6(oef, new String[] {"/"}, new String[] {"/*", "/**/*.jsp", "/**/*.jsp/**"});
+        doTestAggregate6(oef, new String[] {"/"}, new String[] {"/**", "/**/*.jsp", "/**/*.jsp/**"});
 
         oef = FilterFactory.wrap(new JackrabbitEventFilter());
         oef.setEventTypes(ALL_EVENTS);
@@ -2131,14 +2305,14 @@ public class ObservationTest extends Abs
         oef.withIncludeAncestorsRemove()
                 .withNodeTypeAggregate(new String[] { "oak:Unstructured" }, new String[] { "", "jcr:content" } )
                 .withIncludeGlobPaths("/**/*.jsp");
-        doTestAggregate6(oef, new String[] {"/"}, new String[] {"/*", "/**/*.jsp", "/**/*.jsp/**"});
+        doTestAggregate6(oef, new String[] {"/"}, new String[] {"/**", "/**/*.jsp", "/**/*.jsp/**"});
         
         oef = FilterFactory.wrap(new JackrabbitEventFilter());
         oef.setEventTypes(ALL_EVENTS);
         oef.withIncludeAncestorsRemove()
                 .withNodeTypeAggregate(new String[] { "oak:Unstructured" }, new String[] { "", "jcr:content" } )
                 .withIncludeGlobPaths("**/*.jsp");
-        doTestAggregate6(oef, new String[] {"/"}, new String[] {"/*", "**/*.jsp", "**/*.jsp/**"});
+        doTestAggregate6(oef, new String[] {"/"}, new String[] {"/**", "**/*.jsp", "**/*.jsp/**"});
 
         oef = FilterFactory.wrap(new JackrabbitEventFilter());
         oef.setEventTypes(ALL_EVENTS);
@@ -2159,7 +2333,14 @@ public class ObservationTest extends Abs
         oef.withIncludeAncestorsRemove()
                 .withNodeTypeAggregate(new String[] { "oak:Unstructured" }, new String[] { "", "jcr:content" } )
                 .withIncludeGlobPaths("/parent/**/*.jsp");
-        doTestAggregate6(oef, new String[] {"/"}, new String[] {"/*", "/parent/*", "/parent/**/*.jsp", "/parent/**/*.jsp/**"});
+        doTestAggregate6(oef, new String[] {"/"}, new String[] {"/parent", "/parent/**", "/parent/**/*.jsp", "/parent/**/*.jsp/**"});
+        
+        oef = FilterFactory.wrap(new JackrabbitEventFilter());
+        oef.setEventTypes(ALL_EVENTS);
+        oef.withIncludeAncestorsRemove()
+                .withNodeTypeAggregate(new String[] { "oak:Unstructured" }, new String[] { "", "jcr:content" } )
+                .withIncludeGlobPaths("/parent/bar/**/*.jsp");
+        doTestAggregate6(oef, new String[] {"/"}, new String[] {"/parent", "/parent/bar", "/parent/bar/**", "/parent/bar/**/*.jsp", "/parent/bar/**/*.jsp/**"});
         
         oef = FilterFactory.wrap(new JackrabbitEventFilter());
         oef.setEventTypes(ALL_EVENTS);
@@ -2180,7 +2361,7 @@ public class ObservationTest extends Abs
         oef.withIncludeAncestorsRemove()
                 .withNodeTypeAggregate(new String[] { "oak:Unstructured" }, new String[] { "", "jcr:content" } )
                 .withIncludeGlobPaths("/parent/**/*.jsp", "/foo/bar/**");
-        doTestAggregate6(oef, new String[] {"/"}, new String[] {"/*", "/foo/*", "/foo/bar/*", "/foo/bar/**", "/parent/*", "/parent/**/*.jsp", "/parent/**/*.jsp/**"});
+        doTestAggregate6(oef, new String[] {"/"}, new String[] {"/parent", "/foo", "/foo/bar", "/foo/bar/**", "/parent/**", "/parent/**/*.jsp", "/parent/**/*.jsp/**"});
     }
 
     private void doTestAggregate6(OakEventFilter oef, String[] expectedSubTrees, String[] expectedPrefilterPaths)