You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by en...@apache.org on 2022/09/10 19:42:21 UTC

[sling-org-apache-sling-jcr-repoinit] branch master updated: SLING-11571 repoinit: allow add or remove mixin types (#36)

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

enorman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-repoinit.git


The following commit(s) were added to refs/heads/master by this push:
     new f7361d4  SLING-11571 repoinit: allow add or remove mixin types (#36)
f7361d4 is described below

commit f7361d46183b21acaa0a2e54bad6d401c6d43287
Author: Eric Norman <en...@apache.org>
AuthorDate: Sat Sep 10 12:42:16 2022 -0700

    SLING-11571 repoinit: allow add or remove mixin types (#36)
---
 bnd.bnd                                            |   2 +-
 pom.xml                                            |   2 +-
 .../apache/sling/jcr/repoinit/impl/AclVisitor.java |  54 ++++++++-
 .../sling/jcr/repoinit/impl/DoNothingVisitor.java  |  13 ++
 .../org/apache/sling/jcr/repoinit/MixinsTest.java  | 131 +++++++++++++++++++++
 5 files changed, 199 insertions(+), 3 deletions(-)

diff --git a/bnd.bnd b/bnd.bnd
index e49236d..7b85d6c 100644
--- a/bnd.bnd
+++ b/bnd.bnd
@@ -3,4 +3,4 @@ Import-Package:\
   org.apache.jackrabbit.oak.spi.security.principal;version="[1.5,3)",\
   *
 Provide-Capability: osgi.implementation;osgi.implementation="org.apache.sling.jcr.repoinit";version:Version="8.1"
-Require-Capability: org.apache.sling.repoinit.language;filter:="(version>=8.5)"
+Require-Capability: org.apache.sling.repoinit.language;filter:="(version>=8.6)"
diff --git a/pom.xml b/pom.xml
index b1a7aea..7af451e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -225,7 +225,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.repoinit.parser</artifactId>
-            <version>1.7.0</version>
+            <version>1.7.1-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java b/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java
index 705edf7..09e0293 100644
--- a/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java
+++ b/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java
@@ -29,6 +29,7 @@ import javax.jcr.Session;
 import javax.jcr.nodetype.ConstraintViolationException;
 
 import org.apache.sling.repoinit.parser.operations.AclLine;
+import org.apache.sling.repoinit.parser.operations.AddMixins;
 import org.apache.sling.repoinit.parser.operations.CreatePath;
 import org.apache.sling.repoinit.parser.operations.DeleteAclPrincipalBased;
 import org.apache.sling.repoinit.parser.operations.DeleteAclPrincipals;
@@ -38,6 +39,7 @@ import org.apache.sling.repoinit.parser.operations.DeleteAclPaths;
 import org.apache.sling.repoinit.parser.operations.RemoveAcePaths;
 import org.apache.sling.repoinit.parser.operations.RemoveAcePrincipalBased;
 import org.apache.sling.repoinit.parser.operations.RemoveAcePrincipals;
+import org.apache.sling.repoinit.parser.operations.RemoveMixins;
 import org.apache.sling.repoinit.parser.operations.RestrictionClause;
 import org.apache.sling.repoinit.parser.operations.SetAclPaths;
 import org.apache.sling.repoinit.parser.operations.SetAclPrincipalBased;
@@ -217,7 +219,57 @@ class AclVisitor extends DoNothingVisitor {
             report(e, "Session.save failed: " + e);
         }
     }
-    
+
+    @Override
+    public void visitAddMixins(AddMixins am) {
+        List<String> paths = am.getPaths();
+        if (paths != null) {
+            for (String absPath : paths) {
+                try {
+                    if (!session.itemExists(absPath)) {
+                        log.warn("Path does not exist, not adding mixins: {}", absPath);
+                    } else {
+                        List<String> mixins = am.getMixins();
+                        if (mixins != null) {
+                            Node node = session.getNode(absPath);
+                            log.info("Adding mixins {} to node {}", mixins, absPath);
+                            for (String mixin : mixins) {
+                                node.addMixin(mixin);
+                            }
+                        }
+                    }
+                } catch (Exception e) {
+                    report(e, "AddMixins execution failed at " + absPath + ": " + e);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void visitRemoveMixins(RemoveMixins rm) {
+        List<String> paths = rm.getPaths();
+        if (paths != null) {
+            for (String absPath : paths) {
+                try {
+                    if (!session.itemExists(absPath)) {
+                        log.warn("Path does not exist, not removing mixins: {}", absPath);
+                    } else {
+                        List<String> mixins = rm.getMixins();
+                        if (mixins != null) {
+                            Node node = session.getNode(absPath);
+                            log.info("Removing mixins {} from node {}", mixins, absPath);
+                            for (String mixin : mixins) {
+                                node.removeMixin(mixin);
+                            }
+                        }
+                    }
+                } catch (Exception e) {
+                    report(e, "RemoveMixins execution failed at " + absPath + ": " + e);
+                }
+            }
+        }
+    }
+
     @NotNull
     private static Node addChildNode(@NotNull Node parent, @NotNull PathSegmentDefinition psd) throws RepositoryException {
         String primaryType = psd.getPrimaryType();
diff --git a/src/main/java/org/apache/sling/jcr/repoinit/impl/DoNothingVisitor.java b/src/main/java/org/apache/sling/jcr/repoinit/impl/DoNothingVisitor.java
index 18ae6fa..4594130 100644
--- a/src/main/java/org/apache/sling/jcr/repoinit/impl/DoNothingVisitor.java
+++ b/src/main/java/org/apache/sling/jcr/repoinit/impl/DoNothingVisitor.java
@@ -19,6 +19,7 @@ package org.apache.sling.jcr.repoinit.impl;
 import javax.jcr.Session;
 
 import org.apache.sling.repoinit.parser.operations.AddGroupMembers;
+import org.apache.sling.repoinit.parser.operations.AddMixins;
 import org.apache.sling.repoinit.parser.operations.CreateGroup;
 import org.apache.sling.repoinit.parser.operations.CreatePath;
 import org.apache.sling.repoinit.parser.operations.CreateServiceUser;
@@ -38,6 +39,7 @@ import org.apache.sling.repoinit.parser.operations.RemoveAcePaths;
 import org.apache.sling.repoinit.parser.operations.RemoveAcePrincipalBased;
 import org.apache.sling.repoinit.parser.operations.RemoveAcePrincipals;
 import org.apache.sling.repoinit.parser.operations.RemoveGroupMembers;
+import org.apache.sling.repoinit.parser.operations.RemoveMixins;
 import org.apache.sling.repoinit.parser.operations.SetAclPaths;
 import org.apache.sling.repoinit.parser.operations.SetAclPrincipalBased;
 import org.apache.sling.repoinit.parser.operations.SetAclPrincipals;
@@ -192,4 +194,15 @@ class DoNothingVisitor implements OperationVisitor {
     public void visitSetProperties(SetProperties sp) {
         // no-op
     }
+
+    @Override
+    public void visitAddMixins(AddMixins s) {
+        // no-op
+    }
+
+    @Override
+    public void visitRemoveMixins(RemoveMixins s) {
+        // no-op
+    }
+
 }
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/MixinsTest.java b/src/test/java/org/apache/sling/jcr/repoinit/MixinsTest.java
new file mode 100644
index 0000000..9137493
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/repoinit/MixinsTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.sling.jcr.repoinit;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+
+import org.apache.sling.jcr.repoinit.impl.TestUtil;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/** Test the creation of paths with specific node types */
+public class MixinsTest {
+
+    @Rule
+    public final SlingContext context = new SlingContext(ResourceResolverType.JCR_OAK);
+    
+    private TestUtil U;
+
+    @Before
+    public void setup() throws RepositoryException, IOException {
+        U = new TestUtil(context);
+    }
+
+    @Test
+    public void addOneMixinOnOnePath() throws Exception {
+        U.parseAndExecute("create path /addOneMixinOnOnePath(nt:unstructured)");
+        U.assertNodeExists("/addOneMixinOnOnePath", "nt:unstructured", Collections.emptyList());
+
+        U.parseAndExecute("add mixin mix:lockable to /addOneMixinOnOnePath");
+        U.assertNodeExists("/addOneMixinOnOnePath", "nt:unstructured", Collections.singletonList("mix:lockable"));
+    }
+
+    @Test
+    public void addTwoMixinsOnTwoPaths() throws Exception {
+        U.parseAndExecute("create path /addTwoMixinsOnOnePath1(nt:unstructured)\n"
+                + "create path /addTwoMixinsOnOnePath2(nt:unstructured)");
+        U.assertNodeExists("/addTwoMixinsOnOnePath1", "nt:unstructured", Collections.emptyList());
+        U.assertNodeExists("/addTwoMixinsOnOnePath1", "nt:unstructured", Collections.emptyList());
+
+        U.parseAndExecute("add mixin mix:lockable,mix:referenceable to /addTwoMixinsOnOnePath1,/addTwoMixinsOnOnePath2");
+        U.assertNodeExists("/addTwoMixinsOnOnePath1", "nt:unstructured", Arrays.asList("mix:lockable","mix:referenceable"));
+        U.assertNodeExists("/addTwoMixinsOnOnePath1", "nt:unstructured", Arrays.asList("mix:lockable","mix:referenceable"));
+    }
+
+    @Test
+    public void removeOneMixinFromOnePath() throws Exception {
+        U.parseAndExecute("create path /removeOneMixinOnOnePath(nt:unstructured mixin mix:lockable)");
+        U.assertNodeExists("/removeOneMixinOnOnePath", "nt:unstructured", Collections.singletonList("mix:lockable"));
+
+        U.parseAndExecute("remove mixin mix:lockable from /removeOneMixinOnOnePath");
+        U.assertNodeExists("/removeOneMixinOnOnePath", "nt:unstructured", Collections.emptyList());
+    }
+
+    @Test
+    public void removeTwoMixinsFromTwoPaths() throws Exception {
+        U.parseAndExecute("create path /removeTwoMixinsOnOnePath1(nt:unstructured mixin mix:lockable,mix:referenceable)\n"
+                + "create path /removeTwoMixinsOnOnePath2(nt:unstructured mixin mix:lockable,mix:referenceable)");
+        U.assertNodeExists("/removeTwoMixinsOnOnePath1", "nt:unstructured", Arrays.asList("mix:lockable","mix:referenceable"));
+        U.assertNodeExists("/removeTwoMixinsOnOnePath2", "nt:unstructured", Arrays.asList("mix:lockable","mix:referenceable"));
+
+        U.parseAndExecute("remove mixin mix:lockable,mix:referenceable from /removeTwoMixinsOnOnePath1,/removeTwoMixinsOnOnePath2");
+        U.assertNodeExists("/removeTwoMixinsOnOnePath1", "nt:unstructured", Collections.emptyList());
+        U.assertNodeExists("/removeTwoMixinsOnOnePath2", "nt:unstructured", Collections.emptyList());
+    }
+
+    @Test
+    public void addMixinOnNotExistingPath() throws Exception {
+        // this should just log a warning and continue
+        U.parseAndExecute("add mixin mix:lockable to /addMixinOnNotExistingPath");
+        assertNodeNotExists("/addMixinOnNotExistingPath");
+    }
+
+    @Test
+    public void removeMixinFromNotExistingPath() throws Exception {
+        // this should just log a warning and continue
+        U.parseAndExecute("remove mixin mix:lockable from /removeMixinFromNotExistingPath");
+        assertNodeNotExists("/removeMixinFromNotExistingPath");
+    }
+
+    @Test
+    public void addNonExistingMixinToPath() throws Exception {
+        U.parseAndExecute("create path /addNonExistingMixinToPath(nt:unstructured)");
+        try {
+            U.parseAndExecute("add mixin mix:invalid to /addNonExistingMixinToPath");
+        } catch (Exception e) {
+            assertTrue("Expected NoSuchNodeTypeException", e.getCause() instanceof NoSuchNodeTypeException);
+        }
+    }
+
+    @Test
+    public void removeNonExistingMixinFromPath() throws Exception {
+        U.parseAndExecute("create path /removeNonExistingMixinFromPath(nt:unstructured)");
+        try {
+            U.parseAndExecute("remove mixin mix:invalid from /removeNonExistingMixinFromPath");
+        } catch (Exception e) {
+            assertTrue("Expected NoSuchNodeTypeException", e.getCause() instanceof NoSuchNodeTypeException);
+        }
+    }
+
+    protected void assertNodeNotExists(String path) throws RepositoryException {
+        Session adminSession = context.resourceResolver().adaptTo(Session.class);
+        assertFalse("Node should not exist", adminSession.nodeExists(path));
+    }
+
+}