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.
*