You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by tr...@apache.org on 2017/11/08 04:00:45 UTC

svn commit: r1814551 - in /jackrabbit/commons/filevault/trunk/vault-core: ./ src/main/java/org/apache/jackrabbit/vault/fs/config/ src/main/java/org/apache/jackrabbit/vault/fs/impl/ src/test/java/org/apache/jackrabbit/vault/fs/filter/ src/test/java/org/...

Author: tripod
Date: Wed Nov  8 04:00:45 2017
New Revision: 1814551

URL: http://svn.apache.org/viewvc?rev=1814551&view=rev
Log:
JCRVLT-197 AggregateImpl.includesProperty fails with multiple filter roots

Added:
    jackrabbit/commons/filevault/trunk/vault-core/.ratignore
    jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/complex-expected.xml
    jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/complex.xml
Modified:
    jackrabbit/commons/filevault/trunk/vault-core/pom.xml
    jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/DefaultWorkspaceFilter.java
    jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/package-info.java
    jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/AggregateImpl.java
    jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/fs/filter/WorkspaceFilterTest.java
    jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestFilteredPropertyExport.java

Added: jackrabbit/commons/filevault/trunk/vault-core/.ratignore
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/.ratignore?rev=1814551&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/.ratignore (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/.ratignore Wed Nov  8 04:00:45 2017
@@ -0,0 +1,2 @@
+.ratignore
+src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/complex-expected.xml
\ No newline at end of file

Modified: jackrabbit/commons/filevault/trunk/vault-core/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/pom.xml?rev=1814551&r1=1814550&r2=1814551&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/pom.xml (original)
+++ jackrabbit/commons/filevault/trunk/vault-core/pom.xml Wed Nov  8 04:00:45 2017
@@ -97,6 +97,26 @@
                     <excludePackageNames>org.apache.jackrabbit.vault.util.xml.*</excludePackageNames>
                 </configuration>
             </plugin>
+            <!-- ====================================================================== -->
+            <!-- R A T   P L U G I N                                                    -->
+            <!-- ====================================================================== -->
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <version>0.12</version>
+                <executions>
+                    <execution>
+                        <phase>verify</phase>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                        <configuration>
+                            <basedir>${project.basedir}</basedir>
+                            <excludesFile>${project.basedir}/.ratignore</excludesFile>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 

Modified: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/DefaultWorkspaceFilter.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/DefaultWorkspaceFilter.java?rev=1814551&r1=1814550&r2=1814551&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/DefaultWorkspaceFilter.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/DefaultWorkspaceFilter.java Wed Nov  8 04:00:45 2017
@@ -101,13 +101,36 @@ public class DefaultWorkspaceFilter impl
      */
     public void add(PathFilterSet set) {
         nodesFilterSets.add(set);
+        propsFilterSets.add(set);
+    }
+
+    /**
+     * Add a #PathFilterSet for node and property items.
+     * @param nodeFilter the set of filters to add.
+     * @param propFilter the set of filters to add.
+     */
+    public void add(PathFilterSet nodeFilter, PathFilterSet propFilter) {
+        nodesFilterSets.add(nodeFilter);
+        propsFilterSets.add(propFilter);
     }
 
     /**
      * Add a #PathFilterSet for properties items.
      * @param set the set of filters to add.
+     *
+     * @deprecated use {@link #add(PathFilterSet, PathFilterSet)} instead.
      */
+    @Deprecated
     public void addPropertyFilterSet(PathFilterSet set) {
+        // minimal backward compatibility: replace the props filter with the same root
+        Iterator<PathFilterSet> iter = propsFilterSets.iterator();
+        while (iter.hasNext()) {
+            PathFilterSet filterSet = iter.next();
+            if (filterSet.getRoot().equals(set.getRoot())) {
+                iter.remove();
+                break;
+            }
+        }
         propsFilterSets.add(set);
     }
 
@@ -216,10 +239,10 @@ public class DefaultWorkspaceFilter impl
             mapped.setGlobalIgnored(globalIgnored.translate(mapping));
         }
         for (PathFilterSet set: nodesFilterSets) {
-            mapped.add(set.translate(mapping));
+            mapped.nodesFilterSets.add(set.translate(mapping));
         }
         for (PathFilterSet set: propsFilterSets) {
-            mapped.addPropertyFilterSet(set.translate(mapping));
+            mapped.propsFilterSets.add(set.translate(mapping));
         }
         return mapped;
     }
@@ -332,20 +355,25 @@ public class DefaultWorkspaceFilter impl
         for (int i=0; i<n1.getLength(); i++) {
             Node child = n1.item(i);
             if (child.getNodeType() == Node.ELEMENT_NODE) {
-                Element element = (Element) child;
-                boolean matchProperties = Boolean.valueOf(element.getAttribute("matchProperties"));
-                PathFilterSet set =  (matchProperties) ? propFilters : nodeFilters;
+                final PathFilter filter = readFilter((Element) child);
                 if ("include".equals(child.getNodeName())) {
-                    set.addInclude(readFilter((Element) child));
+                    propFilters.addInclude(filter);
+                    if (!(filter instanceof DefaultPropertyPathFilter)) {
+                        // also add non property filters to the node filters
+                        nodeFilters.addInclude(filter);
+                    }
                 } else if ("exclude".equals(child.getNodeName())) {
-                    set.addExclude(readFilter((Element) child));
+                    propFilters.addExclude(filter);
+                    if (!(filter instanceof DefaultPropertyPathFilter)) {
+                        // also add non property filters to the node filters
+                        nodeFilters.addExclude(filter);
+                    }
                 } else {
                     throw new ConfigurationException("either <include> or <exclude> expected.");
                 }
             }
         }
-        add(nodeFilters);
-        addPropertyFilterSet(propFilters);
+        add(nodeFilters, propFilters);
     }
 
     protected PathFilter readFilter(Element elem) throws ConfigurationException {
@@ -353,6 +381,10 @@ public class DefaultWorkspaceFilter impl
         if (pattern == null || "".equals(pattern)) {
             throw new ConfigurationException("Filter pattern must not be empty");
         }
+        boolean matchProperties = Boolean.valueOf(elem.getAttribute("matchProperties"));
+        if (matchProperties) {
+            return new DefaultPropertyPathFilter(pattern);
+        }
         return new DefaultPathFilter(pattern);
     }
 
@@ -387,7 +419,7 @@ public class DefaultWorkspaceFilter impl
             AttributesImpl attrs = new AttributesImpl();
             attrs.addAttribute(null, null, ATTR_VERSION, "CDATA", String.valueOf(version));
             ser.startElement(null, null, "workspaceFilter", attrs);
-            for (PathFilterSet set: nodesFilterSets) {
+            for (PathFilterSet set: propsFilterSets) {
                 attrs = new AttributesImpl();
                 attrs.addAttribute(null, null, "root", "CDATA", set.getRoot());
                 if (set.getImportMode() != ImportMode.REPLACE) {
@@ -399,8 +431,10 @@ public class DefaultWorkspaceFilter impl
                     PathFilter filter = entry.getFilter();
                     if (filter instanceof DefaultPathFilter) {
                         attrs = new AttributesImpl();
-                        attrs.addAttribute(null, null, "pattern", "CDATA",
-                                ((DefaultPathFilter) filter).getPattern());
+                        attrs.addAttribute(null, null, "pattern", "CDATA", ((DefaultPathFilter) filter).getPattern());
+                        if (filter instanceof DefaultPropertyPathFilter) {
+                            attrs.addAttribute(null, null, "matchProperties", "CDATA", "true");
+                        }
                         if (entry.isInclude()) {
                             ser.startElement(null, null, "include", attrs);
                             ser.endElement("include");
@@ -481,5 +515,25 @@ public class DefaultWorkspaceFilter impl
         }
     }
 
+    /**
+     * internal class to mark the property filter entries. eventually promote to outer class and adjust the 'contains'
+     * code accordingly. But since the filter set are publicly accessible, this would introduce backward compatbility
+     * issues for code that is reading those directly.
+     */
+    private static class DefaultPropertyPathFilter extends DefaultPathFilter {
+
+        private DefaultPropertyPathFilter(String pattern) {
+            super(pattern);
+        }
+
+        @Override
+        public PathFilter translate(PathMapping mapping) {
+            DefaultPathFilter mapped =  (DefaultPathFilter) super.translate(mapping);
+            if (mapped != this) {
+                mapped = new DefaultPropertyPathFilter(mapped.getPattern());
+            }
+            return mapped;
+        }
+    }
 
 }
\ No newline at end of file

Modified: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/package-info.java?rev=1814551&r1=1814550&r2=1814551&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/package-info.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/package-info.java Wed Nov  8 04:00:45 2017
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-@Version("2.4.0")
+@Version("2.5.0")
 package org.apache.jackrabbit.vault.fs.config;
 
 import org.osgi.annotation.versioning.Version;
\ No newline at end of file

Modified: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/AggregateImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/AggregateImpl.java?rev=1814551&r1=1814550&r2=1814551&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/AggregateImpl.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/AggregateImpl.java Wed Nov  8 04:00:45 2017
@@ -47,6 +47,7 @@ import org.apache.jackrabbit.vault.fs.ap
 import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
 import org.apache.jackrabbit.vault.fs.api.RepositoryAddress;
 import org.apache.jackrabbit.vault.fs.api.VaultFsConfig;
+import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
 import org.apache.jackrabbit.vault.fs.impl.io.AggregateWalkListener;
 import org.apache.jackrabbit.vault.util.NodeNameComparator;
 import org.apache.jackrabbit.vault.util.PathUtil;
@@ -572,13 +573,26 @@ public class AggregateImpl implements Ag
         }
     }
 
-    private boolean includesProperty(String propertyPath) {
-        for (PathFilterSet filterSet: mgr.getWorkspaceFilter().getPropertyFilterSets()) {
-            if (!filterSet.contains(propertyPath)) {
-                return false;
+    /**
+     * Tests if the given workspace filter includes the given property. If the filter does not cover the property,
+     * it returns {@code true}.
+     *
+     * @param filter the workspace filter
+     * @param propertyPath the path to the property
+     * @return {@code true} if the property is included in the aggregate
+     */
+    private boolean includesProperty(WorkspaceFilter filter, String propertyPath) {
+        if (!filter.covers(propertyPath)) {
+            // include all properties that are not covered by any filter. this is to ensure that the ancestor paths
+            // have at least jcr:primary type.
+            return true;
+        }
+        for (PathFilterSet filterSet: filter.getPropertyFilterSets()) {
+            if (filterSet.contains(propertyPath)) {
+                return true;
             }
         }
-        return true;
+        return false;
     }
 
     private void addNamespace(Set<String> prefixes, String name) throws RepositoryException {
@@ -680,12 +694,13 @@ public class AggregateImpl implements Ag
         if (log.isDebugEnabled()) {
             log.trace("descending into {} (descend={})", node.getPath(), descend);
         }
+        final WorkspaceFilter filter = mgr.getWorkspaceFilter();
         // add "our" properties to the include set
         PropertyIterator pIter = node.getProperties();
         while (pIter.hasNext()) {
             Property p = pIter.nextProperty();
             String path = p.getPath();
-            if (aggregator.includes(getNode(), node, p, path) && includesProperty(path)) {
+            if (aggregator.includes(getNode(), node, p, path) && includesProperty(filter, path)) {
                 include(node, p, path);
             }
         }
@@ -695,9 +710,9 @@ public class AggregateImpl implements Ag
         while (nIter.hasNext()) {
             Node n = nIter.nextNode();
             String path = n.getPath();
-            PathFilterSet coverSet = mgr.getWorkspaceFilter().getCoveringFilterSet(path);
-            boolean isAncestor = mgr.getWorkspaceFilter().isAncestor(path);
-            boolean isIncluded = mgr.getWorkspaceFilter().contains(path);
+            PathFilterSet coverSet = filter.getCoveringFilterSet(path);
+            boolean isAncestor = filter.isAncestor(path);
+            boolean isIncluded = filter.contains(path);
             if (coverSet == null && !isAncestor) {
                 continue;
             }

Modified: jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/fs/filter/WorkspaceFilterTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/fs/filter/WorkspaceFilterTest.java?rev=1814551&r1=1814550&r2=1814551&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/fs/filter/WorkspaceFilterTest.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/fs/filter/WorkspaceFilterTest.java Wed Nov  8 04:00:45 2017
@@ -27,6 +27,7 @@ import org.apache.jackrabbit.vault.fs.ap
 import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
 import org.apache.jackrabbit.vault.fs.config.ConfigurationException;
 import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
+import org.apache.tika.io.IOUtils;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
@@ -132,9 +133,20 @@ public class WorkspaceFilterTest {
         PathFilterSet propertyFilterSet = propertyFilterSets.get(0);
         assertEquals("/var/foo/bar", propertyFilterSet.getRoot());
         List<FilterSet.Entry<PathFilter>> propertyFilters = propertyFilterSet.getEntries();
-        assertEquals(1, propertyFilters.size());
+        assertEquals(2, propertyFilters.size());
         FilterSet.Entry<PathFilter> propertyFilter = propertyFilters.get(0);
         assertFalse(propertyFilter.isInclude());
+    }
+
+    @Test
+    public void testToSource() throws IOException, ConfigurationException {
+
+        DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+        filter.load(getClass().getResourceAsStream("workspacefilters/complex.xml"));
+        filter.resetSource();
+
+        String expected = IOUtils.toString(getClass().getResourceAsStream("workspacefilters/complex-expected.xml"));
 
+        assertEquals("Filter source", expected, filter.getSourceAsString());
     }
 }
\ No newline at end of file

Modified: jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestFilteredPropertyExport.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestFilteredPropertyExport.java?rev=1814551&r1=1814550&r2=1814551&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestFilteredPropertyExport.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestFilteredPropertyExport.java Wed Nov  8 04:00:45 2017
@@ -17,6 +17,7 @@
 
 package org.apache.jackrabbit.vault.packaging.integration;
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
 import java.util.Properties;
@@ -27,6 +28,7 @@ import javax.jcr.Session;
 
 import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
 import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
+import org.apache.jackrabbit.vault.fs.config.ConfigurationException;
 import org.apache.jackrabbit.vault.fs.config.DefaultMetaInf;
 import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
 import org.apache.jackrabbit.vault.fs.filter.DefaultPathFilter;
@@ -49,9 +51,25 @@ public class TestFilteredPropertyExport
     }
 
     @Test
+    public void noPropertyFiltered_deprecated() throws IOException, RepositoryException, PackageException {
+        DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+        filter.add(new PathFilterSet("/tmp"));
+        filter.addPropertyFilterSet(new PathFilterSet("/tmp"));
+        // export and extract
+        File pkgFile = assemblePackage(filter);
+        clean("/tmp");
+        packMgr.open(pkgFile).extract(admin, getDefaultOptions());
+        // validate the extracted content
+        assertPropertiesExist("/tmp", "p1", "p2", "p3");
+        assertPropertiesExist("/tmp/foo", "p1", "p2", "p3");
+        assertPropertiesExist("/tmp/foo/bar", "p1", "p2", "p3");
+    }
+
+    @Test
     public void noPropertyFiltered() throws IOException, RepositoryException, PackageException {
         DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
         filter.add(new PathFilterSet("/tmp"));
+
         // export and extract
         File pkgFile = assemblePackage(filter);
         clean("/tmp");
@@ -63,6 +81,25 @@ public class TestFilteredPropertyExport
     }
 
     @Test
+    public void filterPropertyP1OnFoo_deprecated() throws IOException, RepositoryException, PackageException {
+        PathFilterSet properties = new PathFilterSet("/tmp");
+        properties.addExclude(new DefaultPathFilter("/tmp/foo/p1"));
+
+        DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+        filter.add(new PathFilterSet("/tmp"), properties);
+
+        // export and extract
+        File pkgFile = assemblePackage(filter);
+        clean("/tmp");
+        packMgr.open(pkgFile).extract(admin, getDefaultOptions());
+        // validate the extracted content
+        assertPropertiesExist("/tmp", "p1", "p2", "p3");
+        assertPropertiesExist("/tmp/foo", "p2", "p3");
+        assertPropertiesMissg("/tmp/foo", "p1");
+        assertPropertiesExist("/tmp/foo/bar", "p1", "p2", "p3");
+    }
+
+    @Test
     public void filterPropertyP1OnFoo() throws IOException, RepositoryException, PackageException {
         DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
         filter.add(new PathFilterSet("/tmp"));
@@ -82,13 +119,73 @@ public class TestFilteredPropertyExport
     }
 
     @Test
+    public void filterPropertyPxOnFoo_deprecated() throws IOException, RepositoryException, PackageException {
+        DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+        filter.add(new PathFilterSet("/tmp"));
+
+        PathFilterSet properties = new PathFilterSet("/tmp");
+        properties.addExclude(new DefaultPathFilter("/tmp/foo/p.*"));
+        filter.addPropertyFilterSet(properties);
+        // export and extract
+        File pkgFile = assemblePackage(filter);
+        clean("/tmp");
+        packMgr.open(pkgFile).extract(admin, getDefaultOptions());
+        // validate the extracted content
+        assertPropertiesExist("/tmp", "p1", "p2", "p3");
+        assertPropertiesMissg("/tmp/foo", "p1", "p2", "p3");
+        assertPropertiesExist("/tmp/foo/bar", "p1", "p2", "p3");
+    }
+
+    @Test
     public void filterPropertyPxOnFoo() throws IOException, RepositoryException, PackageException {
+
+        PathFilterSet properties = new PathFilterSet("/tmp");
+        properties.addExclude(new DefaultPathFilter("/tmp/foo/p.*"));
+
+        DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+        filter.add(new PathFilterSet("/tmp"), properties);
+
+        // export and extract
+        File pkgFile = assemblePackage(filter);
+        clean("/tmp");
+        packMgr.open(pkgFile).extract(admin, getDefaultOptions());
+        // validate the extracted content
+        assertPropertiesExist("/tmp", "p1", "p2", "p3");
+        assertPropertiesMissg("/tmp/foo", "p1", "p2", "p3");
+        assertPropertiesExist("/tmp/foo/bar", "p1", "p2", "p3");
+    }
+
+    @Test
+    public void filterPropertyWithTwoRoots_deprecated() throws IOException, RepositoryException, PackageException {
+        PathFilterSet properties = new PathFilterSet("/tmp");
+        properties.addExclude(new DefaultPathFilter("/tmp/foo/p.*"));
+
+        DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+        filter.add(new PathFilterSet("/foo"));
+        filter.add(new PathFilterSet("/tmp"), properties);
+
+        // export and extract
+        File pkgFile = assemblePackage(filter);
+        clean("/tmp");
+        packMgr.open(pkgFile).extract(admin, getDefaultOptions());
+        // validate the extracted content
+        assertPropertiesExist("/tmp", "p1", "p2", "p3");
+        assertPropertiesMissg("/tmp/foo", "p1", "p2", "p3");
+        assertPropertiesExist("/tmp/foo/bar", "p1", "p2", "p3");
+    }
+
+    @Test
+    public void filterPropertyWithTwoRoots() throws IOException, RepositoryException, PackageException {
+
         DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+        filter.add(new PathFilterSet("/foo"));
+        filter.addPropertyFilterSet(new PathFilterSet("/foo"));
         filter.add(new PathFilterSet("/tmp"));
 
         PathFilterSet properties = new PathFilterSet("/tmp");
         properties.addExclude(new DefaultPathFilter("/tmp/foo/p.*"));
         filter.addPropertyFilterSet(properties);
+
         // export and extract
         File pkgFile = assemblePackage(filter);
         clean("/tmp");
@@ -100,7 +197,30 @@ public class TestFilteredPropertyExport
     }
 
     @Test
-    public void filterRelativeProperties() throws IOException, RepositoryException, PackageException {
+    public void filterPropertyFromSource() throws IOException, RepositoryException, PackageException, ConfigurationException {
+        String src = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+                "<workspaceFilter version=\"1.0\">\n" +
+                "    <filter root=\"/foo\"/>\n" +
+                "    <filter root=\"/tmp\">\n" +
+                "        <exclude pattern=\"/tmp/foo/p.*\" matchProperties=\"true\"/>\n" +
+                "    </filter>\n" +
+                "</workspaceFilter>";
+
+        DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+        filter.load(new ByteArrayInputStream(src.getBytes("utf-8")));
+
+        // export and extract
+        File pkgFile = assemblePackage(filter);
+        clean("/tmp");
+        packMgr.open(pkgFile).extract(admin, getDefaultOptions());
+        // validate the extracted content
+        assertPropertiesExist("/tmp", "p1", "p2", "p3");
+        assertPropertiesMissg("/tmp/foo", "p1", "p2", "p3");
+        assertPropertiesExist("/tmp/foo/bar", "p1", "p2", "p3");
+    }
+
+    @Test
+    public void filterRelativeProperties_deprecated() throws IOException, RepositoryException, PackageException {
         DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
         filter.add(new PathFilterSet("/tmp"));
 
@@ -120,6 +240,27 @@ public class TestFilteredPropertyExport
         assertPropertiesMissg("/tmp/foo/bar", "p1");
     }
 
+    @Test
+    public void filterRelativeProperties() throws IOException, RepositoryException, PackageException {
+        PathFilterSet properties = new PathFilterSet("/tmp");
+        properties.addExclude(new DefaultPathFilter(".*/p1"));
+
+        DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+        filter.add(new PathFilterSet("/tmp"), properties);
+
+        // export and extract
+        File pkgFile = assemblePackage(filter);
+        clean("/tmp");
+        packMgr.open(pkgFile).extract(admin, getDefaultOptions());
+        // validate the extracted content
+        assertPropertiesExist("/tmp", "p2", "p3");
+        assertPropertiesMissg("/tmp", "p1");
+        assertPropertiesExist("/tmp/foo", "p2", "p3");
+        assertPropertiesMissg("/tmp/foo", "p1");
+        assertPropertiesExist("/tmp/foo/bar", "p2", "p3");
+        assertPropertiesMissg("/tmp/foo/bar", "p1");
+    }
+
 
     /**
      * Setup the path /tmp/foo/bar with properties set at each level
@@ -129,7 +270,7 @@ public class TestFilteredPropertyExport
         Node root = session.getRootNode();
         Node tmp = setupProperties(root.addNode("tmp"));
         Node foo = setupProperties(tmp.addNode("foo"));
-        Node bar = setupProperties(foo.addNode("bar"));
+        setupProperties(foo.addNode("bar"));
     }
 
     private Node setupProperties(Node node)

Added: jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/complex-expected.xml
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/complex-expected.xml?rev=1814551&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/complex-expected.xml (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/complex-expected.xml Wed Nov  8 04:00:45 2017
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<workspaceFilter version="1.0">
+    <filter root="/bar" mode="merge"/>
+    <filter root="/tmp">
+        <include pattern="/a/b.*"/>
+        <include pattern="/a/c.*"/>
+        <include pattern="/a/.*" matchProperties="true"/>
+    </filter>
+    <filter root="/var/foo/bar">
+        <exclude pattern="^.*/node1"/>
+        <exclude pattern="^.*/prop1" matchProperties="true"/>
+    </filter>
+</workspaceFilter>

Added: jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/complex.xml
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/complex.xml?rev=1814551&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/complex.xml (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/complex.xml Wed Nov  8 04:00:45 2017
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<workspaceFilter version="1.0">
+    <filter root="/bar" mode="merge" type="cleanup"/>
+    <filter root="/tmp">
+        <include pattern="/a/b.*" />
+        <include pattern="/a/c.*" />
+        <include pattern="/a/.*" matchProperties="true" />
+    </filter>
+    <filter root="/var/foo/bar">
+        <exclude pattern="^.*/node1" />
+        <exclude pattern="^.*/prop1" matchProperties="true"/>
+    </filter>
+</workspaceFilter>