Author: tmaret Date: Fri Sep 15 08:27:58 2017 New Revision: 1808431 URL: http://svn.apache.org/viewvc?rev=1808431&view=rev Log: SLING-7066 - Support mixins in repoinit "create path" statements
* Add parser support for creating paths with mixins * Add JCR implementation Modified: sling/trunk/bundles/extensions/repoinit/parser/src/main/java/org/apache/sling/repoinit/parser/operations/CreatePath.java sling/trunk/bundles/extensions/repoinit/parser/src/main/java/org/apache/sling/repoinit/parser/operations/PathSegmentDefinition.java sling/trunk/bundles/extensions/repoinit/parser/src/main/javacc/RepoInitGrammar.jjt sling/trunk/bundles/extensions/repoinit/parser/src/test/resources/testcases/test-20-output.txt sling/trunk/bundles/extensions/repoinit/parser/src/test/resources/testcases/test-20.txt sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/CreatePathsTest.java sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/impl/TestUtil.java Modified: sling/trunk/bundles/extensions/repoinit/parser/src/main/java/org/apache/sling/repoinit/parser/operations/CreatePath.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/repoinit/parser/src/main/java/org/apache/sling/repoinit/parser/operations/CreatePath.java?rev=1808431&r1=1808430&r2=1808431&view=diff ============================================================================== --- sling/trunk/bundles/extensions/repoinit/parser/src/main/java/org/apache/sling/repoinit/parser/operations/CreatePath.java (original) +++ sling/trunk/bundles/extensions/repoinit/parser/src/main/java/org/apache/sling/repoinit/parser/operations/CreatePath.java Fri Sep 15 08:27:58 2017 @@ -44,8 +44,12 @@ public class CreatePath extends Operatio public void accept(OperationVisitor v) { v.visitCreatePath(this); } - + public void addSegment(String path, String primaryType) { + addSegment(path, primaryType, null); + } + + public void addSegment(String path, String primaryType, List<String> mixins) { // We might get a path like /var/discovery, in which case // the specified primary type applies to the last // segment only @@ -55,10 +59,16 @@ public class CreatePath extends Operatio continue; } String pt = defaultPrimaryType; - if(i == segments.length -1 && primaryType != null) { - pt = primaryType; + List<String> ms = null; + if(i == segments.length -1) { + if (primaryType != null) { + pt = primaryType; + } + if (mixins != null && ! mixins.isEmpty()) { + ms = mixins; + } } - pathDef.add(new PathSegmentDefinition(segments[i], pt)); + pathDef.add(new PathSegmentDefinition(segments[i], pt, ms)); } } Modified: sling/trunk/bundles/extensions/repoinit/parser/src/main/java/org/apache/sling/repoinit/parser/operations/PathSegmentDefinition.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/repoinit/parser/src/main/java/org/apache/sling/repoinit/parser/operations/PathSegmentDefinition.java?rev=1808431&r1=1808430&r2=1808431&view=diff ============================================================================== --- sling/trunk/bundles/extensions/repoinit/parser/src/main/java/org/apache/sling/repoinit/parser/operations/PathSegmentDefinition.java (original) +++ sling/trunk/bundles/extensions/repoinit/parser/src/main/java/org/apache/sling/repoinit/parser/operations/PathSegmentDefinition.java Fri Sep 15 08:27:58 2017 @@ -17,23 +17,44 @@ package org.apache.sling.repoinit.parser.operations; -/** Defines a segment of a path to be created, - * with its name and an optional primary type +import java.util.List; + +/** Defines a segment of a path to be created, + * with its name and an optional primary type and optional mixins */ public class PathSegmentDefinition { private final String segment; private final String primaryType; + private final List<String> mixins; public PathSegmentDefinition(String segment, String primaryType) { + this(segment, primaryType, null); + } + + public PathSegmentDefinition(String segment, String primaryType, List<String> mixins) { this.segment = segment; this.primaryType = primaryType; + this.mixins = mixins; } public String toString() { final StringBuilder sb = new StringBuilder(); sb.append(segment); - if(primaryType != null) { - sb.append("(").append(primaryType).append(")"); + boolean hasPrimaryType = primaryType != null; + boolean hasMixin = mixins != null && ! mixins.isEmpty(); + if (hasPrimaryType || hasMixin) { + sb.append("("); + if (hasPrimaryType) { + sb.append(primaryType); + } + if (hasPrimaryType && hasMixin) { + sb.append(" "); + } + if (hasMixin) { + sb.append("mixin "); + sb.append(mixins.toString()); + } + sb.append(")"); } return sb.toString(); } @@ -45,4 +66,8 @@ public class PathSegmentDefinition { public String getPrimaryType() { return primaryType; } + + public List<String> getMixins() { + return mixins; + } } Modified: sling/trunk/bundles/extensions/repoinit/parser/src/main/javacc/RepoInitGrammar.jjt URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/repoinit/parser/src/main/javacc/RepoInitGrammar.jjt?rev=1808431&r1=1808430&r2=1808431&view=diff ============================================================================== --- sling/trunk/bundles/extensions/repoinit/parser/src/main/javacc/RepoInitGrammar.jjt (original) +++ sling/trunk/bundles/extensions/repoinit/parser/src/main/javacc/RepoInitGrammar.jjt Fri Sep 15 08:27:58 2017 @@ -65,6 +65,7 @@ TOKEN: | < DELETE: "delete" > | < DISABLE: "disable" > | < SERVICE: "service" > +| < MIXIN: "mixin" > | < PATH: "path" > | < END: "end" > | < USER: "user" > @@ -207,18 +208,22 @@ void createPathStatement(List<Operation> String defaultPrimaryType = null; Token t1 = null; Token t2 = null; + List<String> t3 = null; } { <CREATE> <PATH> ( <LPAREN> t1 = <NAMESPACED_ITEM> <RPAREN> { defaultPrimaryType = t1.image; } ) ? ( t1 = <PATH_STRING> ( <LPAREN> t2 = <NAMESPACED_ITEM> <RPAREN> ) ? + ( <LPAREN> <MIXIN> t3 = namespacedItemsList() <RPAREN>) ? + ( <LPAREN> t2 = <NAMESPACED_ITEM> <MIXIN> t3 = namespacedItemsList() <RPAREN>) ? { if(cp == null) { cp = new CreatePath(defaultPrimaryType); } - cp.addSegment(t1.image, t2 == null ? null : t2.image); - t2 = null; + cp.addSegment(t1.image, t2 == null ? null : t2.image, t3); + t2 = null; + t3 = null; } ) + Modified: sling/trunk/bundles/extensions/repoinit/parser/src/test/resources/testcases/test-20-output.txt URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/repoinit/parser/src/test/resources/testcases/test-20-output.txt?rev=1808431&r1=1808430&r2=1808431&view=diff ============================================================================== --- sling/trunk/bundles/extensions/repoinit/parser/src/test/resources/testcases/test-20-output.txt (original) +++ sling/trunk/bundles/extensions/repoinit/parser/src/test/resources/testcases/test-20-output.txt Fri Sep 15 08:27:58 2017 @@ -1,4 +1,9 @@ CreatePath [var(sling:Folder), discovery(nt:unstructured), somefolder(sling:Folder)] CreatePath [one, two, three] CreatePath [three, four(nt:folk), five(nt:jazz), six] -CreatePath [seven(nt:x), eight(nt:x), nine(nt:x)] \ No newline at end of file +CreatePath [seven(nt:x), eight(nt:x), nine(nt:x)] +CreatePath [one(mixin [nt:art]), step(mixin [nt:dance]), two, steps] +CreatePath [one(nt:foxtrot), step(nt:foxtrot mixin [nt:dance]), two(nt:foxtrot), steps(nt:foxtrot)] +CreatePath [one, step(mixin [nt:dance, nt:art]), two, steps] +CreatePath [one, step(nt:foxtrot mixin [nt:dance]), two, steps] +CreatePath [one, step(nt:foxtrot mixin [nt:dance, nt:art]), two, steps] \ No newline at end of file Modified: sling/trunk/bundles/extensions/repoinit/parser/src/test/resources/testcases/test-20.txt URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/repoinit/parser/src/test/resources/testcases/test-20.txt?rev=1808431&r1=1808430&r2=1808431&view=diff ============================================================================== --- sling/trunk/bundles/extensions/repoinit/parser/src/test/resources/testcases/test-20.txt (original) +++ sling/trunk/bundles/extensions/repoinit/parser/src/test/resources/testcases/test-20.txt Fri Sep 15 08:27:58 2017 @@ -3,3 +3,8 @@ create path (sling:Folder) /var/discover create path /one/two/three create path /three/four(nt:folk)/five(nt:jazz)/six create path (nt:x) /seven/eight/nine +create path /one(mixin nt:art)/step(mixin nt:dance)/two/steps +create path (nt:foxtrot) /one/step(mixin nt:dance)/two/steps +create path /one/step(mixin nt:dance,nt:art)/two/steps +create path /one/step(nt:foxtrot mixin nt:dance)/two/steps +create path /one/step(nt:foxtrot mixin nt:dance,nt:art)/two/steps \ No newline at end of file Modified: sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java?rev=1808431&r1=1808430&r2=1808431&view=diff ============================================================================== --- sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java (original) +++ sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java Fri Sep 15 08:27:58 2017 @@ -91,9 +91,16 @@ class AclVisitor extends DoNothingVisito if(session.itemExists(fullPath)) { log.info("Path already exists, nothing to do (and not checking its primary type for now): {}", fullPath); } else { - final Node n = parentPath.equals("") ? session.getRootNode() : session.getNode(parentPath); + final Node parent = parentPath.equals("") ? session.getRootNode() : session.getNode(parentPath); log.info("Creating node {} with primary type {}", fullPath, psd.getPrimaryType()); - n.addNode(psd.getSegment(), psd.getPrimaryType()); + Node node = parent.addNode(psd.getSegment(), psd.getPrimaryType()); + List<String> mixins = psd.getMixins(); + if (mixins != null) { + log.info("Adding mixins {} to node {}", mixins, fullPath); + for (String mixin : mixins) { + node.addMixin(mixin); + } + } } } catch(Exception e) { throw new RuntimeException("CreatePath execution failed at " + psd + ": " + e, e); Modified: sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/CreatePathsTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/CreatePathsTest.java?rev=1808431&r1=1808430&r2=1808431&view=diff ============================================================================== --- sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/CreatePathsTest.java (original) +++ sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/CreatePathsTest.java Fri Sep 15 08:27:58 2017 @@ -17,6 +17,8 @@ package org.apache.sling.jcr.repoinit; import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; import javax.jcr.RepositoryException; @@ -75,4 +77,30 @@ public class CreatePathsTest { U.assertNodeExists("/ten/eleven", "sling:Folder"); U.assertNodeExists("/ten/eleven/twelve", "sling:Folder"); } + + @Test + public void createPathWithMixins() throws Exception { + final String path = "/eleven(mixin mix:lockable)/twelve(mixin mix:referenceable,mix:shareable)/thirteen"; + U.parseAndExecute("create path " + path); + U.assertNodeExists("/eleven", Collections.singletonList("mix:lockable")); + U.assertNodeExists("/eleven/twelve", Arrays.asList("mix:shareable", "mix:referenceable")); + } + + @Test + public void createPathWithJcrDefaultTypeAndMixins() throws Exception { + final String path = "/twelve/thirteen(mixin mix:lockable)/fourteen"; + U.parseAndExecute("create path (nt:unstructured)" + path); + U.assertNodeExists("/twelve", "nt:unstructured", Collections.<String>emptyList()); + U.assertNodeExists("/twelve/thirteen", "nt:unstructured", Collections.singletonList("mix:lockable")); + U.assertNodeExists("/twelve/thirteen/fourteen", "nt:unstructured", Collections.<String>emptyList()); + } + + @Test + public void createPathWithJcrTypeAndMixins() throws Exception { + final String path = "/thirteen(nt:unstructured)/fourteen(nt:unstructured mixin mix:lockable)/fifteen(mixin mix:lockable)"; + U.parseAndExecute("create path " + path); + U.assertNodeExists("/thirteen", "nt:unstructured", Collections.<String>emptyList()); + U.assertNodeExists("/thirteen/fourteen", "nt:unstructured", Collections.singletonList("mix:lockable")); + U.assertNodeExists("/thirteen/fourteen/fifteen", "nt:unstructured", Collections.singletonList("mix:lockable")); + } } Modified: sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/impl/TestUtil.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/impl/TestUtil.java?rev=1808431&r1=1808430&r2=1808431&view=diff ============================================================================== --- sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/impl/TestUtil.java (original) +++ sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/impl/TestUtil.java Fri Sep 15 08:27:58 2017 @@ -31,6 +31,7 @@ import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.SimpleCredentials; +import javax.jcr.nodetype.NodeType; import org.apache.commons.io.IOUtils; import org.apache.jackrabbit.api.security.user.Authorizable; @@ -86,10 +87,18 @@ public class TestUtil { } public void assertNodeExists(String path) throws RepositoryException { - assertNodeExists(path, null); + assertNodeExists(path, null, null); } public void assertNodeExists(String path, String primaryType) throws RepositoryException { + assertNodeExists(path, primaryType, null); + } + + public void assertNodeExists(String path, List<String> mixins) throws RepositoryException { + assertNodeExists(path, null, mixins); + } + + public void assertNodeExists(String path, String primaryType, List<String> mixins) throws RepositoryException { if(!adminSession.nodeExists(path)) { fail("Node does not exist:" + path); } @@ -103,6 +112,18 @@ public class TestUtil { fail("Primary type mismatch for " + path + ", expected " + primaryType + " but got " + actual); } } + if (mixins != null) { + final Node n = adminSession.getNode(path); + NodeType[] mixinNodeTypes = n.getMixinNodeTypes(); + if (mixinNodeTypes.length != mixins.size()) { + fail("Number of mixin node types does not match, expected " + mixins.size() + " but got " + mixinNodeTypes.length); + } + for (NodeType mixinNodeType : mixinNodeTypes) { + if (! mixins.contains(mixinNodeType.getName())) { + fail("Node contains the unexpected mixin node type " + mixinNodeType.getName()); + } + } + } } public void parseAndExecute(String input) throws RepositoryException, RepoInitParsingException {