You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by kw...@apache.org on 2021/04/08 07:10:17 UTC

[jackrabbit-filevault] branch master updated: JCRVLT-514 (de-)serialize property filters in JcrWorkspaceFilter (#133)

This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git


The following commit(s) were added to refs/heads/master by this push:
     new e730ef9  JCRVLT-514 (de-)serialize property filters in JcrWorkspaceFilter (#133)
e730ef9 is described below

commit e730ef9c999ac69b477675cd2671ff6ab5167d4d
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Thu Apr 8 09:10:11 2021 +0200

    JCRVLT-514 (de-)serialize property filters in JcrWorkspaceFilter (#133)
---
 .../apache/jackrabbit/vault/fs/api/FilterSet.java  |   6 +-
 .../vault/fs/config/DefaultWorkspaceFilter.java    |  11 +-
 .../vault/packaging/JcrPackageDefinition.java      |   7 +-
 .../vault/packaging/impl/JcrWorkspaceFilter.java   | 128 +++++++++++++++------
 .../jackrabbit/vault/packaging/package-info.java   |   2 +-
 .../vault/packaging/impl/JcrWorkspaceFilterIT.java |  55 +++++++++
 6 files changed, 165 insertions(+), 44 deletions(-)

diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/api/FilterSet.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/api/FilterSet.java
index eea59e3..8d8994e 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/api/FilterSet.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/api/FilterSet.java
@@ -252,11 +252,11 @@ public abstract class FilterSet<E extends Filter> implements Dumpable {
      */
     @Override
     public void dump(@NotNull DumpContext ctx, boolean isLast) {
-        ctx.printf(false, "root: %s", getRoot());
+        ctx.printf(false, "root: %s, mode %s", getRoot(), getImportMode());
         if (entries != null) {
             Iterator<Entry<E>> iter = entries.iterator();
             while (iter.hasNext()) {
-                Entry e = iter.next();
+                Entry<E> e = iter.next();
                 e.dump(ctx, !iter.hasNext());
             }
         }
@@ -280,7 +280,7 @@ public abstract class FilterSet<E extends Filter> implements Dumpable {
         if (this == o) return true;
         if (!(o instanceof FilterSet)) return false;
 
-        FilterSet filterSet = (FilterSet) o;
+        FilterSet<E> filterSet = (FilterSet<E>) o;
         if (entries != null ? !entries.equals(filterSet.entries) : filterSet.entries != null) return false;
         return root.equals(filterSet.root);
 
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/DefaultWorkspaceFilter.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/DefaultWorkspaceFilter.java
index 2832e2c..02047e0 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/DefaultWorkspaceFilter.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/config/DefaultWorkspaceFilter.java
@@ -488,7 +488,16 @@ public class DefaultWorkspaceFilter implements Dumpable, WorkspaceFilter {
         Iterator<PathFilterSet> iter = nodesFilterSets.iterator();
         while (iter.hasNext()) {
             PathFilterSet set = iter.next();
-            ctx.println(!iter.hasNext(), "ItemFilterSet");
+            ctx.println(!iter.hasNext(), "NodeFilterSet");
+            ctx.indent(!iter.hasNext());
+            set.dump(ctx, false);
+            ctx.outdent();
+        }
+        
+        iter = propsFilterSets.iterator();
+        while (iter.hasNext()) {
+            PathFilterSet set = iter.next();
+            ctx.println(!iter.hasNext(), "PropertyFilterSet");
             ctx.indent(!iter.hasNext());
             set.dump(ctx, false);
             ctx.outdent();
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/JcrPackageDefinition.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/JcrPackageDefinition.java
index 3c157e7..6ee6b87 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/JcrPackageDefinition.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/JcrPackageDefinition.java
@@ -162,11 +162,16 @@ public interface JcrPackageDefinition extends PackageProperties {
     String PN_MODE = "mode";
 
     /**
-     * Property name of the filter rules
+     * Property name of the path filter rules
      */
     String PN_RULES = "rules";
 
     /**
+     * Property name of the property filter rules
+     */
+    String PN_PROPERTY_RULES = "propertyRules";
+
+    /**
      * Property name of the rule type
      */
     String PN_TYPE = "type";
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrWorkspaceFilter.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrWorkspaceFilter.java
index 9f15ed1..1919706 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrWorkspaceFilter.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrWorkspaceFilter.java
@@ -25,9 +25,14 @@ import javax.jcr.NodeIterator;
 import javax.jcr.Property;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.version.VersionException;
 
+import org.apache.jackrabbit.vault.fs.api.FilterSet;
 import org.apache.jackrabbit.vault.fs.api.ImportMode;
-import org.apache.jackrabbit.vault.fs.api.ItemFilterSet;
+import org.apache.jackrabbit.vault.fs.api.PathFilter;
 import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
 import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
 import org.apache.jackrabbit.vault.fs.config.ConfigurationException;
@@ -53,35 +58,31 @@ public class JcrWorkspaceFilter  {
             if (root.length() == 0) {
                 continue;
             }
+            boolean isPropertyFilter = false;
+            if (filter.getName().startsWith("p")) {
+                isPropertyFilter = true;
+            }
             String mode = filter.hasProperty(JcrPackageDefinitionImpl.PN_MODE)
                     ? filter.getProperty(JcrPackageDefinitionImpl.PN_MODE).getString()
                     : "";
             PathFilterSet set = new PathFilterSet(root);
+            PathFilterSet propertySet = new PathFilterSet(root);
             if (mode.length() > 0) {
                 set.setImportMode(ImportMode.valueOf(mode.toUpperCase()));
+                propertySet.setImportMode(ImportMode.valueOf(mode.toUpperCase()));
             }
+            
             if (filter.hasProperty(JcrPackageDefinitionImpl.PN_RULES)) {
-                // new version with mv rules property
-                Property p = filter.getProperty(JcrPackageDefinitionImpl.PN_RULES);
-                Value[] values = p.getDefinition().isMultiple() ? p.getValues() : new Value[]{p.getValue()};
-                for (Value value: values) {
-                    String rule = value.getString();
-                    int idx = rule.indexOf(':');
-                    String type = idx > 0 ? rule.substring(0, idx) : "include";
-                    String patt = idx > 0 ? rule.substring(idx + 1) : "";
-                    DefaultPathFilter pf;
-                    try {
-                        pf = new DefaultPathFilter(patt);
-                    } catch (ConfigurationException e) {
-                        throw new RepositoryException("Can not load filter from node " + defNode.getPath(), e);
-                    }
-                    if ("include".equals(type)) {
-                        set.addInclude(pf);
-                    } else {
-                        set.addExclude(pf);
+                try {
+                    loadRules(set, filter, JcrPackageDefinitionImpl.PN_RULES);
+                    if (!loadRules(propertySet, filter, JcrPackageDefinitionImpl.PN_PROPERTY_RULES)) {
+                        propertySet = null;
                     }
+                } catch (ConfigurationException e) {
+                    throw new RepositoryException("Can not load filter from node " + defNode.getPath(), e);
                 }
             } else {
+                // this is the legacy format
                 for (NodeIterator rules = filter.getNodes(); rules.hasNext();) {
                     Node rule = rules.nextNode();
                     String type = rule.getProperty(JcrPackageDefinitionImpl.PN_TYPE).getString();
@@ -98,12 +99,40 @@ public class JcrWorkspaceFilter  {
                         set.addExclude(pf);
                     }
                 }
+                propertySet = null;
+            }
+            if (propertySet != null) {
+                wsp.add(set, propertySet);
+            } else {
+                wsp.add(set);
             }
-            wsp.add(set);
         }
         return wsp;
     }
 
+    private static boolean loadRules(PathFilterSet set, Node filterNode, String propertyName) throws ConfigurationException, RepositoryException {
+        if (!filterNode.hasProperty(propertyName)) {
+            return false;
+        }
+        Property p = filterNode.getProperty(propertyName);
+        Value[] values = p.getDefinition().isMultiple() ? p.getValues() : new Value[]{p.getValue()};
+        for (Value value: values) {
+            String rule = value.getString();
+            int idx = rule.indexOf(':');
+            String type = idx > 0 ? rule.substring(0, idx) : "include";
+            String patt = idx > 0 ? rule.substring(idx + 1) : "";
+            DefaultPathFilter pf = new DefaultPathFilter(patt);
+            
+            if ("include".equals(type)) {
+                set.addInclude(pf);
+            } else {
+                set.addExclude(pf);
+            }
+        }
+        return true;
+    }
+
+    @Deprecated
     public static void saveLegacyFilter(WorkspaceFilter filter, Node defNode, boolean save)
             throws RepositoryException {
         // delete all nodes first
@@ -115,7 +144,7 @@ public class JcrWorkspaceFilter  {
             Node setNode = defNode.addNode("f" + nr);
             setNode.setProperty(JcrPackageDefinitionImpl.PN_ROOT, set.getRoot());
             int eNr = 0;
-            for (ItemFilterSet.Entry e: set.getEntries()) {
+            for (FilterSet.Entry<PathFilter> e: set.getEntries()) {
                 // expect path filter
                 if (!(e.getFilter() instanceof DefaultPathFilter)) {
                     throw new IllegalArgumentException("Can only handle default path filters.");
@@ -139,28 +168,51 @@ public class JcrWorkspaceFilter  {
             defNode.getNode(JcrPackageDefinitionImpl.NN_FILTER).remove();
         }
         Node filterNode = defNode.addNode(JcrPackageDefinitionImpl.NN_FILTER);
-        int nr = 0;
-        for (PathFilterSet set: filter.getFilterSets()) {
-            Node setNode = filterNode.addNode("f" + nr);
+        savePathFilterSet(filter.getFilterSets(), filter.getPropertyFilterSets(), filterNode);
+        
+        if (save) {
+            defNode.getSession().save();
+        }
+    }
+
+
+    private static void savePathFilterSet(List<PathFilterSet> pathFilterSets, List<PathFilterSet> propertyFilterSets, Node filterNode) throws RepositoryException {
+        int no = 0;
+        for (PathFilterSet set: pathFilterSets) {
+            Node setNode = filterNode.addNode("f" + no);
             setNode.setProperty(JcrPackageDefinitionImpl.PN_ROOT, set.getRoot());
             setNode.setProperty(JcrPackageDefinitionImpl.PN_MODE, set.getImportMode().name().toLowerCase());
-            List<String> rules = new LinkedList<String>();
-            for (ItemFilterSet.Entry e: set.getEntries()) {
-                // expect path filter
-                if (!(e.getFilter() instanceof DefaultPathFilter)) {
-                    throw new IllegalArgumentException("Can only handle default path filters.");
-                }
-                String type = e.isInclude() ? "include" : "exclude";
-                String patt = ((DefaultPathFilter) e.getFilter()).getPattern();
-                rules.add(type + ":" + patt);
+            
+            saveRules(setNode, set.getEntries(), JcrPackageDefinitionImpl.PN_RULES);
+            // find property filter for same root
+            PathFilterSet propertyFilterSet = getSetForRoot(propertyFilterSets, set.getRoot());
+            if (propertyFilterSet != null) {
+                saveRules(setNode, propertyFilterSet.getEntries(), JcrPackageDefinitionImpl.PN_PROPERTY_RULES);
             }
-            setNode.setProperty(JcrPackageDefinitionImpl.PN_RULES, rules.toArray(new String[rules.size()]));
-            nr++;
-        }
-        if (save) {
-            defNode.getSession().save();
+            no++;
         }
     }
 
+    private static PathFilterSet getSetForRoot(List<PathFilterSet> filterSets, String root) {
+        for (PathFilterSet set : filterSets) {
+            if (set.getRoot().equals(root)) {
+                return set;
+            }
+        }
+        return null;
+    }
 
+    private static void saveRules(Node setNode, List<FilterSet.Entry<PathFilter>> entries, String propertyName) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
+        List<String> rules = new LinkedList<>();
+        for (FilterSet.Entry<PathFilter> e: entries) {
+            // expect path filter
+            if (!(e.getFilter() instanceof DefaultPathFilter)) {
+                throw new IllegalArgumentException("Can only handle default path filters.");
+            }
+            String type = e.isInclude() ? "include" : "exclude";
+            String patt = ((DefaultPathFilter) e.getFilter()).getPattern();
+            rules.add(type + ":" + patt);
+        }
+        setNode.setProperty(propertyName, rules.toArray(new String[rules.size()]));
+    }
 }
\ No newline at end of file
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/package-info.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/package-info.java
index 8ba3eea..0c8c0f8 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/package-info.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/package-info.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-@Version("2.12.0")
+@Version("2.13.0")
 package org.apache.jackrabbit.vault.packaging;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/impl/JcrWorkspaceFilterIT.java b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/impl/JcrWorkspaceFilterIT.java
new file mode 100644
index 0000000..74d0d43
--- /dev/null
+++ b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/impl/JcrWorkspaceFilterIT.java
@@ -0,0 +1,55 @@
+/*
+ * 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.impl;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.commons.JcrUtils;
+import org.apache.jackrabbit.vault.fs.api.ImportMode;
+import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
+import org.apache.jackrabbit.vault.fs.config.ConfigurationException;
+import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
+import org.apache.jackrabbit.vault.fs.filter.DefaultPathFilter;
+import org.apache.jackrabbit.vault.packaging.integration.IntegrationTestBase;
+import org.junit.Assert;
+import org.junit.Test;
+
+
+public class JcrWorkspaceFilterIT extends IntegrationTestBase {
+
+    @Test
+    public void testComplexFilterRoundtrip() throws RepositoryException, ConfigurationException {
+        DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+        PathFilterSet pathFilterSet = new PathFilterSet("/my/root");
+        pathFilterSet.setImportMode(ImportMode.MERGE);
+        pathFilterSet.setType("cleanup");
+        pathFilterSet.addInclude(new DefaultPathFilter("/my/root/include.*"));
+        pathFilterSet.addExclude(new DefaultPathFilter("/my/root/exclude.*"));
+        
+        PathFilterSet propertyFilterSet = new PathFilterSet("/my/root");
+        propertyFilterSet.setImportMode(ImportMode.MERGE);
+        propertyFilterSet.setType("cleanup");
+        propertyFilterSet.addInclude(new DefaultPathFilter("/my/root/myprops.*"));
+        propertyFilterSet.addExclude(new DefaultPathFilter("/my/root/notmyprops.*"));
+        filter.add(pathFilterSet, propertyFilterSet);
+        Node defNode = JcrUtils.getOrCreateByPath("/etc/packages/mypackage/jcr:content/vlt:definition", "vlt:PackageDefinition", admin);
+        JcrWorkspaceFilter.saveFilter(filter, defNode, false);
+        Assert.assertEquals(filter, JcrWorkspaceFilter.loadFilter(defNode));
+    }
+    
+}