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 2015/07/12 17:01:33 UTC

[3/5] commons-scxml git commit: SCXML-234 fixing unit test failure in ScriptTest

SCXML-234 fixing unit test failure in ScriptTest


Project: http://git-wip-us.apache.org/repos/asf/commons-scxml/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-scxml/commit/6eb76141
Tree: http://git-wip-us.apache.org/repos/asf/commons-scxml/tree/6eb76141
Diff: http://git-wip-us.apache.org/repos/asf/commons-scxml/diff/6eb76141

Branch: refs/heads/master
Commit: 6eb761413871082d2ea128d8e132dd5ac06bbf4f
Parents: 8691eb9
Author: Woonsan Ko <w....@onehippo.com>
Authored: Sat Jul 11 16:46:43 2015 -0400
Committer: Woonsan Ko <w....@onehippo.com>
Committed: Sat Jul 11 16:46:43 2015 -0400

----------------------------------------------------------------------
 .../scxml2/env/javascript/JSBindings.java       |  4 +-
 .../scxml2/env/javascript/JSContext.java        | 13 ++-
 .../scxml2/env/javascript/JSEvaluator.java      | 87 +++++++++++++++-----
 .../scxml2/env/javascript/JSEvaluatorTest.java  | 23 +++++-
 4 files changed, 100 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6eb76141/src/main/java/org/apache/commons/scxml2/env/javascript/JSBindings.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/javascript/JSBindings.java b/src/main/java/org/apache/commons/scxml2/env/javascript/JSBindings.java
index ec48c12..85bef0f 100644
--- a/src/main/java/org/apache/commons/scxml2/env/javascript/JSBindings.java
+++ b/src/main/java/org/apache/commons/scxml2/env/javascript/JSBindings.java
@@ -326,7 +326,7 @@ public class JSBindings implements Bindings {
      * </p>
      * @return true if a global bindings (i.e. nashorn Global instance) was ever set by the script engine
      */
-    private boolean hasGlobalBindings() {
+    boolean hasGlobalBindings() {
         if (bindings.containsKey(NASHORN_GLOBAL)) {
             return true;
         }
@@ -338,7 +338,7 @@ public class JSBindings implements Bindings {
      * Return the global bindings (i.e. nashorn Global instance) set by the script engine if existing.
      * @return the global bindings (i.e. nashorn Global instance) set by the script engine, or null if not existing.
      */
-    private Bindings getGlobalBindings() {
+    Bindings getGlobalBindings() {
         if (bindings.containsKey(NASHORN_GLOBAL)) {
             return (Bindings) bindings.get(NASHORN_GLOBAL);
         }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6eb76141/src/main/java/org/apache/commons/scxml2/env/javascript/JSContext.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/javascript/JSContext.java b/src/main/java/org/apache/commons/scxml2/env/javascript/JSContext.java
index 95f59be..d63d25a 100644
--- a/src/main/java/org/apache/commons/scxml2/env/javascript/JSContext.java
+++ b/src/main/java/org/apache/commons/scxml2/env/javascript/JSContext.java
@@ -17,6 +17,8 @@
 
 package org.apache.commons.scxml2.env.javascript;
 
+import java.util.Map;
+
 import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.env.SimpleContext;
 
@@ -44,13 +46,22 @@ public class JSContext extends SimpleContext {
     }
 
     /**
+     * Constructor with initial vars.
+     * @param parent The parent context
+     * @param initialVars The initial set of variables.
+     */
+    public JSContext(final Context parent, final Map<String, Object> initialVars) {
+        super(parent, initialVars);
+    }
+
+    /**
      * Child constructor. Just invokes the identical SimpleContext
      * constructor.
      *
      * @param parent Parent context for this context.
      *
      */
-    public JSContext(Context parent) {
+    public JSContext(final Context parent) {
         super(parent);
     }
 

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6eb76141/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java b/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
index 4c64ea2..8b47e93 100644
--- a/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
+++ b/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
@@ -30,6 +30,7 @@ import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.EvaluatorProvider;
 import org.apache.commons.scxml2.SCXMLExpressionException;
 import org.apache.commons.scxml2.XPathBuiltin;
+import org.apache.commons.scxml2.env.EffectiveContextMap;
 import org.apache.commons.scxml2.model.SCXML;
 
 /**
@@ -71,6 +72,10 @@ public class JSEvaluator implements Evaluator {
         }
     }
 
+    /** Error message if evaluation context is not a JexlContext. */
+    private static final String ERR_CTX_TYPE = "Error evaluating JavaScript "
+        + "expression, Context must be a org.apache.commons.scxml2.env.javascript.JSContext";
+
     /** Pattern for recognizing the SCXML In() special predicate. */
     private static final Pattern IN_FN = Pattern.compile("In\\(");
     /** Pattern for recognizing the Commons SCXML Data() builtin function. */
@@ -124,8 +129,17 @@ public class JSEvaluator implements Evaluator {
      * @throws SCXMLExpressionException Thrown if the expression was invalid.
      */
     @Override
-    public Object eval(Context context,String expression) throws SCXMLExpressionException {
+    public Object eval(Context context, String expression) throws SCXMLExpressionException {
+        if (expression == null) {
+            return null;
+        }
+
+        if (!(context instanceof JSContext)) {
+            throw new SCXMLExpressionException(ERR_CTX_TYPE);
+        }
+
         try {
+            JSContext effectiveContext = getEffectiveContext((JSContext) context);
 
             // ... initialize
             ScriptEngine engine   = factory.getEngineByName("JavaScript");
@@ -137,9 +151,15 @@ public class JSEvaluator implements Evaluator {
             jsExpression = LOCATION_FN.matcher(jsExpression).replaceAll("_builtin.Location(");
 
             // ... evaluate
-            JSBindings jsBindings = new JSBindings(context, bindings);
-            jsBindings.put("_builtin", new JSFunctions(context));
-            return engine.eval(jsExpression,jsBindings);
+            JSBindings jsBindings = new JSBindings(effectiveContext, bindings);
+            jsBindings.put("_builtin", new JSFunctions(effectiveContext));
+
+            Object ret = engine.eval(jsExpression, jsBindings);
+
+            // copy global bindings attributes to context, so callers may get access to the evaluated variables.
+            copyGlobalBindingsToContext(jsBindings, (JSContext) effectiveContext);
+
+            return ret;
 
         } catch (Exception x) {
             throw new SCXMLExpressionException("Error evaluating ['" + expression + "'] " + x);
@@ -159,15 +179,15 @@ public class JSEvaluator implements Evaluator {
      *                                  not return a boolean.
      */
     @Override
-    public Boolean evalCond(Context context,String expression) throws SCXMLExpressionException {
-        final Object result = eval(context,expression);
+    public Boolean evalCond(Context context, String expression) throws SCXMLExpressionException {
+        final Object result = eval(context, expression);
 
         if (result == null) {
-           return Boolean.FALSE;
+            return Boolean.FALSE;
         }
 
         if (result instanceof Boolean) {
-           return (Boolean)result;
+            return (Boolean)result;
         }
 
         throw new SCXMLExpressionException("Invalid boolean expression: " + expression);
@@ -186,13 +206,13 @@ public class JSEvaluator implements Evaluator {
      * @throws SCXMLExpressionException Thrown if the expression was invalid.
      */
     @Override
-    public Object evalLocation(Context context,String expression) throws SCXMLExpressionException {
+    public Object evalLocation(Context context, String expression) throws SCXMLExpressionException {
         if (expression == null) {
             return null;
-        }
-        else if (context.has(expression)) {
+        } else if (context.has(expression)) {
             return expression;
         }
+
         return eval(context, expression);
     }
 
@@ -203,23 +223,21 @@ public class JSEvaluator implements Evaluator {
                            final String attr) throws SCXMLExpressionException {
 
         Object loc = evalLocation(ctx, location);
-        if (loc != null) {
 
+        if (loc != null) {
             if (XPathBuiltin.isXPathLocation(ctx, loc)) {
                 XPathBuiltin.assign(ctx, loc, data, type, attr);
-            }
-            else {
+            } else {
                 StringBuilder sb = new StringBuilder(location).append("=").append(ASSIGN_VARIABLE_NAME);
+
                 try {
                     ctx.getVars().put(ASSIGN_VARIABLE_NAME, data);
                     eval(ctx, sb.toString());
-                }
-                finally {
+                } finally {
                     ctx.getVars().remove(ASSIGN_VARIABLE_NAME);
                 }
             }
-        }
-        else {
+        } else {
             throw new SCXMLExpressionException("evalAssign - cannot resolve location: '" + location + "'");
         }
     }
@@ -239,8 +257,37 @@ public class JSEvaluator implements Evaluator {
      * @throws SCXMLExpressionException Thrown if the script was invalid.
      */
     @Override
-    public Object evalScript(Context ctx, String script)
-    throws SCXMLExpressionException {
+    public Object evalScript(Context ctx, String script) throws SCXMLExpressionException {
         return eval(ctx, script);
     }
+
+    /**
+     * Create a new context which is the summation of contexts from the
+     * current state to document root, child has priority over parent
+     * in scoping rules.
+     *
+     * @param nodeCtx The JexlContext for this state.
+     * @return The effective JexlContext for the path leading up to
+     *         document root.
+     */
+    protected JSContext getEffectiveContext(final JSContext nodeCtx) {
+        return new JSContext(nodeCtx, new EffectiveContextMap(nodeCtx));
+    }
+
+    /**
+     * Copy the global Bindings (i.e. nashorn Global instance) attributes to {@code jsContext}
+     * in order to make sure all the new global variables set by the JavaScript engine after evaluation
+     * available from {@link JSContext} instance as well.
+     * @param jsBindings
+     * @param jsContext
+     */
+    private void copyGlobalBindingsToContext(final JSBindings jsBindings, final JSContext jsContext) {
+        Bindings globalBindings = jsBindings.getGlobalBindings();
+
+        if (globalBindings != null) {
+            for (String key : globalBindings.keySet()) {
+                jsContext.set(key, globalBindings.get(key));
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6eb76141/src/test/java/org/apache/commons/scxml2/env/javascript/JSEvaluatorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/javascript/JSEvaluatorTest.java b/src/test/java/org/apache/commons/scxml2/env/javascript/JSEvaluatorTest.java
index 45cae01..28d923e 100644
--- a/src/test/java/org/apache/commons/scxml2/env/javascript/JSEvaluatorTest.java
+++ b/src/test/java/org/apache/commons/scxml2/env/javascript/JSEvaluatorTest.java
@@ -19,6 +19,10 @@ package org.apache.commons.scxml2.env.javascript;
 
 import java.io.StringReader;
 
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+
 import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.SCXMLExecutor;
@@ -31,10 +35,6 @@ import org.junit.Test;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathFactory;
-
 /** JUnit 3 test case for the JSEvaluator expression evaluator
  *  class. Includes basic tests for:
  *  <ul>
@@ -145,6 +145,21 @@ public class JSEvaluatorTest {
         Assert.assertTrue   (((Boolean) evaluator.eval(context, "1+1 == 2")).booleanValue());
     }
 
+    @Test
+    public void testScript() throws SCXMLExpressionException {
+        Evaluator evaluator = new JSEvaluator();
+        context.set("x", 3);
+        context.set("y", 0);
+        String script = 
+            "if ((x * 2.0) == 5.0) {" +
+                "y = 1.0;\n" +
+            "} else {\n" +
+                "y = 2.0;\n" +
+            "}";
+        Assert.assertEquals(2.0, evaluator.evalScript(context, script));
+        Assert.assertEquals(2.0, context.get("y"));
+    }
+
     /**
      * Tests handling of illegal expressions.
      *