SLING-10741 explicitly manages mixin types and revert previous commit that can be useful for corner array cases
diff --git a/src/main/java/org/apache/sling/pipes/internal/CommandUtil.java b/src/main/java/org/apache/sling/pipes/internal/CommandUtil.java index 2611e12..8de164c 100644 --- a/src/main/java/org/apache/sling/pipes/internal/CommandUtil.java +++ b/src/main/java/org/apache/sling/pipes/internal/CommandUtil.java
@@ -20,12 +20,14 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static org.apache.sling.pipes.PipeBindings.INJECTED_SCRIPT_REGEXP; @@ -37,7 +39,10 @@ static final String KEY_VALUE_SEP = "="; static final String FIRST_TOKEN = "first"; static final String SECOND_TOKEN = "second"; + static final String PN_JCR_MIXIN = "jcr:mixinTypes"; + static final Pattern MIXINS_ARRAY_PATTERN = Pattern.compile("^\\s*\\[(.*)\\]\\s*$"); private static final Pattern UNEMBEDDEDSCRIPT_PATTERN = Pattern.compile("^(\\d+(\\.\\d+)?)|" + //21.42 + "(\\[.*]$)|" + //['one','two'] "(\\w[\\w_\\-\\d]+\\..+)|" + //map.field... "(\\w[\\w_\\-\\d]+\\['.+'])|" + //map['field'] "(true$|false$)|" + //boolean @@ -84,9 +89,22 @@ public static void writeToMap(Map<String, Object> map, boolean embed, Object... params){ for (int i = 0; i < params.length - 1; i += 2) { map.put(params[i].toString(), embed ? embedIfNeeded(params[i + 1]) : params[i + 1]); + if (params[i].toString().equals(PN_JCR_MIXIN)) { + map.put(PN_JCR_MIXIN, handleMixins((String)params[i + 1])); + } } } + static String[] handleMixins(String value) { + Matcher matcher = MIXINS_ARRAY_PATTERN.matcher(value); + if (matcher.matches()) { + return Arrays.stream(matcher.group(1).split(PAIR_SEP)) + .map(String::trim) + .collect(Collectors.toList()).toArray(new String[0]); + } + return new String[] { value }; + } + /** * @param input comma separated key=value pairs * @param valueTransformer before adding it to the map, that function will be applied to found value
diff --git a/src/test/java/org/apache/sling/pipes/internal/CommandUtilTest.java b/src/test/java/org/apache/sling/pipes/internal/CommandUtilTest.java index 870a3b8..08dba0b 100644 --- a/src/test/java/org/apache/sling/pipes/internal/CommandUtilTest.java +++ b/src/test/java/org/apache/sling/pipes/internal/CommandUtilTest.java
@@ -17,6 +17,11 @@ package org.apache.sling.pipes.internal; import junit.framework.TestCase; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; import org.junit.Test; public class CommandUtilTest extends TestCase { @@ -32,6 +37,24 @@ assertEquals("${some + wellformed + script}", CommandUtil.embedIfNeeded("${some + wellformed + script}")); assertEquals("${true}", CommandUtil.embedIfNeeded("true")); assertEquals("${'some string'}", CommandUtil.embedIfNeeded("'some string'")); - assertEquals("['one','two']", CommandUtil.embedIfNeeded("['one','two']")); + assertEquals("${['one','two']}", CommandUtil.embedIfNeeded("['one','two']")); + } + + @Test + public void testHandleMixin() { + String[] expected = new String[] {"rep:versionable", "rep:AccessControllable"}; + Assert.assertArrayEquals(expected, CommandUtil.handleMixins("[ rep:versionable, rep:AccessControllable]")); + Assert.assertArrayEquals(expected, CommandUtil.handleMixins("[rep:versionable,rep:AccessControllable]")); + } + + @Test + public void testWriteToMap() { + Map<String, Object> map = new HashMap<>(); + CommandUtil.writeToMap(map, true, "p1", "'some string'", "p2", "/some/path", + "p3","['one','two']", "jcr:mixinTypes", "[ rep:versionable, some:OtherMixin]"); + assertEquals("${'some string'}", map.get("p1")); + assertEquals("/some/path", map.get("p2")); + assertEquals("${['one','two']}", map.get("p3")); + Assert.assertArrayEquals(new String [] {"rep:versionable", "some:OtherMixin"}, (String[])map.get("jcr:mixinTypes")); } } \ No newline at end of file
diff --git a/src/test/java/org/apache/sling/pipes/internal/JCRWritePipeTest.java b/src/test/java/org/apache/sling/pipes/internal/JCRWritePipeTest.java new file mode 100644 index 0000000..028e545 --- /dev/null +++ b/src/test/java/org/apache/sling/pipes/internal/JCRWritePipeTest.java
@@ -0,0 +1,74 @@ +/* + * 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.pipes.internal; + +import static org.apache.sling.testing.mock.caconfig.ContextPlugins.CACONFIG; +import static org.junit.Assert.assertEquals; + +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.Collection; +import java.util.stream.Collectors; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.nodetype.NodeType; + +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.pipes.AbstractPipeTest; +import org.apache.sling.testing.mock.sling.ResourceResolverType; +import org.apache.sling.testing.mock.sling.junit.SlingContext; +import org.apache.sling.testing.mock.sling.junit.SlingContextBuilder; +import org.codehaus.plexus.util.CollectionUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +public class JCRWritePipeTest extends AbstractPipeTest { + + @Rule + public SlingContext jcrContext = new SlingContextBuilder(ResourceResolverType.JCR_OAK).plugin(CACONFIG).build(); + + @Before + public void setup() throws PersistenceException { + context = jcrContext; + super.setup(); + } + + void assertMixinTypesEquals(String path, String... mixins) throws RepositoryException { + String[] m = mixins != null ? mixins : new String[0]; + Resource resource = context.resourceResolver().getResource(path); + Node node = resource.adaptTo(Node.class); + Collection<String> intersection = CollectionUtils.intersection(Arrays.asList(m), + Arrays.stream(node.getMixinNodeTypes()) + .map(NodeType::getName) + .collect(Collectors.toList())); + assertEquals(m.length, intersection.size()); + } + + @Test + public void testMixins() throws InvocationTargetException, IllegalAccessException, RepositoryException { + execute("mkdir /content/typed"); + assertMixinTypesEquals("/content/typed"); + execute("echo /content/typed | write jcr:mixinTypes=[sling:HierarchyNode,sling:Resource]"); + assertMixinTypesEquals("/content/typed","sling:HierarchyNode", "sling:Resource"); + execute("echo /content/typed | write jcr:mixinTypes=[sling:Resource]"); + assertMixinTypesEquals("/content/typed", "sling:Resource"); + } +}