You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by np...@apache.org on 2018/11/23 10:15:37 UTC

[sling-org-apache-sling-pipes] branch master updated: SLING-8130 conditionnal node writes

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

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


The following commit(s) were added to refs/heads/master by this push:
     new d21fbcb  SLING-8130 conditionnal node writes
d21fbcb is described below

commit d21fbcbfb1eeea6252f61fb003bf5fdb4955aa44
Author: Nicolas Peltier <pe...@gmail.com>
AuthorDate: Fri Nov 23 11:14:51 2018 +0100

    SLING-8130 conditionnal node writes
    
    introducing the  syntax that can be persisted in a write tree configuration
---
 .../java/org/apache/sling/pipes/PipeBindings.java  | 40 ++++++++++++++++------
 .../java/org/apache/sling/pipes/PipeBuilder.java   |  4 +--
 .../org/apache/sling/pipes/internal/WritePipe.java | 16 +++++----
 .../apache/sling/pipes/internal/WritePipeTest.java | 30 ++++++++++++++++
 src/test/resources/write.json                      | 11 ++++++
 5 files changed, 82 insertions(+), 19 deletions(-)

diff --git a/src/main/java/org/apache/sling/pipes/PipeBindings.java b/src/main/java/org/apache/sling/pipes/PipeBindings.java
index 850c3a7..bba4728 100644
--- a/src/main/java/org/apache/sling/pipes/PipeBindings.java
+++ b/src/main/java/org/apache/sling/pipes/PipeBindings.java
@@ -17,9 +17,9 @@
 package org.apache.sling.pipes;
 
 import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.api.resource.ValueMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -71,8 +71,11 @@ public class PipeBindings {
      * add ${name.pipeName} binding allowing to retrieve pipeName's current resource name
      */
     public static final String NAME_BINDING = "name";
-    
-    private static final Pattern INJECTED_SCRIPT = Pattern.compile("\\$\\{(([^\\{^\\}]*(\\{[0-9,]+\\})?)*)\\}");
+
+    private static final String INJECTED_SCRIPT_REGEXP = "\\$\\{(([^\\{^\\}]*(\\{[0-9,]+\\})?)*)\\}";
+    private static final Pattern INJECTED_SCRIPT = Pattern.compile(INJECTED_SCRIPT_REGEXP);
+    protected static final String IF_PREFIX = "$if";
+    protected static final Pattern CONDITIONAL_STRING =  Pattern.compile("^\\" + IF_PREFIX + INJECTED_SCRIPT_REGEXP);
 
     ScriptEngine engine;
     
@@ -197,14 +200,6 @@ public class PipeBindings {
     }
 
     /**
-     * copy bindings
-     * @param original original bindings to copy
-     */
-    public void copyBindings(PipeBindings original){
-        getBindings().putAll(original.getBindings());
-    }
-
-    /**
      * evaluate a given expression
      * @param expr ecma like expression
      * @return object that is the result of the expression
@@ -255,6 +250,29 @@ public class PipeBindings {
     }
 
     /**
+     * Return expression, instantiated expression or null if the expression is conditional and evaluation is falsy
+     * @param conditionalExpression can be static, or dynamic, can be conditional in which case it must be of following
+     * format <code>$if${condition}someString</code>. someString will be returned if condition is true, otherwise null
+     * @return instantiated expression or null if expression is conditional (see above) and condition is falsy
+     * @throws ScriptException in case one of the evaluation went wrong
+     */
+    public String conditionalString(String conditionalExpression) throws ScriptException {
+        Matcher matcher = CONDITIONAL_STRING.matcher(conditionalExpression);
+        if (matcher.find()){
+            Object output = evaluate(StringUtils.substringAfter(matcher.group(0), IF_PREFIX));
+            if (output != null){
+                String s = output.toString().toLowerCase().trim();
+                if(StringUtils.isNotEmpty(s) && !"false".equals(s) && !"undefined".equals(s)){
+                    return instantiateExpression(conditionalExpression.substring(matcher.group(0).length()));
+                }
+            }
+        } else {
+            return instantiateExpression(conditionalExpression);
+        }
+        return null;
+    }
+
+    /**
      * Expression is a function of variables from execution context, that
      * we implement here as a String
      * @param expr ecma like expression
diff --git a/src/main/java/org/apache/sling/pipes/PipeBuilder.java b/src/main/java/org/apache/sling/pipes/PipeBuilder.java
index 3388c4c..8607bef 100644
--- a/src/main/java/org/apache/sling/pipes/PipeBuilder.java
+++ b/src/main/java/org/apache/sling/pipes/PipeBuilder.java
@@ -246,11 +246,11 @@ public interface PipeBuilder {
     PipeBuilder not(String expr);
 
     /**
-     * attach a multi value property pipe to the current context
+     * attach a MULTI value property pipe to the current context
      * @return updated instance of PipeBuilder
      */
     @PipeExecutor(command = "mp", resourceType = MultiPropertyPipe.RESOURCE_TYPE, pipeClass = MultiPropertyPipe.class,
-            description = "read multi property, and output each value in the bindings")
+            description = "read MULTI property, and output each value in the bindings")
     PipeBuilder mp();
 
     /**
diff --git a/src/main/java/org/apache/sling/pipes/internal/WritePipe.java b/src/main/java/org/apache/sling/pipes/internal/WritePipe.java
index 9793930..5f2bcbe 100644
--- a/src/main/java/org/apache/sling/pipes/internal/WritePipe.java
+++ b/src/main/java/org/apache/sling/pipes/internal/WritePipe.java
@@ -46,10 +46,12 @@ import java.util.regex.Pattern;
 public class WritePipe extends BasePipe {
     private static final Logger logger = LoggerFactory.getLogger(WritePipe.class);
     public static final String RESOURCE_TYPE = RT_PREFIX + "write";
+    protected static final Pattern ADD_PATCH = Pattern.compile("\\+\\[(.*)\\]");
+    protected static final Pattern MULTI = Pattern.compile("\\[(.*)\\]");
+
     Node confTree;
     private List<Resource> propertiesToRemove;
-    Pattern addPatch = Pattern.compile("\\+\\[(.*)\\]");
-    Pattern multi = Pattern.compile("\\[(.*)\\]");
+
 
     /**
      * public constructor
@@ -88,7 +90,7 @@ public class WritePipe extends BasePipe {
         if (value != null && value instanceof String) {
             //in that case we treat special case like MV or patches
             String sValue = (String)value;
-            Matcher patch = addPatch.matcher(sValue);
+            Matcher patch = ADD_PATCH.matcher(sValue);
             if (patch.matches()) {
                 String newValue = patch.group(1);
                 String[] actualValues = resource.adaptTo(ValueMap.class).get(key, String[].class);
@@ -98,7 +100,7 @@ public class WritePipe extends BasePipe {
                 }
                 return newValues.toArray(new String[newValues.size()]);
             }
-            Matcher multiMatcher = multi.matcher(sValue);
+            Matcher multiMatcher = MULTI.matcher(sValue);
             if (multiMatcher.matches()) {
                 return multiMatcher.group(1).split(",");
             }
@@ -194,8 +196,10 @@ public class WritePipe extends BasePipe {
             while (childrenConf.hasNext()){
                 Node childConf = childrenConf.nextNode();
                 String name = childConf.getName();
-                name = bindings.instantiateExpression(name);
-                if (!isDryRun()){
+                name = bindings.conditionalString(name);
+                if (name == null){
+                    logger.debug("name has been instantiated as null, not writing that tree");
+                } else if (!isDryRun()){
                     Node childTarget = targetNode.hasNode(name) ? targetNode.getNode(name) : targetNode.addNode(name, childConf.getPrimaryNodeType().getName());
                     logger.debug("writing tree {}", childTarget.getPath());
                     writeTree(childConf, resolver.getResource(childTarget.getPath()));
diff --git a/src/test/java/org/apache/sling/pipes/internal/WritePipeTest.java b/src/test/java/org/apache/sling/pipes/internal/WritePipeTest.java
index 45bbf1d..e1bce7b 100644
--- a/src/test/java/org/apache/sling/pipes/internal/WritePipeTest.java
+++ b/src/test/java/org/apache/sling/pipes/internal/WritePipeTest.java
@@ -29,6 +29,7 @@ import org.junit.Test;
 
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
 import java.util.Iterator;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -37,6 +38,7 @@ import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 /**
@@ -159,4 +161,32 @@ public class WritePipeTest extends AbstractPipeTest {
         context.resourceResolver().commit();
         assertNotNull("there should be a node created", context.resourceResolver().getResource(PATH_APPLE + "/testExpression"));
     }
+
+
+    protected void testIfNode(Object bindingValue, boolean nodeExpected) throws PersistenceException, RepositoryException {
+        String expectedPath = PATH_APPLE + "/isTrue";
+        Pipe pipe = getPipe(PATH_PIPE + "/ifNode");
+        pipe.getBindings().addBinding("addedTest", bindingValue);
+        pipe.getOutput().next();
+        context.resourceResolver().commit();
+        Resource resource = context.resourceResolver().getResource(expectedPath);
+        if (nodeExpected){
+            assertNotNull("there should be isTrue node for test binding " + bindingValue, resource);
+        } else {
+            assertNull("there should be no isTrue node created for test binding " + bindingValue, resource);
+        }
+        if (resource != null){
+            resource.adaptTo(Node.class).remove();
+        }
+    }
+
+    @Test
+    public void testIfNode() throws PersistenceException, RepositoryException {
+        testIfNode(null, false);
+        testIfNode("undefined", false);
+        testIfNode("false", false);
+        testIfNode(false, false);
+        testIfNode("some random string", true);
+        testIfNode(true, true);
+    }
 }
diff --git a/src/test/resources/write.json b/src/test/resources/write.json
index 0cd2dc4..0b7d20b 100644
--- a/src/test/resources/write.json
+++ b/src/test/resources/write.json
@@ -101,5 +101,16 @@
         "jcr:primaryType":"nt:unstructured"
       }
     }
+  },
+  "ifNode":{
+    "jcr:primaryType":"nt:unstructured",
+    "sling:resourceType":"slingPipes/write",
+    "path":"/content/fruits/apple",
+    "conf": {
+      "jcr:primaryType":"nt:unstructured",
+      "$if${addedTest}isTrue": {
+        "jcr:primaryType":"nt:unstructured"
+      }
+    }
   }
 }
\ No newline at end of file