diff --git vault-core/src/main/java/org/apache/jackrabbit/vault/fs/api/WorkspaceFilter.java vault-core/src/main/java/org/apache/jackrabbit/vault/fs/api/WorkspaceFilter.java
index a1c27cd..1c5f362 100644
--- vault-core/src/main/java/org/apache/jackrabbit/vault/fs/api/WorkspaceFilter.java
+++ vault-core/src/main/java/org/apache/jackrabbit/vault/fs/api/WorkspaceFilter.java
@@ -25,25 +25,31 @@ import javax.jcr.RepositoryException;
import javax.jcr.Session;
/**
- * WorkspaceFilter...
+ * WorkspaceFilter defined a filter for items (node or property).
*/
public interface WorkspaceFilter extends Dumpable {
/**
- * Returns a list of path filter sets.
+ * Returns a list of path filter sets for node items.
* @return the list of path filter sets.
*/
List getFilterSets();
/**
- * Returns the filter set that covers the respective path
+ * Returns a list of path filter sets for property items.
+ * @return the list of path filter sets.
+ */
+ List getPropertyFilterSets();
+
+ /**
+ * Returns the filter set that covers the respective node path
* @param path the path
* @return the filter set or null
*/
PathFilterSet getCoveringFilterSet(String path);
/**
- * Returns the import mode for the given path.
+ * Returns the import mode for the given node path.
* @param path path to check
* @return the import mode or {@link ImportMode#REPLACE} if the given path
* is not covered by this filter.
@@ -51,7 +57,7 @@ public interface WorkspaceFilter extends Dumpable {
ImportMode getImportMode(String path);
/**
- * Checks if the given path is contained in this workspace filter.
+ * Checks if the given node path is contained in this workspace filter.
* It returns true if any of the filter sets contain the path
* and it's not globally ignored.
*
@@ -61,7 +67,7 @@ public interface WorkspaceFilter extends Dumpable {
boolean contains(String path);
/**
- * Checks if the given path is covered in this workspace filter.
+ * Checks if the given node path is covered in this workspace filter.
* It only returns true if at least one of the sets covers
* the path and is not globally ignored.
*
@@ -71,7 +77,7 @@ public interface WorkspaceFilter extends Dumpable {
boolean covers(String path);
/**
- * Checks if the given path is an ancestor of any of the filter sets.
+ * Checks if the given node path is an ancestor of any of the filter sets.
*
* @param path the item to check
* @return true if the given item is an ancestor
@@ -79,7 +85,7 @@ public interface WorkspaceFilter extends Dumpable {
boolean isAncestor(String path);
/**
- * Checks if the given path is globally ignored.
+ * Checks if the given node path is globally ignored.
*
* @param path the path to check.
* @return true if the item is globally ignored.
diff --git vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/DefaultWorkspaceFilter.java vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/DefaultWorkspaceFilter.java
index 46f036f..d373d99 100644
--- vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/DefaultWorkspaceFilter.java
+++ vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/DefaultWorkspaceFilter.java
@@ -73,7 +73,9 @@ public class DefaultWorkspaceFilter implements Dumpable, WorkspaceFilter {
*/
private static final Logger log = LoggerFactory.getLogger(DefaultWorkspaceFilter.class);
- private final List filterSets = new LinkedList();
+ private final List nodesFilterSets = new LinkedList();
+
+ private final List propsFilterSets = new LinkedList();
public static final String ATTR_VERSION = "version";
@@ -93,15 +95,34 @@ public class DefaultWorkspaceFilter implements Dumpable, WorkspaceFilter {
*/
private ImportMode importMode;
+ /**
+ * Add a #PathFilterSet for nodes items.
+ * @param set the set of filters to add.
+ */
public void add(PathFilterSet set) {
- filterSets.add(set);
+ nodesFilterSets.add(set);
+ }
+
+ /**
+ * Add a #PathFilterSet for properties items.
+ * @param set the set of filters to add.
+ */
+ public void addPropertyFilterSet(PathFilterSet set) {
+ propsFilterSets.add(set);
}
/**
* {@inheritDoc}
*/
public List getFilterSets() {
- return filterSets;
+ return nodesFilterSets;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List getPropertyFilterSets() {
+ return propsFilterSets;
}
/**
@@ -111,7 +132,7 @@ public class DefaultWorkspaceFilter implements Dumpable, WorkspaceFilter {
if (isGloballyIgnored(path)) {
return null;
}
- for (PathFilterSet set: filterSets) {
+ for (PathFilterSet set: nodesFilterSets) {
if (set.covers(path)) {
return set;
}
@@ -141,7 +162,7 @@ public class DefaultWorkspaceFilter implements Dumpable, WorkspaceFilter {
if (isGloballyIgnored(path)) {
return false;
}
- for (PathFilterSet set: filterSets) {
+ for (PathFilterSet set: nodesFilterSets) {
if (set.contains(path)) {
return true;
}
@@ -156,7 +177,7 @@ public class DefaultWorkspaceFilter implements Dumpable, WorkspaceFilter {
if (isGloballyIgnored(path)) {
return false;
}
- for (PathFilterSet set: filterSets) {
+ for (PathFilterSet set: nodesFilterSets) {
if (set.covers(path)) {
return true;
}
@@ -168,7 +189,7 @@ public class DefaultWorkspaceFilter implements Dumpable, WorkspaceFilter {
* {@inheritDoc}
*/
public boolean isAncestor(String path) {
- for (PathFilterSet set: filterSets) {
+ for (PathFilterSet set: nodesFilterSets) {
if (set.isAncestor(path)) {
return true;
}
@@ -194,9 +215,12 @@ public class DefaultWorkspaceFilter implements Dumpable, WorkspaceFilter {
if (globalIgnored != null) {
mapped.setGlobalIgnored(globalIgnored.translate(mapping));
}
- for (PathFilterSet set: filterSets) {
+ for (PathFilterSet set: nodesFilterSets) {
mapped.add(set.translate(mapping));
}
+ for (PathFilterSet set: propsFilterSets) {
+ mapped.addPropertyFilterSet(set.translate(mapping));
+ }
return mapped;
}
@@ -284,35 +308,44 @@ public class DefaultWorkspaceFilter implements Dumpable, WorkspaceFilter {
if (!"filter".equals(child.getNodeName())) {
throw new ConfigurationException(" expected.");
}
- PathFilterSet def = readDef((Element) child);
- filterSets.add(def);
+ readDef((Element) child);
}
}
}
- private PathFilterSet readDef(Element elem) throws ConfigurationException {
+ private void readDef(Element elem) throws ConfigurationException {
String root = elem.getAttribute("root");
- PathFilterSet def = new PathFilterSet(root == null || root.length() == 0 ? "/" : root);
+ if (root == null || root.length() == 0) {
+ root = "/";
+ }
+ PathFilterSet nodeFilters = new PathFilterSet(root);
+ PathFilterSet propFilters = new PathFilterSet(root);
// check for import mode
String mode = elem.getAttribute("mode");
if (mode != null && mode.length() > 0) {
- def.setImportMode(ImportMode.valueOf(mode.toUpperCase()));
+ ImportMode importMode = ImportMode.valueOf(mode.toUpperCase());
+ nodeFilters.setImportMode(importMode);
+ propFilters.setImportMode(importMode);
}
// check for filters
NodeList n1 = elem.getChildNodes();
for (int i=0; i or expected.");
}
}
}
- return def;
+ add(nodeFilters);
+ addPropertyFilterSet(propFilters);
}
protected PathFilter readFilter(Element elem) throws ConfigurationException {
@@ -327,7 +360,7 @@ public class DefaultWorkspaceFilter implements Dumpable, WorkspaceFilter {
* {@inheritDoc}
*/
public void dump(DumpContext ctx, boolean isLast) {
- Iterator iter = filterSets.iterator();
+ Iterator iter = nodesFilterSets.iterator();
while (iter.hasNext()) {
PathFilterSet set = iter.next();
ctx.println(!iter.hasNext(), "ItemFilterSet");
@@ -354,7 +387,7 @@ public class DefaultWorkspaceFilter implements Dumpable, WorkspaceFilter {
AttributesImpl attrs = new AttributesImpl();
attrs.addAttribute(null, null, ATTR_VERSION, "CDATA", String.valueOf(version));
ser.startElement(null, null, "workspaceFilter", attrs);
- for (PathFilterSet set: filterSets) {
+ for (PathFilterSet set: nodesFilterSets) {
attrs = new AttributesImpl();
attrs.addAttribute(null, null, "root", "CDATA", set.getRoot());
if (set.getImportMode() != ImportMode.REPLACE) {
@@ -411,7 +444,7 @@ public class DefaultWorkspaceFilter implements Dumpable, WorkspaceFilter {
ProgressTracker tracker = new ProgressTracker(listener);
// get common ancestor
Tree tree = new Tree();
- for (PathFilterSet set: filterSets) {
+ for (PathFilterSet set: nodesFilterSets) {
tree.put(set.getRoot(), set);
}
String rootPath = tree.getRootPath();
diff --git vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/AggregateImpl.java vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/AggregateImpl.java
index d70da46..025628c 100644
--- vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/AggregateImpl.java
+++ vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/AggregateImpl.java
@@ -572,6 +572,15 @@ public class AggregateImpl implements Aggregate {
}
}
+ private boolean includeProperty(String propertyPath) {
+ for (PathFilterSet filterSet : mgr.getWorkspaceFilter().getPropertyFilterSets()) {
+ if (! filterSet.contains(propertyPath)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private void addNamespace(Set prefixes, String name) throws RepositoryException {
int idx = name.indexOf(':');
if (idx > 0) {
@@ -676,7 +685,7 @@ public class AggregateImpl implements Aggregate {
while (pIter.hasNext()) {
Property p = pIter.nextProperty();
String path = p.getPath();
- if (aggregator.includes(getNode(), node, p, path)) {
+ if (aggregator.includes(getNode(), node, p, path) && includeProperty(path)) {
include(node, p, path);
}
}
diff --git vault-core/src/test/java/org/apache/jackrabbit/vault/fs/filter/WorkspaceFilterTest.java vault-core/src/test/java/org/apache/jackrabbit/vault/fs/filter/WorkspaceFilterTest.java
index 3fe5908..2b39550 100644
--- vault-core/src/test/java/org/apache/jackrabbit/vault/fs/filter/WorkspaceFilterTest.java
+++ vault-core/src/test/java/org/apache/jackrabbit/vault/fs/filter/WorkspaceFilterTest.java
@@ -16,14 +16,22 @@
*/
package org.apache.jackrabbit.vault.fs.filter;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.jackrabbit.vault.fs.api.FilterSet;
+import org.apache.jackrabbit.vault.fs.api.PathFilter;
import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
import org.apache.jackrabbit.vault.fs.api.PathMapping;
import org.apache.jackrabbit.vault.fs.api.SimplePathMapping;
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.junit.Test;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
@@ -101,4 +109,32 @@ public class WorkspaceFilterTest {
set3.seal();
assertFalse(set3.hasOnlyRelativePatterns());
}
+
+ @Test
+ public void testLoadingWorkspaceFilter()
+ throws IOException, ConfigurationException {
+ DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+ filter.load(getClass().getResourceAsStream("workspacefilters/items.xml"));
+
+ List nodeFilterSets = filter.getFilterSets();
+ assertNotNull(nodeFilterSets);
+ assertEquals(1, nodeFilterSets.size());
+ PathFilterSet nodeFilterSet = nodeFilterSets.get(0);
+ assertEquals("/var/foo/bar", nodeFilterSet.getRoot());
+ List> nodeFilters = nodeFilterSet.getEntries();
+ assertEquals(1, nodeFilters.size());
+ FilterSet.Entry nodeFilter = nodeFilters.get(0);
+ assertFalse(nodeFilter.isInclude());
+
+ List propertyFilterSets = filter.getPropertyFilterSets();
+ assertNotNull(propertyFilterSets);
+ assertEquals(1, propertyFilterSets.size());
+ PathFilterSet propertyFilterSet = propertyFilterSets.get(0);
+ assertEquals("/var/foo/bar", propertyFilterSet.getRoot());
+ List> propertyFilters = propertyFilterSet.getEntries();
+ assertEquals(1, propertyFilters.size());
+ FilterSet.Entry propertyFilter = propertyFilters.get(0);
+ assertFalse(propertyFilter.isInclude());
+
+ }
}
\ No newline at end of file
diff --git vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/IntegrationTestBase.java vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/IntegrationTestBase.java
index 56e2def..06a0584 100644
--- vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/IntegrationTestBase.java
+++ vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/IntegrationTestBase.java
@@ -273,6 +273,11 @@ public class IntegrationTestBase {
assertEquals(path + " should contain " + value, value, admin.getProperty(path).getString());
}
+ public void assertPropertyExists(String path) throws RepositoryException {
+ assertTrue(path + " should exist", admin.propertyExists(path));
+ }
+
+
public void assertProperty(String path, String[] values) throws RepositoryException {
ArrayList strings = new ArrayList();
for (Value v: admin.getProperty(path).getValues()) {
diff --git vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestFilteredPropertyExport.java vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestFilteredPropertyExport.java
new file mode 100644
index 0000000..54d1d3f
--- /dev/null
+++ vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestFilteredPropertyExport.java
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+package org.apache.jackrabbit.vault.packaging.integration;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+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.DefaultMetaInf;
+import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
+import org.apache.jackrabbit.vault.fs.filter.DefaultPathFilter;
+import org.apache.jackrabbit.vault.packaging.ExportOptions;
+import org.apache.jackrabbit.vault.packaging.PackageException;
+import org.apache.jackrabbit.vault.packaging.VaultPackage;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * TestFilteredExport cover testing the filtering of properties
+ */
+public class TestFilteredPropertyExport extends IntegrationTestBase {
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ setupTmpFooBarWithProperties(admin);
+ admin.save();
+ }
+
+ @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");
+ 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 filterPropertyP1OnFoo() throws IOException, RepositoryException, PackageException {
+ DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+ filter.add(new PathFilterSet("/tmp"));
+
+ PathFilterSet properties = new PathFilterSet("/tmp");
+ properties.addExclude(new DefaultPathFilter("/tmp/foo/p1"));
+ 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");
+ assertPropertiesExist("/tmp/foo", "p2", "p3");
+ assertPropertiesMissg("/tmp/foo", "p1" );
+ assertPropertiesExist("/tmp/foo/bar", "p1", "p2", "p3");
+ }
+
+ @Test
+ public void filterPropertyPxOnFoo() 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 filterRelativeProperties() throws IOException, RepositoryException, PackageException {
+ DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+ filter.add(new PathFilterSet("/tmp"));
+
+ PathFilterSet properties = new PathFilterSet("/tmp");
+ properties.addExclude(new DefaultPathFilter(".*/p1"));
+ filter.addPropertyFilterSet(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
+ */
+ private void setupTmpFooBarWithProperties(Session session)
+ throws RepositoryException {
+ Node root = session.getRootNode();
+ Node tmp = setupProperties(root.addNode("tmp"));
+ Node foo = setupProperties(tmp.addNode("foo"));
+ Node bar = setupProperties(foo.addNode("bar"));
+ }
+
+ private Node setupProperties(Node node)
+ throws RepositoryException {
+ node.setProperty("p1", "v1");
+ node.setProperty("p2", "v2");
+ node.setProperty("p3", "v3");
+ return node;
+ }
+
+ private File assemblePackage(WorkspaceFilter filter)
+ throws IOException, RepositoryException {
+
+ File tmpFile = File.createTempFile("vaulttest", "zip");
+
+ ExportOptions options = new ExportOptions();
+ DefaultMetaInf meta = new DefaultMetaInf();
+ meta.setFilter(filter);
+
+ Properties props = new Properties();
+ props.setProperty(VaultPackage.NAME_GROUP, "jackrabbit/test");
+ props.setProperty(VaultPackage.NAME_NAME, "filtered-export-package");
+ meta.setProperties(props);
+
+ options.setMetaInf(meta);
+
+ packMgr.assemble(admin, options, tmpFile).close();
+ return tmpFile;
+ }
+
+ private void assertPropertiesExist(String rootPath, String ... propNames)
+ throws RepositoryException {
+ for (String propName : propNames) {
+ String propPath = String.format("%s/%s", rootPath, propName);
+ assertPropertyExists(propPath);
+ }
+ }
+
+ private void assertPropertiesMissg(String rootPath, String ... propNames)
+ throws RepositoryException {
+ for (String propName : propNames) {
+ String propPath = String.format("%s/%s", rootPath, propName);
+ assertPropertyMissing(propPath);
+ }
+ }
+
+}
\ No newline at end of file
diff --git vault-core/src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/items.xml vault-core/src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/items.xml
new file mode 100644
index 0000000..361a4f1
--- /dev/null
+++ vault-core/src/test/resources/org/apache/jackrabbit/vault/fs/filter/workspacefilters/items.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+