You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by wo...@apache.org on 2013/10/19 00:40:51 UTC

svn commit: r1533656 - in /commons/proper/scxml/trunk: ./ src/main/java/org/apache/commons/scxml2/env/jexl/ src/test/java/org/apache/commons/scxml2/ src/test/java/org/apache/commons/scxml2/env/jexl/

Author: woonsan
Date: Fri Oct 18 22:40:50 2013
New Revision: 1533656

URL: http://svn.apache.org/r1533656
Log:
SCXML-114: Upgrading JEXL to 2.1.1
- Applied Henri Biestro's patch with some small additional work (e.g, J6 generics, renaming, javadocs, unit test)
- Many thanks to Henri Biestro!

Added:
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java
Modified:
    commons/proper/scxml/trunk/pom.xml
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlContext.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCInstanceTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/JexlContextTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/JexlEvaluatorTest.java

Modified: commons/proper/scxml/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/pom.xml?rev=1533656&r1=1533655&r2=1533656&view=diff
==============================================================================
--- commons/proper/scxml/trunk/pom.xml (original)
+++ commons/proper/scxml/trunk/pom.xml Fri Oct 18 22:40:50 2013
@@ -156,9 +156,9 @@
       <optional>true</optional>
     </dependency>
     <dependency>
-      <groupId>commons-jexl</groupId>
+      <groupId>org.apache.commons</groupId>
       <artifactId>commons-jexl</artifactId>
-      <version>1.1</version>
+      <version>2.1.1</version>
       <optional>true</optional>
     </dependency>
     <dependency>

Added: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java?rev=1533656&view=auto
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java (added)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java Fri Oct 18 22:40:50 2013
@@ -0,0 +1,83 @@
+/*
+ * 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.commons.scxml2.env.jexl;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.scxml2.Builtin;
+import org.apache.commons.scxml2.model.TransitionTarget;
+
+/**
+ * Global JEXL namespace functor, implements Data() and In() operators.
+ * Cooperates with JexlContext.
+ */
+public final class JexlBuiltin {
+    /**
+     * The context currently in use for evaluation.
+     */
+    private final JexlContext context;
+
+    /**
+     * Creates a new instance, wraps the context.
+     * @param ctxt the context in use
+     */
+    public JexlBuiltin(final JexlContext ctxt) {
+        context = ctxt;
+    }
+
+    /**
+     * Gets the ALL_NAMESPACES map from context.
+     * @return the ALL_NAMESPACES map
+     */
+    private Map<String, String> getNamespaces() {
+        return (Map<String, String>) context.get("_ALL_NAMESPACES");
+    }
+
+    /**
+     * Gets the ALL_STATES set from context.
+     * @return the ALL_STATES set
+     */
+    private Set<TransitionTarget> getAllStates() {
+        return (Set<TransitionTarget>) context.get("_ALL_STATES");
+    }
+
+    /**
+     * Implements the Data() predicate for SCXML documents ( see Builtin#data ).
+     * @param data the context node
+     * @param path the XPath expression
+     * @return the first node matching the path
+     */
+    public Object Data(final Object data, final String path) {
+        // first call maps delegates to dataNode(), subsequent ones to data()
+        if (context.isEvaluatingLocation()) {
+            context.setEvaluatingLocation(false);
+            return Builtin.dataNode(getNamespaces(), data, path);
+        } else {
+            return Builtin.data(getNamespaces(), data, path);
+        }
+    }
+
+    /**
+     * Implements the In() predicate for SCXML documents ( see Builtin#isMember )
+     * @param state The State ID to compare with
+     * @return Whether this State belongs to this Set
+     */
+    public boolean In(final String state) {
+        return Builtin.isMember(getAllStates(), state);
+    }
+}

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlContext.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlContext.java?rev=1533656&r1=1533655&r2=1533656&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlContext.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlContext.java Fri Oct 18 22:40:50 2013
@@ -18,7 +18,6 @@ package org.apache.commons.scxml2.env.je
 
 import java.util.Map;
 
-import org.apache.commons.scxml2.Builtin;
 import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.env.SimpleContext;
 
@@ -27,17 +26,22 @@ import org.apache.commons.scxml2.env.Sim
  *
  */
 public class JexlContext extends SimpleContext
-    implements org.apache.commons.jexl.JexlContext {
+    implements org.apache.commons.jexl2.JexlContext {
 
     /** Serial version UID. */
     private static final long serialVersionUID = 1L;
 
     /**
+     * Internal flag to indicate whether it is to evaluate a location
+     * that returns a Node within an XML data tree.
+     */
+    private boolean evaluatingLocation = false;
+
+    /**
      * Constructor.
      */
     public JexlContext() {
         super();
-        getVars().put("_builtin", new Builtin());
     }
 
     /**
@@ -47,7 +51,6 @@ public class JexlContext extends SimpleC
      */
     public JexlContext(final Map<String, Object> initialVars) {
         super(initialVars);
-        getVars().put("_builtin", new Builtin());
     }
 
     /**
@@ -57,34 +60,22 @@ public class JexlContext extends SimpleC
      */
     public JexlContext(final Context parent) {
         super(parent);
-        getVars().put("_builtin", new Builtin());
     }
 
     /**
-     * Set the variables map.
-     *
-     * @param vars The new variables map.
-     *
-     * @see org.apache.commons.jexl.JexlContext#setVars(Map)
-     * @see org.apache.commons.scxml2.env.SimpleContext#setVars(Map)
+     * Returns the internal flag to indicate whether it is to evaluate a location
+     * that returns a Node within an XML data tree.
      */
-    @Override
-    @SuppressWarnings("unchecked")
-    // Accomodate legacy signature org.apache.commons.jexl.JexlContext#setVars(Map)
-    public void setVars(final Map vars) {
-        super.setVars(vars);
-        getVars().put("_builtin", new Builtin());
+    public boolean isEvaluatingLocation() {
+        return evaluatingLocation;
     }
 
     /**
-     * Clear this Context.
-     *
-     * @see org.apache.commons.scxml2.Context#reset()
+     * Sets the internal flag to indicate whether it is to evaluate a location
+     * that returns a Node within an XML data tree.
      */
-    @Override
-    public void reset() {
-        super.reset();
-        getVars().put("_builtin", new Builtin());
+    public void setEvaluatingLocation(boolean evaluatingLocation) {
+        this.evaluatingLocation = evaluatingLocation;
     }
 
 }

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java?rev=1533656&r1=1533655&r2=1533656&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java Fri Oct 18 22:40:50 2013
@@ -18,15 +18,14 @@ package org.apache.commons.scxml2.env.je
 
 import java.io.Serializable;
 import java.util.AbstractMap;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.regex.Pattern;
 
-import org.apache.commons.jexl.Expression;
-import org.apache.commons.jexl.ExpressionFactory;
-import org.apache.commons.jexl.Script;
-import org.apache.commons.jexl.ScriptFactory;
+import org.apache.commons.jexl2.Expression;
+import org.apache.commons.jexl2.JexlEngine;
+import org.apache.commons.jexl2.Script;
 import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.SCXMLExpressionException;
@@ -44,12 +43,19 @@ public class JexlEvaluator implements Ev
 
     /** Error message if evaluation context is not a JexlContext. */
     private static final String ERR_CTX_TYPE = "Error evaluating JEXL "
-        + "expression, Context must be a org.apache.commons.jexl.JexlContext";
+        + "expression, Context must be a org.apache.commons.jexl2.JexlContext";
 
-    /** Pattern for recognizing the SCXML In() special predicate. */
-    private static Pattern inFct = Pattern.compile("In\\(");
-    /** Pattern for recognizing the Commons SCXML Data() builtin function. */
-    private static Pattern dataFct = Pattern.compile("Data\\(");
+    /** The JexlEngine instance to use. */
+    private static final transient JexlEngine jexlEngine;
+    static {
+        jexlEngine = new JexlEngine();
+        Map<String, Object> top = new HashMap<String, Object>();
+        // With null prefix, define top-level user defined functions.
+        // See javadoc of org.apache.commons.jexl2.JexlEngine#setFunctions(Map<String,Object> funcs) for detail.
+        top.put(null, JexlBuiltin.class);
+        jexlEngine.setFunctions(top);
+        jexlEngine.setCache(256);
+    }
 
     /** Constructor. */
     public JexlEvaluator() {
@@ -78,12 +84,9 @@ public class JexlEvaluator implements Ev
         }
         Expression exp = null;
         try {
-            String evalExpr = inFct.matcher(expr).
-                replaceAll("_builtin.isMember(_ALL_STATES, ");
-            evalExpr = dataFct.matcher(evalExpr).
-                replaceAll("_builtin.data(_ALL_NAMESPACES, ");
-            exp = ExpressionFactory.createExpression(evalExpr);
-            return exp.evaluate(getEffectiveContext(jexlCtx));
+            final JexlContext effective = getEffectiveContext(jexlCtx);
+            exp = jexlEngine.createExpression(expr);
+            return exp.evaluate(effective);
         } catch (Exception e) {
             throw new SCXMLExpressionException("eval('" + expr + "'):"
                 + e.getMessage(), e);
@@ -106,13 +109,10 @@ public class JexlEvaluator implements Ev
         }
         Expression exp = null;
         try {
-            String evalExpr = inFct.matcher(expr).
-                replaceAll("_builtin.isMember(_ALL_STATES, ");
-            evalExpr = dataFct.matcher(evalExpr).
-                replaceAll("_builtin.data(_ALL_NAMESPACES, ");
-            exp = ExpressionFactory.createExpression(evalExpr);
-            return (Boolean) exp.evaluate(getEffectiveContext(jexlCtx));
-        } catch (Exception e) {e.printStackTrace();
+            final JexlContext effective = getEffectiveContext(jexlCtx);
+            exp = jexlEngine.createExpression(expr);
+            return (Boolean) exp.evaluate(effective);
+        } catch (Exception e) {
             throw new SCXMLExpressionException("evalCond('" + expr + "'):"
                 + e.getMessage(), e);
         }
@@ -134,14 +134,10 @@ public class JexlEvaluator implements Ev
         }
         Expression exp = null;
         try {
-            String evalExpr = inFct.matcher(expr).
-                replaceAll("_builtin.isMember(_ALL_STATES, ");
-            evalExpr = dataFct.matcher(evalExpr).
-                replaceFirst("_builtin.dataNode(_ALL_NAMESPACES, ");
-            evalExpr = dataFct.matcher(evalExpr).
-                replaceAll("_builtin.data(_ALL_NAMESPACES, ");
-            exp = ExpressionFactory.createExpression(evalExpr);
-            return (Node) exp.evaluate(getEffectiveContext(jexlCtx));
+            final JexlContext effective = getEffectiveContext(jexlCtx);
+            effective.setEvaluatingLocation(true);
+            exp = jexlEngine.createExpression(expr);
+            return (Node) exp.evaluate(effective);
         } catch (Exception e) {
             throw new SCXMLExpressionException("evalLocation('" + expr + "'):"
                 + e.getMessage(), e);
@@ -151,7 +147,7 @@ public class JexlEvaluator implements Ev
     /**
      * @see Evaluator#evalScript(Context, String)
      */
-    public Object evalScript(Context ctx, String script)
+    public Object evalScript(final Context ctx, final String script)
     throws SCXMLExpressionException {
         if (script == null) {
             return null;
@@ -164,12 +160,10 @@ public class JexlEvaluator implements Ev
         }
         Script jexlScript = null;
         try {
-            String scriptStr = inFct.matcher(script).
-                replaceAll("_builtin.isMember(_ALL_STATES, ");
-            scriptStr = dataFct.matcher(scriptStr).
-                replaceAll("_builtin.data(_ALL_NAMESPACES, ");
-            jexlScript = ScriptFactory.createScript(scriptStr);
-            return jexlScript.execute(getEffectiveContext(jexlCtx));
+            final JexlContext effective = getEffectiveContext(jexlCtx);
+            effective.setEvaluatingLocation(true);
+            jexlScript = jexlEngine.createScript(script);
+            return jexlScript.execute(effective);
         } catch (Exception e) {
             throw new SCXMLExpressionException("evalScript('" + script + "'):"
                 + e.getMessage(), e);
@@ -209,10 +203,10 @@ public class JexlEvaluator implements Ev
     private static final class EffectiveContextMap extends AbstractMap<String, Object> {
 
         /** The {@link Context} for the current state. */
-        final Context leaf;
+        private final Context leaf;
 
         /** Constructor. */
-        public EffectiveContextMap(JexlContext ctx) {
+        public EffectiveContextMap(final JexlContext ctx) {
             super();
             this.leaf = ctx;
         }
@@ -235,7 +229,7 @@ public class JexlEvaluator implements Ev
          * {@inheritDoc}
          */
         @Override
-        public Object put(String key, Object value) {
+        public Object put(final String key, final Object value) {
             Object old = leaf.get(key);
             if (leaf.has(key)) {
                 leaf.set(key, value);
@@ -249,7 +243,7 @@ public class JexlEvaluator implements Ev
          * {@inheritDoc}
          */
         @Override
-        public Object get(Object key) {
+        public Object get(final Object key) {
             Context current = leaf;
             while (current != null) {
                 if (current.getVars().containsKey(key)) {

Modified: commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCInstanceTest.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCInstanceTest.java?rev=1533656&r1=1533655&r2=1533656&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCInstanceTest.java (original)
+++ commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCInstanceTest.java Fri Oct 18 22:40:50 2013
@@ -19,7 +19,7 @@ package org.apache.commons.scxml2;
 import java.util.HashSet;
 import java.util.Set;
 
-import org.apache.commons.jexl.JexlContext;
+import org.apache.commons.jexl2.JexlContext;
 import org.apache.commons.scxml2.env.SimpleContext;
 import org.apache.commons.scxml2.env.jexl.JexlEvaluator;
 import org.apache.commons.scxml2.model.History;

Modified: commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/JexlContextTest.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/JexlContextTest.java?rev=1533656&r1=1533655&r2=1533656&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/JexlContextTest.java (original)
+++ commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/JexlContextTest.java Fri Oct 18 22:40:50 2013
@@ -19,7 +19,6 @@ package org.apache.commons.scxml2.env.je
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.commons.scxml2.Builtin;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -29,8 +28,6 @@ public class JexlContextTest {
     public void testNew() {
         JexlContext ctx = new JexlContext();
         Assert.assertNotNull(ctx);
-        Assert.assertEquals(1, ctx.getVars().size());
-        Assert.assertTrue(ctx.get("_builtin") instanceof Builtin);
     }
     
     @Test
@@ -39,24 +36,19 @@ public class JexlContextTest {
         m.put("foo", "bar");
         JexlContext ctx = new JexlContext(m);
         Assert.assertNotNull(ctx);
-        Assert.assertEquals(2, ctx.getVars().size());
-        Assert.assertTrue(ctx.get("_builtin") instanceof Builtin);
+        Assert.assertEquals(1, ctx.getVars().size());
         String fooValue = (String) ctx.get("foo");
         Assert.assertEquals("bar", fooValue);
     }
     
     @Test
     public void testSetVars() {
-        JexlContext ctx = new JexlContext();
-        Assert.assertNotNull(ctx);
-        Assert.assertEquals(1, ctx.getVars().size());
-        Assert.assertTrue(ctx.get("_builtin") instanceof Builtin);
         Map<String, Object> m = new HashMap<String, Object>();
         m.put("foo", "bar");
-        ctx.setVars(m);
-        Assert.assertEquals(2, ctx.getVars().size());
+        JexlContext ctx = new JexlContext(m);
+        Assert.assertNotNull(ctx);
+        Assert.assertEquals(1, ctx.getVars().size());
         String fooValue = (String) ctx.get("foo");
-        Assert.assertTrue(ctx.get("_builtin") instanceof Builtin);
         Assert.assertEquals("bar", fooValue);
     }
 

Modified: commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/JexlEvaluatorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/JexlEvaluatorTest.java?rev=1533656&r1=1533655&r2=1533656&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/JexlEvaluatorTest.java (original)
+++ commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/JexlEvaluatorTest.java Fri Oct 18 22:40:50 2013
@@ -30,10 +30,24 @@ public class JexlEvaluatorTest {
     @Test
     public void testPristine() throws SCXMLExpressionException {
         Evaluator eval = new JexlEvaluator();
-        Assert.assertNotNull(eval);
         Assert.assertTrue(((Boolean) eval.eval(ctx, "1+1 eq 2")).booleanValue());
     }
-    
+
+    @Test
+    public void testScript() throws SCXMLExpressionException {
+        Evaluator eval = new JexlEvaluator();
+        ctx.set("x", 3);
+        ctx.set("y", 0);
+        String script = 
+            "if ((x * 2) == 5) {" +
+                "y = 1;\n" +
+            "} else {\n" +
+                "y = 2;\n" +
+            "}";
+        Assert.assertEquals(2, eval.evalScript(ctx, script));
+        Assert.assertEquals(2, ctx.get("y"));
+    }
+
     @Test
     public void testErrorMessage() {
         Evaluator eval = new JexlEvaluator();