SCXML-242: Providing JSON base datamodel as replacement for XML/XPath See: https://issues.apache.org/jira/browse/SCXML-242 - adding FasterXML Jackson as (default) json parser - adding new ContentParser to encapsulate Data (content) parsing logic - adding new AbstractBaseEvaluator for common new cloneData method - replace all XML based datamodel examples with JSON and dropping all Data() and Location() usages - dropping Data() and Location() implementations and related XPathBuiltin for Jexl, Javascript and Groovy languages - deleting no longer relevant XPath based unit-tests
Project: http://git-wip-us.apache.org/repos/asf/commons-scxml/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-scxml/commit/6af929eb Tree: http://git-wip-us.apache.org/repos/asf/commons-scxml/tree/6af929eb Diff: http://git-wip-us.apache.org/repos/asf/commons-scxml/diff/6af929eb Branch: refs/heads/master Commit: 6af929eb622b07742d4eeac3b754c60ad6a60a3d Parents: 7b3a237 Author: Ate Douma <a...@apache.org> Authored: Sat Dec 26 18:49:34 2015 +0100 Committer: Ate Douma <a...@apache.org> Committed: Sat Dec 26 18:49:34 2015 +0100 ---------------------------------------------------------------------- pom.xml | 22 +- .../org/apache/commons/scxml2/Evaluator.java | 6 + .../org/apache/commons/scxml2/SCInstance.java | 16 +- .../org/apache/commons/scxml2/XPathBuiltin.java | 93 ------- .../scxml2/env/AbstractBaseEvaluator.java | 82 ++++++ .../scxml2/env/groovy/GroovyEvaluator.java | 30 +-- .../scxml2/env/groovy/GroovySCXMLScript.java | 27 +- .../scxml2/env/javascript/JSEvaluator.java | 78 +++--- .../scxml2/env/javascript/JSFunctions.java | 25 +- .../commons/scxml2/env/jexl/JexlBuiltin.java | 25 +- .../commons/scxml2/env/jexl/JexlEvaluator.java | 30 +-- .../scxml2/env/minimal/MinimalEvaluator.java | 5 + .../scxml2/env/xpath/XPathEvaluator.java | 4 +- .../apache/commons/scxml2/io/ContentParser.java | 217 ++++++++++++++++ .../apache/commons/scxml2/io/SCXMLReader.java | 25 +- .../org/apache/commons/scxml2/model/Assign.java | 31 +-- .../org/apache/commons/scxml2/model/Data.java | 53 ++-- .../scxml2/NamespacePrefixedXPathsTest.java | 89 ------- .../commons/scxml2/env/groovy/datamodel-01.xml | 84 ++++++ .../commons/scxml2/env/groovy/datamodel-05.xml | 80 ++++++ .../scxml2/env/javascript/JSEvaluatorTest.java | 65 +++-- .../scxml2/env/javascript/datamodel-01.xml | 84 ++++++ .../scxml2/env/javascript/datamodel-05.xml | 80 ++++++ .../scxml2/env/javascript/example-01.xml | 39 +-- .../commons/scxml2/env/jexl/datamodel-01.xml | 56 +--- .../commons/scxml2/env/jexl/datamodel-02.xml | 90 ------- .../commons/scxml2/env/jexl/datamodel-03.xml | 255 ------------------- .../commons/scxml2/env/jexl/datamodel-04.xml | 48 ---- .../commons/scxml2/env/jexl/datamodel-05.xml | 66 +++-- .../commons/scxml2/env/jexl/eventdata-03.xml | 11 +- .../scxml2/invoke/InvokeParamNameTest.java | 13 +- .../apache/commons/scxml2/invoke/invoker-04.xml | 8 +- .../commons/scxml2/io/ContentParserTest.java | 79 ++++++ .../commons/scxml2/model/DatamodelTest.java | 57 +++-- .../commons/scxml2/model/ParallelTest.java | 14 +- .../apache/commons/scxml2/model/SendTest.java | 4 +- .../apache/commons/scxml2/model/assign-src.json | 25 ++ .../apache/commons/scxml2/model/assign-src.xml | 21 -- .../commons/scxml2/model/assign-test-01.xml | 29 +-- .../commons/scxml2/model/assign-test-02.xml | 23 +- .../commons/scxml2/model/cancel-test-01.xml | 11 +- .../commons/scxml2/model/cancel-test-02.xml | 11 +- .../apache/commons/scxml2/model/parallel-03.xml | 34 ++- .../commons/scxml2/model/send-test-01.xml | 11 +- 44 files changed, 1085 insertions(+), 1071 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index e4cdb5f..fbe52ce 100644 --- a/pom.xml +++ b/pom.xml @@ -143,6 +143,21 @@ <version>1.1.3</version> </dependency> <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + <version>2.6.4</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + <version>2.6.4</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.4</version> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> @@ -170,12 +185,6 @@ <artifactId>commons-beanutils</artifactId> <version>1.9.2</version> </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.4</version> - <scope>test</scope> - </dependency> </dependencies> <distributionManagement> @@ -211,6 +220,7 @@ <directory>src/test/java</directory> <includes> <include>**/*.xml</include> + <include>**/*.json</include> <include>**/*.xsl</include> <include>**/*.gif</include> </includes> http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/Evaluator.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/Evaluator.java b/src/main/java/org/apache/commons/scxml2/Evaluator.java index ae2e744..0d7cad7 100644 --- a/src/main/java/org/apache/commons/scxml2/Evaluator.java +++ b/src/main/java/org/apache/commons/scxml2/Evaluator.java @@ -76,6 +76,12 @@ public interface Evaluator { String getSupportedDatamodel(); /** + * @param data data to be cloned + * @return A deep clone of the data + */ + Object cloneData(Object data); + + /** * Evaluate an expression returning a data value * * @param ctx variable context http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/SCInstance.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/SCInstance.java b/src/main/java/org/apache/commons/scxml2/SCInstance.java index 6b0e5b8..1260fa4 100644 --- a/src/main/java/org/apache/commons/scxml2/SCInstance.java +++ b/src/main/java/org/apache/commons/scxml2/SCInstance.java @@ -299,15 +299,14 @@ public class SCInstance implements Serializable { // earlier or externally defined 'initial' value found: do not overwrite continue; } - Node datumNode = datum.getNode(); - Node valueNode = null; - if (datumNode != null) { - valueNode = datumNode.cloneNode(true); - } + /* + TODO: external data.src support (not yet implemented), including late-binding thereof // prefer "src" over "expr" over "inline" if (datum.getSrc() != null) { ctx.setLocal(datum.getId(), valueNode); - } else if (datum.getExpr() != null) { + } else + */ + if (datum.getExpr() != null) { Object value; try { ctx.setLocal(Context.NAMESPACES_KEY, datum.getNamespaces()); @@ -345,8 +344,9 @@ public class SCInstance implements Serializable { else { ctx.setLocal(datum.getId(), value); } - } else { - ctx.setLocal(datum.getId(), valueNode); + } + else { + ctx.setLocal(datum.getId(), evaluator.cloneData(datum.getValue())); } } } http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java b/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java deleted file mode 100644 index faba709..0000000 --- a/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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; - -import org.apache.commons.scxml2.env.xpath.XPathEvaluator; - -/** - * Implementation and support of Commons SCXML builtin predicates to support XPath based datamodel operations - * for non-XPath languages. - * - * These static builtin functions delegate to a static {@link }XPathEvaluator} instance. - */ -public class XPathBuiltin { - - private static XPathEvaluator evaluator = new XPathEvaluator(); - - /** - * Optional static setter to change and override the default {@link XPathEvaluator} - * @param evaluator A custom evaluator to be used - */ - public static void setEvaluator(XPathEvaluator evaluator) { - XPathBuiltin.evaluator = evaluator; - } - - /** - * Evaluate an xpath expression returning a data value - * - * @param ctx variable context - * @param expression xpath expression - * @return the result of the evaluation - * @throws SCXMLExpressionException A malformed expression exception - * @see Evaluator#eval(Context, String) - */ - public static Object eval(Context ctx, String expression) throws SCXMLExpressionException { - return evaluator.eval(ctx, expression); - } - - /** - * Evaluate an xpath location that returns a data assignable reference or list of references. - * Manifests as "location" attributes of <assign> element. - * - * @param ctx variable context - * @param expression expression - * @return The location result. - * @throws SCXMLExpressionException A malformed expression exception - * @see Evaluator#evalLocation(Context, String) - */ - public static Object evalLocation(Context ctx, String expression) throws SCXMLExpressionException { - return evaluator.evalLocation(ctx, expression); - } - - /** - * Determine if an {@link Evaluator#evalLocation(Context, String)} returned result represents an XPath location - * @param ctx variable context - * @param data result data from {@link Evaluator#evalLocation(Context, String)} - * @return true if the data represents an XPath location - * @see XPathEvaluator#isXPathLocation(Context, Object) - */ - public static boolean isXPathLocation(Context ctx, Object data) { - return evaluator.isXPathLocation(ctx, data); - } - - /** - * Assigns data to a location - * - * @param ctx variable context - * @param location location expression - * @param data the data to assign. - * @param type the type of assignment to perform, null assumes {@link Evaluator.AssignType#REPLACE_CHILDREN} - * @param attr the name of the attribute to add when using type {@link Evaluator.AssignType#ADD_ATTRIBUTE} - * @throws SCXMLExpressionException A malformed expression exception - * @see Evaluator#evalAssign(Context, String, Object, Evaluator.AssignType, String) - * @see XPathEvaluator#assign(Context, Object, Object, Evaluator.AssignType, String) - */ - public static void assign(Context ctx, Object location, Object data, Evaluator.AssignType type, String attr) - throws SCXMLExpressionException { - evaluator.assign(ctx, location, data, type, attr); - } -} http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/AbstractBaseEvaluator.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/env/AbstractBaseEvaluator.java b/src/main/java/org/apache/commons/scxml2/env/AbstractBaseEvaluator.java new file mode 100644 index 0000000..abd96a4 --- /dev/null +++ b/src/main/java/org/apache/commons/scxml2/env/AbstractBaseEvaluator.java @@ -0,0 +1,82 @@ +/* + * 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; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.scxml2.Evaluator; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * Base Evaluator providing common functionality for most Evaluator implementations + */ +public abstract class AbstractBaseEvaluator implements Evaluator, Serializable { + + @Override + public Object cloneData(final Object data) { + if (data != null) { + if (data instanceof String || data instanceof Number || data instanceof Boolean) { + return data; + } + if (data instanceof Node) { + return ((Node)data).cloneNode(true); + } + else if (data instanceof NodeList) { + NodeList nodeList = (NodeList)data; + ArrayList<Node> list = new ArrayList<>(); + for (int i = 0, size = nodeList.getLength(); i < size; i++) { + list.add(nodeList.item(i).cloneNode(true)); + } + return list; + } + else if (data instanceof List) { + ArrayList<Object> list = new ArrayList<>(); + for (Object v : (List)data) { + list.add(cloneData(v)); + } + return list; + } + else if (data instanceof Map) { + Map<?,?> dataMap = (Map<?,?>)data; + HashMap<Object, Object> map = new LinkedHashMap<>(); + for (Map.Entry<?,?> entry : dataMap.entrySet()) { + map.put(cloneData(entry.getKey()), cloneData(entry.getValue())); + } + return map; + } + else { + return cloneUnknownDataType(data); + } + } + return data; + } + + /** + * Returns cloned value of data of unknown type, to be overridden as desired by specialized Evaluators + * @param data data object of unknown type (not of type String, Number, Boolean, Node, NodeList, List or Map) + * @return toString() value of data of unknown type + */ + protected Object cloneUnknownDataType(final Object data) { + return data.toString(); + } +} http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java b/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java index f67e7d1..c82d2d7 100644 --- a/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java +++ b/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java @@ -18,7 +18,6 @@ package org.apache.commons.scxml2.env.groovy; import groovy.lang.Script; -import java.io.Serializable; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -31,7 +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.SCXMLSystemContext; -import org.apache.commons.scxml2.XPathBuiltin; +import org.apache.commons.scxml2.env.AbstractBaseEvaluator; import org.apache.commons.scxml2.env.EffectiveContextMap; import org.apache.commons.scxml2.model.SCXML; @@ -41,7 +40,7 @@ import org.apache.commons.scxml2.model.SCXML; * This implementation itself is thread-safe, so you can keep singleton for efficiency. * </P> */ -public class GroovyEvaluator implements Evaluator, Serializable { +public class GroovyEvaluator extends AbstractBaseEvaluator { /** Serial version UID. */ private static final long serialVersionUID = 1L; @@ -256,26 +255,13 @@ public class GroovyEvaluator implements Evaluator, Serializable { */ public void evalAssign(final Context ctx, final String location, final Object data, final AssignType type, final String attr) throws SCXMLExpressionException { - - final Object loc = evalLocation(ctx, location); - if (loc != null) { - - if (XPathBuiltin.isXPathLocation(ctx, loc)) { - XPathBuiltin.assign(ctx, loc, data, type, attr); - } - else { - final StringBuilder sb = new StringBuilder(location).append("=").append(ASSIGN_VARIABLE_NAME); - try { - ctx.getVars().put(ASSIGN_VARIABLE_NAME, data); - eval(ctx, sb.toString()); - } - finally { - ctx.getVars().remove(ASSIGN_VARIABLE_NAME); - } - } + final StringBuilder sb = new StringBuilder(location).append("=").append(ASSIGN_VARIABLE_NAME); + try { + ctx.getVars().put(ASSIGN_VARIABLE_NAME, data); + eval(ctx, sb.toString()); } - else { - throw new SCXMLExpressionException("evalAssign - cannot resolve location: '" + location + "'"); + finally { + ctx.getVars().remove(ASSIGN_VARIABLE_NAME); } } http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java b/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java index 29407ef..5980211 100644 --- a/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java +++ b/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java @@ -25,13 +25,10 @@ import java.util.Collection; import java.util.Map; import org.apache.commons.scxml2.Builtin; -import org.apache.commons.scxml2.SCXMLExpressionException; -import org.apache.commons.scxml2.XPathBuiltin; /** - * Groovy {@link Script} base class for SCXML, providing the standard 'builtin' functions {@link #In(String)}, - * {@link #Data(String)} and {@link #Location(String)}, as well as JEXL like convenience functions - * {@link #empty(Object)} and {@link #var(String)}. + * Groovy {@link Script} base class for SCXML, providing the standard 'builtin' function {@link #In(String)}, + * as well as JEXL like convenience functions {@link #empty(Object)} and {@link #var(String)}. */ public abstract class GroovySCXMLScript extends Script { @@ -59,26 +56,6 @@ public abstract class GroovySCXMLScript extends Script { } /** - * Implements the Data() predicate for SCXML documents. - * @param expression the XPath expression - * @return the data matching the expression - * @throws SCXMLExpressionException A malformed expression exception - */ - public Object Data(final String expression) throws SCXMLExpressionException { - return XPathBuiltin.eval(context, expression); - } - - /** - * Implements the Location() predicate for SCXML documents. - * @param location the XPath expression - * @return the location list for the location expression - * @throws SCXMLExpressionException A malformed expression exception - */ - public Object Location(final String location) throws SCXMLExpressionException { - return XPathBuiltin.evalLocation(context, location); - } - - /** * The var function can be used to check if a variable is defined, * <p> * In the Groovy language (implementation) you cannot check for an undefined variable directly: http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/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 9fee8ea..ca0d8eb 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 @@ -29,23 +29,17 @@ import org.apache.commons.scxml2.Context; 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.AbstractBaseEvaluator; import org.apache.commons.scxml2.env.EffectiveContextMap; import org.apache.commons.scxml2.model.SCXML; /** * Embedded JavaScript expression evaluator for SCXML expressions. This * implementation is a just a 'thin' wrapper around the Javascript engine in - * JDK 6 (based on on Mozilla Rhino 1.6.2). - * <p> - * Mozilla Rhino 1.6.2 does not support E4X so accessing the SCXML data model - * is implemented in the same way as the JEXL expression evaluator i.e. using - * the Data() function, for example, - * <assign location="Data(hotelbooking,'hotel/rooms')" expr="2" /> - * </p> + * JDK 8. */ -public class JSEvaluator implements Evaluator { +public class JSEvaluator extends AbstractBaseEvaluator { /** * Unique context variable name used for temporary reference to assign data (thus must be a valid variable name) @@ -78,14 +72,10 @@ public class JSEvaluator implements Evaluator { /** 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. */ - private static final Pattern DATA_FN = Pattern.compile("Data\\("); - /** Pattern for recognizing the Commons SCXML Location() builtin function. */ - private static final Pattern LOCATION_FN = Pattern.compile("Location\\("); // INSTANCE VARIABLES - private ScriptEngineManager factory; + private transient ScriptEngineManager factory; // CONSTRUCTORS @@ -98,12 +88,32 @@ public class JSEvaluator implements Evaluator { // INSTANCE METHODS + protected ScriptEngineManager getFactory() { + if (factory == null) { + factory = new ScriptEngineManager(); + } + return factory; + } + @Override public String getSupportedDatamodel() { return SUPPORTED_DATA_MODEL; } /** + * @return Returns JavaScript "undefined" for null, otherwise inherited behavior + */ + @Override + public Object cloneData(final Object data) { + if (data == null) { + ScriptEngine engine = getFactory().getEngineByName("JavaScript"); + Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); + return bindings.get("undefined"); + } + return super.cloneData(data); + } + + /** * Creates a child context. * * @return Returns a new child JSContext. @@ -117,8 +127,8 @@ public class JSEvaluator implements Evaluator { /** * Evaluates the expression using a new Javascript engine obtained from * factory instantiated in the constructor. The engine is supplied with - * a new JSBindings that includes the SCXML Context and - * <code>Data()</code> functions are replaced with an equivalent internal + * a new JSBindings that includes the SCXML Context and SCXML builtin + * <code>In()</code> function is replaced with an equivalent internal * Javascript function. * * @param context SCXML context. @@ -142,13 +152,11 @@ public class JSEvaluator implements Evaluator { JSContext effectiveContext = getEffectiveContext((JSContext) context); // ... initialize - ScriptEngine engine = factory.getEngineByName("JavaScript"); + ScriptEngine engine = getFactory().getEngineByName("JavaScript"); Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); // ... replace built-in functions String jsExpression = IN_FN.matcher(expression).replaceAll("_builtin.In("); - jsExpression = DATA_FN.matcher(jsExpression).replaceAll("_builtin.Data("); - jsExpression = LOCATION_FN.matcher(jsExpression).replaceAll("_builtin.Location("); // ... evaluate JSBindings jsBindings = new JSBindings(effectiveContext, bindings); @@ -196,8 +204,8 @@ public class JSEvaluator implements Evaluator { /** * Evaluates a location expression using a new Javascript engine obtained from * factory instantiated in the constructor. The engine is supplied with - * a new JSBindings that includes the SCXML Context and - * <code>Data()</code> functions are replaced with an equivalent internal + * a new JSBindings that includes the SCXML Context and SCXML builtin + * <code>In()</code> function is replaced with an equivalent internal * Javascript function. * * @param context FSM context. @@ -221,32 +229,20 @@ public class JSEvaluator implements Evaluator { */ public void evalAssign(final Context ctx, final String location, final Object data, final AssignType type, final String attr) throws SCXMLExpressionException { - - Object loc = evalLocation(ctx, location); - - if (loc != null) { - if (XPathBuiltin.isXPathLocation(ctx, loc)) { - XPathBuiltin.assign(ctx, loc, data, type, attr); - } else { - StringBuilder sb = new StringBuilder(location).append("=").append(ASSIGN_VARIABLE_NAME); - - try { - ctx.getVars().put(ASSIGN_VARIABLE_NAME, data); - eval(ctx, sb.toString()); - } finally { - ctx.getVars().remove(ASSIGN_VARIABLE_NAME); - } - } - } else { - throw new SCXMLExpressionException("evalAssign - cannot resolve location: '" + location + "'"); + StringBuilder sb = new StringBuilder(location).append("=").append(ASSIGN_VARIABLE_NAME); + try { + ctx.getVars().put(ASSIGN_VARIABLE_NAME, data); + eval(ctx, sb.toString()); + } finally { + ctx.getVars().remove(ASSIGN_VARIABLE_NAME); } } /** * Executes the script using a new Javascript engine obtained from * factory instantiated in the constructor. The engine is supplied with - * a new JSBindings that includes the SCXML Context and - * <code>Data()</code> functions are replaced with an equivalent internal + * a new JSBindings that includes the SCXML Context and SCXML builtin + * <code>In()</code> function is replaced with an equivalent internal * Javascript function. * * @param ctx SCXML context. http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java b/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java index bf99ee7..45771a0 100644 --- a/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java +++ b/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java @@ -20,12 +20,9 @@ import java.io.Serializable; import org.apache.commons.scxml2.Builtin; import org.apache.commons.scxml2.Context; -import org.apache.commons.scxml2.SCXMLExpressionException; -import org.apache.commons.scxml2.XPathBuiltin; /** - * Custom Javascript engine function providing the SCXML In() predicate and the Commons SCXML extensions - * for Data() and Location() to support XPath datamodel access. + * Custom Javascript engine function providing the SCXML In() predicate . */ public class JSFunctions implements Serializable { @@ -50,24 +47,4 @@ public class JSFunctions implements Serializable { public boolean In(final String state) { return Builtin.isMember(ctx, state); } - - /** - * Provides the Commons SCXML Data() predicate extension for SCXML documents. - * @param expression the XPath expression - * @return the data matching the expression - * @throws SCXMLExpressionException A malformed expression exception - */ - public Object Data(String expression) throws SCXMLExpressionException { - return XPathBuiltin.eval(ctx, expression); - } - - /** - * Provides the Commons SCXML Location() predicate extension for SCXML documents. - * @param expression the XPath expression - * @return the location matching the expression - * @throws SCXMLExpressionException A malformed expression exception - */ - public Object Location(String expression) throws SCXMLExpressionException { - return XPathBuiltin.evalLocation(ctx, expression); - } } http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java b/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java index b1ece86..cddd0f5 100644 --- a/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java +++ b/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java @@ -17,12 +17,9 @@ package org.apache.commons.scxml2.env.jexl; import org.apache.commons.scxml2.Builtin; -import org.apache.commons.scxml2.SCXMLExpressionException; -import org.apache.commons.scxml2.XPathBuiltin; /** - * Global JEXL namespace functor, providing the standard SCXML In() operator and the Commons SCXML extensions - * for Data() and Location() to support XPath datamodel access. + * Global JEXL namespace functor, providing the standard SCXML In() predicate. */ public final class JexlBuiltin { /** @@ -46,24 +43,4 @@ public final class JexlBuiltin { public boolean In(final String state) { return Builtin.isMember(context, state); } - - /** - * Provides the Commons SCXML Data() predicate extension for SCXML documents. - * @param expression the XPath expression - * @return the data matching the expression - * @throws SCXMLExpressionException A malformed expression exception - */ - public Object Data(final String expression) throws SCXMLExpressionException { - return XPathBuiltin.eval(context, expression); - } - - /** - * Provides the Commons SCXML Location() predicate extension for SCXML documents. - * @param expression the XPath expression - * @return the location matching the expression - * @throws SCXMLExpressionException A malformed expression exception - */ - public Object Location(final String expression) throws SCXMLExpressionException { - return XPathBuiltin.evalLocation(context, expression); - } } http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java b/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java index 3dd0088..d08946c 100644 --- a/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java +++ b/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java @@ -16,7 +16,6 @@ */ package org.apache.commons.scxml2.env.jexl; -import java.io.Serializable; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -28,7 +27,7 @@ import org.apache.commons.scxml2.Context; 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.AbstractBaseEvaluator; import org.apache.commons.scxml2.env.EffectiveContextMap; import org.apache.commons.scxml2.model.SCXML; @@ -40,7 +39,7 @@ import org.apache.commons.scxml2.model.SCXML; * for efficiency of the internal <code>JexlEngine</code> member. * </P> */ -public class JexlEvaluator implements Evaluator, Serializable { +public class JexlEvaluator extends AbstractBaseEvaluator { /** Serial version UID. */ private static final long serialVersionUID = 1L; @@ -222,26 +221,13 @@ public class JexlEvaluator implements Evaluator, Serializable { */ public void evalAssign(final Context ctx, final String location, final Object data, final AssignType type, final String attr) throws SCXMLExpressionException { - - Object loc = evalLocation(ctx, location); - if (loc != null) { - - if (XPathBuiltin.isXPathLocation(ctx, loc)) { - XPathBuiltin.assign(ctx, loc, data, type, attr); - } - else { - StringBuilder sb = new StringBuilder(location).append("=").append(ASSIGN_VARIABLE_NAME); - try { - ctx.getVars().put(ASSIGN_VARIABLE_NAME, data); - eval(ctx, sb.toString()); - } - finally { - ctx.getVars().remove(ASSIGN_VARIABLE_NAME); - } - } + StringBuilder sb = new StringBuilder(location).append("=").append(ASSIGN_VARIABLE_NAME); + try { + ctx.getVars().put(ASSIGN_VARIABLE_NAME, data); + eval(ctx, sb.toString()); } - else { - throw new SCXMLExpressionException("evalAssign - cannot resolve location: '" + location + "'"); + finally { + ctx.getVars().remove(ASSIGN_VARIABLE_NAME); } } http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/minimal/MinimalEvaluator.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/env/minimal/MinimalEvaluator.java b/src/main/java/org/apache/commons/scxml2/env/minimal/MinimalEvaluator.java index 401df4e..66c18e5 100644 --- a/src/main/java/org/apache/commons/scxml2/env/minimal/MinimalEvaluator.java +++ b/src/main/java/org/apache/commons/scxml2/env/minimal/MinimalEvaluator.java @@ -62,6 +62,11 @@ public class MinimalEvaluator implements Evaluator, Serializable { } @Override + public Object cloneData(final Object data) { + return data; + } + + @Override public Object eval(final Context ctx, final String expr) throws SCXMLExpressionException { return expr; } http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java b/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java index 763f090..0da7103 100644 --- a/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java +++ b/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java @@ -16,7 +16,6 @@ */ package org.apache.commons.scxml2.env.xpath; -import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -34,6 +33,7 @@ import org.apache.commons.scxml2.Context; import org.apache.commons.scxml2.Evaluator; import org.apache.commons.scxml2.EvaluatorProvider; import org.apache.commons.scxml2.SCXMLExpressionException; +import org.apache.commons.scxml2.env.AbstractBaseEvaluator; import org.apache.commons.scxml2.env.EffectiveContextMap; import org.apache.commons.scxml2.model.SCXML; import org.w3c.dom.Attr; @@ -48,7 +48,7 @@ import org.w3c.dom.NodeList; * <p>Does not support the <script> module, throws * {@link UnsupportedOperationException} if attempted.</p> */ -public class XPathEvaluator implements Evaluator, Serializable { +public class XPathEvaluator extends AbstractBaseEvaluator { /** Serial version UID. */ private static final long serialVersionUID = -3578920670869493294L; http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/io/ContentParser.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/io/ContentParser.java b/src/main/java/org/apache/commons/scxml2/io/ContentParser.java new file mode 100644 index 0000000..eb044eb --- /dev/null +++ b/src/main/java/org/apache/commons/scxml2/io/ContentParser.java @@ -0,0 +1,217 @@ +/* + * 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.io; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.apache.commons.io.IOUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +/** + * The ContentParser provides utility methods for cleaning content strings and parsing them into "raw" content model Objects + */ +public class ContentParser { + + public static final ContentParser DEFAULT_PARSER = new ContentParser(); + + /** + * Jackson JSON ObjectMapper + */ + private ObjectMapper jsonObjectMapper; + + /** + * Default constructor initializing a Jackson ObjectMapper allowing embedded comments, including YAML style + */ + public ContentParser() { + this.jsonObjectMapper = new ObjectMapper(); + jsonObjectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); + jsonObjectMapper.configure(JsonParser.Feature.ALLOW_YAML_COMMENTS, true); + } + + /** + * Constructor with a custom configured Jackson ObjectMapper + * @param jsonObjectMapper custom configured Jackson ObjectMapper + */ + public ContentParser(final ObjectMapper jsonObjectMapper) { + this.jsonObjectMapper = jsonObjectMapper; + } + + /** + * Trim pre/post-fixed whitespace from content string + * @param content content to trim + * @return trimmed content + */ + public static String trimContent(final String content) { + if (content != null) { + int start = 0; + int length = content.length(); + while (start < length && isWhiteSpace(content.charAt(start))) { + start++; + } + while (length > start && isWhiteSpace(content.charAt(length - 1))) { + length--; + } + if (start == length) { + return ""; + } + return content.substring(start, length); + } + return null; + } + + /** + * Space normalize content string, trimming pre/post-fixed whitespace and collapsing embedded whitespaces to + * single space. + * @param content content to space-normalize + * @return space-normalized content + */ + public static String spaceNormalizeContent(final String content) { + if (content != null) { + int index = 0; + int length = content.length(); + StringBuilder buffer = new StringBuilder(length); + boolean whiteSpace = false; + while (index < length) { + if (isWhiteSpace(content.charAt(index))) { + if (!whiteSpace && buffer.length() > 0) { + buffer.append(' '); + whiteSpace = true; + } + } + else { + buffer.append(content.charAt(index)); + whiteSpace = false; + } + index++; + } + if (whiteSpace) { + buffer.setLength(buffer.length()-1); + } + return buffer.toString(); + } + return null; + } + + /** + * Check if a character is whitespace (space, tab, newline, cr) or not + * @param c character to check + * @return true if character is whitespace + */ + public static boolean isWhiteSpace(final char c) { + return c==' ' || c=='\n' || c=='\t' || c=='\r'; + } + + /** + * Check if content starts with JSON object '{' or array '[' marker + * @param content text to check + * @return true if content start with '{' or '[' character + */ + public static boolean hasJsonSignature(final String content) { + final char c = content.length() > 0 ? content.charAt(0) : 0; + return c == '{' || c == '['; + } + + /** + * Check if content indicates its an XML document + * @param content content to check + * @return true if content indicates its an XML document + */ + public static boolean hasXmlSignature(final String content) { + return content != null && content.startsWith("<?xml "); + } + + /** + * Parse and map JSON string to 'raw' Java Objects: object -> LinkedHashMap, array -> ArrayList + * @param jsonString JSON string to parse + * @return 'raw' mapped Java Object for JSON string + * @throws IOException In case of parsing exceptions + */ + public Object parseJson(final String jsonString) throws IOException { + return jsonObjectMapper.readValue(jsonString, Object.class); + } + + /** + * Parse an XML String and return the document element + * @param xmlString XML String to parse + * @return document element + * @throws IOException + */ + public Node parseXml(final String xmlString) throws IOException { + Document doc = null; + try { + doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlString); + } catch (SAXException e) { + throw new IOException(e); + } catch (ParserConfigurationException e) { + throw new IOException(e); + } + return doc != null ? doc.getDocumentElement() : null; + } + + /** + * Parse a string into a content object, following the SCXML rules as specified for the ECMAscript (section B.2.1) Data Model + * <ul> + * <li>if the content can be interpreted as JSON, it will be parsed as JSON into an 'raw' object model</li> + * <li>if the content can be interpreted as XML, it will be parsed into a XML DOM element</li> + * <li>otherwise the content will be treated (cleaned) as a space-normalized string literal</li> + * </ul> + * @param content the content to parse + * @return the parsed content object + * @throws IOException In case of parsing exceptions + */ + public Object parseContent(final String content) throws IOException { + if (content != null) { + String src = trimContent(content); + if (hasJsonSignature(src)) { + return parseJson(src); + } + else if (hasXmlSignature(src)) { + return parseXml(src); + } + return spaceNormalizeContent(src); + } + return null; + } + + /** + * Load a resource (URL) as an UTF-8 encoded content string to be parsed into a content object through {@link #parseContent(String)} + * @param resourceURL Resource URL to load content from + * @return the parsed content object + * @throws IOException In case of loading or parsing exceptions + */ + public Object parseResource(final String resourceURL) throws IOException { + InputStream in = null; + try { + in = new URL(resourceURL).openStream(); + String content = IOUtils.toString(in, "UTF-8"); + return parseContent(content); + } + finally { + IOUtils.closeQuietly(in); + } + } +} http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java b/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java index d4d2715..2bb0a0e 100644 --- a/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java +++ b/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java @@ -1096,7 +1096,27 @@ public final class SCXMLReader { datum.setId(readRequiredAV(reader, ELEM_DATA, ATTR_ID)); datum.setExpr(readAV(reader, ATTR_EXPR)); readNamespaces(configuration, datum); - datum.setNode(readNode(reader, configuration, XMLNS_SCXML, ELEM_DATA, new String[]{"id"})); + Node node = readNode(reader, configuration, XMLNS_SCXML, ELEM_DATA, new String[]{"id"}); + datum.setNode(node); + if (node.hasChildNodes()) { + NodeList children = node.getChildNodes(); + if (children.getLength() == 1 && children.item(0).getNodeType() == Node.TEXT_NODE) { + String text = configuration.contentParser.trimContent(children.item(0).getNodeValue()); + if (configuration.contentParser.hasJsonSignature(text)) { + try { + datum.setValue(configuration.contentParser.parseJson(text)); + } catch (IOException e) { + throw new ModelException(e); + } + } + else { + datum.setValue(configuration.contentParser.spaceNormalizeContent(text)); + } + } + } + if (datum.getValue() == null) { + datum.setValue(node); + } dm.addData(datum); } @@ -2700,6 +2720,8 @@ public final class SCXMLReader { */ boolean strict; + ContentParser contentParser; + /* * Public constructors */ @@ -2872,6 +2894,7 @@ public final class SCXMLReader { this.namespaces = new HashMap<String, Stack<String>>(); this.silent = silent; this.strict = strict; + this.contentParser = new ContentParser(); } /* http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/model/Assign.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/model/Assign.java b/src/main/java/org/apache/commons/scxml2/model/Assign.java index 172aa85..6d07b3e 100644 --- a/src/main/java/org/apache/commons/scxml2/model/Assign.java +++ b/src/main/java/org/apache/commons/scxml2/model/Assign.java @@ -17,19 +17,13 @@ package org.apache.commons.scxml2.model; import java.io.IOException; - -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.FactoryConfigurationError; -import javax.xml.parsers.ParserConfigurationException; - import org.apache.commons.logging.LogFactory; import org.apache.commons.scxml2.ActionExecutionContext; import org.apache.commons.scxml2.Context; import org.apache.commons.scxml2.Evaluator; import org.apache.commons.scxml2.PathResolver; import org.apache.commons.scxml2.SCXMLExpressionException; -import org.w3c.dom.*; -import org.xml.sax.SAXException; +import org.apache.commons.scxml2.io.ContentParser; /** * The class in this SCXML object model that corresponds to the @@ -180,7 +174,7 @@ public class Assign extends Action implements PathResolverHolder { ctx.setLocal(getNamespacesKey(), getNamespaces()); Object data; if (src != null && src.trim().length() > 0) { - data = getSrcNode(); + data = getSrcData(); } else { data = evaluator.eval(ctx, expr); } @@ -192,41 +186,28 @@ public class Assign extends Action implements PathResolverHolder { // TODO: introduce a optional 'trace.change' setting or something alike to enable .change events, // but don't do this by default as it can interfere with transitions not expecting such events /* - if ((Evaluator.XPATH_DATA_MODEL.equals(evaluator.getSupportedDatamodel()) && location.startsWith("$") && ctx.has(location.substring(1)) - || ctx.has(location))) { TriggerEvent ev = new TriggerEvent(location + ".change", TriggerEvent.CHANGE_EVENT); exctx.getInternalIOProcessor().addEvent(ev); - } */ ctx.setLocal(getNamespacesKey(), null); } /** - * Get the {@link Node} the "src" attribute points to. + * Get the data the "src" attribute points to. * - * @return The node the "src" attribute points to. + * @return The data the "src" attribute points to. */ - private Node getSrcNode() { + private Object getSrcData() { String resolvedSrc = src; if (pathResolver != null) { resolvedSrc = pathResolver.resolvePath(src); } - Document doc = null; try { - doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(resolvedSrc); - } catch (FactoryConfigurationError t) { - logError(t); - } catch (SAXException e) { - logError(e); + return ContentParser.DEFAULT_PARSER.parseResource(resolvedSrc); } catch (IOException e) { logError(e); - } catch (ParserConfigurationException e) { - logError(e); - } - if (doc == null) { return null; } - return doc.getDocumentElement(); } /** http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/model/Data.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/model/Data.java b/src/main/java/org/apache/commons/scxml2/model/Data.java index be5efd0..0771bf5 100644 --- a/src/main/java/org/apache/commons/scxml2/model/Data.java +++ b/src/main/java/org/apache/commons/scxml2/model/Data.java @@ -40,7 +40,7 @@ public class Data implements NamespacePrefixesHolder, Serializable { private String id; /** - * The URL to get the XML data tree from. + * The URL to get the data from. */ private String src; @@ -50,12 +50,17 @@ public class Data implements NamespacePrefixesHolder, Serializable { private String expr; /** - * The child XML data tree, parsed as a Node, cloned per execution + * The child XML data tree, parsed as a Node * instance. */ private Node node; /** + * The parsed value for the child XML data tree or the external src (with early-binding), to be cloned before usage + */ + private Object value; + + /** * The current XML namespaces in the SCXML document for this action node, * preserved for deferred XPath evaluation. Easier than to scrape node * above, given the Builtin API. @@ -63,16 +68,6 @@ public class Data implements NamespacePrefixesHolder, Serializable { private Map<String, String> namespaces; /** - * Constructor. - */ - public Data() { - this.id = null; - this.src = null; - this.expr = null; - this.node = null; - } - - /** * Get the id. * * @return String An identifier. @@ -91,7 +86,7 @@ public class Data implements NamespacePrefixesHolder, Serializable { } /** - * Get the URL where the XML data tree resides. + * Get the URL for external data. * * @return String The URL. */ @@ -100,7 +95,7 @@ public class Data implements NamespacePrefixesHolder, Serializable { } /** - * Set the URL where the XML data tree resides. + * Set the URL for external data. * * @param src The source URL. */ @@ -127,24 +122,46 @@ public class Data implements NamespacePrefixesHolder, Serializable { } /** - * Get the XML data tree. + * Get the child XML data tree. * - * @return Node The XML data tree, parsed as a <code>Node</code>. + * @return Node The child XML data tree, parsed as a standalone DocumentFragment <code>Node</code>. */ public final Node getNode() { return node; } /** - * Set the XML data tree. + * Set the child XML data tree. * - * @param node The XML data tree, parsed as a <code>Node</code>. + * @param node The child XML data tree, parsed as a standalone DocumentFragment <code>Node</code>. */ public final void setNode(final Node node) { this.node = node; } /** + * Get the parsed value for the child XML data tree or the external src (with early-binding), to be cloned before usage. + * @see #setValue(Object) + * @return The parsed Data value + */ + public final Object getValue() { + return value; + } + + /** + * Sets the parsed value for the child XML data tree or the external src (with early-binding), to be cloned before usage. + * @param value a serializable object: + * <ul> + * <li>"Raw" JSON mapped object tree (array->ArrayList, object->LinkedHashMap based)</li> + * <li>XML Node (equals {@link #getNode()})</li> + * <li>space-normalized String</li> + * </ul> + */ + public final void setValue(final Object value) { + this.value = value; + } + + /** * Get the XML namespaces at this action node in the SCXML document. * * @return Returns the map of namespaces. http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/NamespacePrefixedXPathsTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/scxml2/NamespacePrefixedXPathsTest.java b/src/test/java/org/apache/commons/scxml2/NamespacePrefixedXPathsTest.java deleted file mode 100644 index c0164b4..0000000 --- a/src/test/java/org/apache/commons/scxml2/NamespacePrefixedXPathsTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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; - -import java.util.Set; - -import org.apache.commons.scxml2.model.EnterableState; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit tests for namespace prefixes in XPaths pointing bits in a <data>. - */ -public class NamespacePrefixedXPathsTest { - - /** - * Test the XPath evaluation - */ - // JEXL - @Test - public void testNamespacePrefixedXPathsJexl() throws Exception { - SCXMLExecutor exec = SCXMLTestHelper.getExecutor("org/apache/commons/scxml2/env/jexl/datamodel-03.xml"); - exec.go(); - runtest(exec); - } - - // Same test, since same documents (different expression languages) - private void runtest(SCXMLExecutor exec) throws Exception { - // must be in state "ten" at the onset - Set<EnterableState> currentStates = exec.getStatus().getStates(); - Assert.assertEquals(1, currentStates.size()); - Assert.assertEquals("ten", currentStates.iterator().next().getId()); - - // should move to "twenty" - currentStates = SCXMLTestHelper.fireEvent(exec, "done.state.ten"); - Assert.assertEquals(1, currentStates.size()); - Assert.assertEquals("twenty", currentStates.iterator().next().getId()); - - // This is set while exiting "ten" - Double retval = (Double) exec.getGlobalContext().get("retval"); - Assert.assertEquals(Double.valueOf("11"), retval); - - // On to "thirty" - currentStates = SCXMLTestHelper.fireEvent(exec, "done.state.twenty"); - Assert.assertEquals(1, currentStates.size()); - Assert.assertEquals("thirty", currentStates.iterator().next().getId()); - exec = SCXMLTestHelper.testInstanceSerializability(exec); - - // Tests XPath on SCXML actions, set while exiting "twenty" - String retvalstr = (String) exec.getGlobalContext().get("retval"); - Assert.assertEquals("Equal to 20", retvalstr); - - // and so on ... - currentStates = SCXMLTestHelper.fireEvent(exec, "done.state.thirty"); - Assert.assertEquals(1, currentStates.size()); - Assert.assertEquals("forty", currentStates.iterator().next().getId()); - - currentStates = SCXMLTestHelper.fireEvent(exec, "done.state.forty"); - Assert.assertEquals(1, currentStates.size()); - Assert.assertEquals("fifty", currentStates.iterator().next().getId()); - - currentStates = SCXMLTestHelper.fireEvent(exec, "done.state.fifty"); - Assert.assertEquals(1, currentStates.size()); - Assert.assertEquals("sixty", (currentStates.iterator(). - next()).getId()); - - currentStates = SCXMLTestHelper.fireEvent(exec, "done.state.sixty"); - Assert.assertEquals(1, currentStates.size()); - Assert.assertEquals("seventy", currentStates.iterator().next().getId()); - - // done - Assert.assertTrue(exec.getStatus().isFinal()); - } -} - http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-01.xml ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-01.xml b/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-01.xml new file mode 100644 index 0000000..4edc4df --- /dev/null +++ b/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-01.xml @@ -0,0 +1,84 @@ +<?xml version="1.0"?> +<!-- + * 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. +--> +<!-- A fictitious state machine used by test cases. + Meant to illustrate the usage of SCXML <datamodel> element --> +<scxml xmlns="http://www.w3.org/2005/07/scxml" + version="1.0" + datamodel="groovy" + initial="main"> + + <!-- Root or document datamodel --> + <datamodel> + <data id="docdata">{ "root" : { "foo" : { "bar" : "alpha" } } }</data> + </datamodel> + + <state id="main"> + + <initial> + <transition target="ten"/> + </initial> + + <!-- datamodel scoped to state "main" --> + <datamodel> + <!-- Degenerate usage, similar to the <var> element --> + <data id="mainvar" expr="0" /> + <!-- Usage where the value is an JSON model --> + <data id="maindata">{ "root" : { "a" : { "b" : { "c" : "beta", "d" : 123, "e" : 456.789 } } } }</data> + </datamodel> + + <state id="ten"> + <onentry> + <assign location="mainvar" expr="10" /> + </onentry> + <transition event="done.state.ten" + cond="mainvar eq 10 and maindata.root.a.b.c eq 'beta'" + target="twenty" /> + <onexit> + <assign location="maindata.root.a.b.c" expr="'gamma'" /> + </onexit> + </state> + + <state id="twenty"> + <onentry> + <assign location="mainvar" expr="20" /> + </onentry> + <transition event="done.state.twenty" + cond="maindata.root.a.b.c eq 'gamma' and mainvar eq 20" + target="thirty" /> + <onexit> + <assign location="docdata.root.foo" + expr="maindata.root" /> + </onexit> + </state> + + <state id="thirty"> + <!-- Arithmetic operations. + Note that data "docdata" + did not have data at 'root.foo.a.b.d' to begin with, + the data model was manipulated by the <assign> above --> + <transition event="done.state.thirty" + cond="docdata.root.foo.a.b.d + docdata.root.foo.a.b.e eq 579.789" + target="forty" /> + </state> + + <final id="forty"/> + + </state> + +</scxml> + http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-05.xml ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-05.xml b/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-05.xml new file mode 100644 index 0000000..55f5b9e --- /dev/null +++ b/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-05.xml @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<!-- + * 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. +--> +<!-- A fictitious state machine used by test cases. --> +<scxml xmlns="http://www.w3.org/2005/07/scxml" + version="1.0" + datamodel="groovy" + initial="start"> + + <datamodel> + + <data id="airline"> + { + "flight" : + { + "origin" : null, + "destination" : null, + "trip" : "round", + "class" : "economy", + "meal" : null, + "dates" : + [ + { + "startdate" : "01/01/2009", + "enddate" : "01/05/2009" + }, + { + "startdate" : "01/26/2009", + "enddate" : "01/31/2009" + } + ] + } + } + </data> + + <data id="hotel"> + { + "hotel" : + { + "stay" : + { + "delete" : "foo" + }, + "adults" : 1, + "children" : 0, + "rooms" : 1, + "rate" : null + } + } + </data> + + </datamodel> + + <state id="start"> + <onentry> + <log label="subtree copy - delete (should be foo)" expr="hotel.hotel.stay['delete']"/> + <assign location="hotel.hotel.stay" expr="airline.flight.dates[1]"/> + <log label="subtree copy - delete (should be null)" expr="hotel.hotel.stay['delete']"/> + </onentry> + <transition cond="hotel.hotel.stay.startdate eq '01/26/2009'" target="end" /> + </state> + + <final id="end"/> + +</scxml> + http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/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 28d923e..2f8b403 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 @@ -18,6 +18,7 @@ package org.apache.commons.scxml2.env.javascript; import java.io.StringReader; +import java.util.Map; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; @@ -52,25 +53,25 @@ public class JSEvaluatorTest { private static final String BAD_EXPRESSION = ">"; private static final String SCRIPT = "<?xml version='1.0'?>" + - "<scxml xmlns = 'http://www.w3.org/2005/07/scxml' " + - "xmlns:scxml = 'http://commons.apache.org/scxml' " + - "datamodel = 'ecmascript' " + - "initial = 'start' " + - "version = '1.0'>" + - "<datamodel>" + - "<data id='forest'>" + - "<tree xmlns=''>" + - "<branch>" + - "<twig>leaf</twig>" + - "</branch>" + - "</tree>" + - "</data>" + - "</datamodel>" + - "<state id='start'>" + - "<transition target='end' />" + - "</state>" + - "<state id='end' final='true' />" + - "</scxml>"; + "<scxml xmlns = 'http://www.w3.org/2005/07/scxml'" + + " xmlns:scxml = 'http://commons.apache.org/scxml'" + + " datamodel = 'ecmascript'" + + " initial = 'start'" + + " version = '1.0'>" + + " <datamodel>" + + " <data id='forest'>" + + " { \"tree\" :" + + " { \"branch\" :" + + " { \"twig\" : \"leaf\" }" + + " }" + + " }" + + " </data>" + + " </datamodel>" + + " <state id='start'>" + + " <transition target='end'/>" + + " </state>" + + " <state id='end' final='true'/>" + + "</scxml>"; private static final TestItem[] SIMPLE_EXPRESSIONS = { new TestItem("'FIB: ' + (1 + 1 + 2 + 3 + 5)",new String("FIB: 12")), @@ -241,9 +242,9 @@ public class JSEvaluatorTest { */ @Test public void testDataModelExpressions() throws Exception { - Assert.assertEquals("Invalid result: " + "Data('string($forest/tree/branch/twig)')", + Assert.assertEquals("Invalid result: " + "forest.tree.branch.twig", "leaf", - evaluator.eval(context,"Data('string($forest/tree/branch/twig)')")); + evaluator.eval(context,"forest.tree.branch.twig")); } /** @@ -255,8 +256,8 @@ public class JSEvaluatorTest { Assert.assertNull(context.get("forestx")); try { - evaluator.eval(context,"Data(forestx,'string($forestx/tree/branch/twig)')"); - Assert.fail ("Evaluated invalid Data() expression: " + "Data('string($forestx/tree/branch/twig)')"); + evaluator.eval(context,"forestx.tree.branch.twig"); + Assert.fail ("Evaluated invalid DataModel expression: " + "forestx.tree.branch.twig"); } catch (SCXMLExpressionException x) { // expected, ignore @@ -269,17 +270,11 @@ public class JSEvaluatorTest { */ @Test public void testDataModelLocations() throws Exception { - Assert.assertNotNull(context.get("forest")); - XPath xpath = XPathFactory.newInstance().newXPath(); - Node node = (Node) context.get("forest"); - Node twig = (Node) xpath.evaluate("tree/branch/twig", node, XPathConstants.NODE); - - Assert.assertTrue ("Invalid result: " + "Data(forest,'$forest/tree/branch/twig')", - evaluator.eval(context,"Data('$forest/tree/branch/twig')") instanceof Element); + Assert.assertTrue("Invalid result: forest instanceof Map", + evaluator.eval(context, "forest") instanceof Map); - Assert.assertSame ("Incorrect node returned: " + "Data('$forest/tree/branch/twig')", - twig, - evaluator.eval(context,"Data('$forest/tree/branch/twig')")); + Assert.assertTrue("Invalid result: forest.tree.branch.twig instanceof String", + evaluator.eval(context, "forest.tree.branch.twig") instanceof String); } /** @@ -289,8 +284,8 @@ public class JSEvaluatorTest { @Test public void testInvalidDataModelLocations() throws Exception { Assert.assertNotNull(context.get("forest")); - Assert.assertNull("Invalid result: " + "Data('$forest/tree/branch/twigx')", - evaluator.eval(context,"Data('$forest/tree/branch/twigx')")); + Assert.assertNull("Invalid result: " + "forest.tree.branch.twigx", + evaluator.eval(context,"forest.tree.branch.twigx")); } /** http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-01.xml ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-01.xml b/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-01.xml new file mode 100644 index 0000000..3234099 --- /dev/null +++ b/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-01.xml @@ -0,0 +1,84 @@ +<?xml version="1.0"?> +<!-- + * 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. +--> +<!-- A fictitious state machine used by test cases. + Meant to illustrate the usage of SCXML <datamodel> element --> +<scxml xmlns="http://www.w3.org/2005/07/scxml" + version="1.0" + datamodel="ecmascript" + initial="main"> + + <!-- Root or document datamodel --> + <datamodel> + <data id="docdata">{ "root" : { "foo" : { "bar" : "alpha" } } }</data> + </datamodel> + + <state id="main"> + + <initial> + <transition target="ten"/> + </initial> + + <!-- datamodel scoped to state "main" --> + <datamodel> + <!-- Degenerate usage, similar to the <var> element --> + <data id="mainvar" expr="0" /> + <!-- Usage where the value is an JSON model --> + <data id="maindata">{ "root" : { "a" : { "b" : { "c" : "beta", "d" : 123, "e" : 456.789 } } } }</data> + </datamodel> + + <state id="ten"> + <onentry> + <assign location="mainvar" expr="10" /> + </onentry> + <transition event="done.state.ten" + cond="mainvar == 10 && maindata.root.a.b.c == 'beta'" + target="twenty" /> + <onexit> + <assign location="maindata.root.a.b.c" expr="'gamma'" /> + </onexit> + </state> + + <state id="twenty"> + <onentry> + <assign location="mainvar" expr="20" /> + </onentry> + <transition event="done.state.twenty" + cond="maindata.root.a.b.c == 'gamma' && mainvar == 20" + target="thirty" /> + <onexit> + <assign location="docdata.root.foo" + expr="maindata.root" /> + </onexit> + </state> + + <state id="thirty"> + <!-- Arithmetic operations. + Note that data "docdata" + did not have data at 'root.foo.a.b.d' to begin with, + the data model was manipulated by the <assign> above --> + <transition event="done.state.thirty" + cond="docdata.root.foo.a.b.d + docdata.root.foo.a.b.e == 579.789" + target="forty" /> + </state> + + <final id="forty"/> + + </state> + +</scxml> + http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-05.xml ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-05.xml b/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-05.xml new file mode 100644 index 0000000..75817f0 --- /dev/null +++ b/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-05.xml @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<!-- + * 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. +--> +<!-- A fictitious state machine used by test cases. --> +<scxml xmlns="http://www.w3.org/2005/07/scxml" + version="1.0" + datamodel="ecmascript" + initial="start"> + + <datamodel> + + <data id="airline"> + { + "flight" : + { + "origin" : null, + "destination" : null, + "trip" : "round", + "class" : "economy", + "meal" : null, + "dates" : + [ + { + "startdate" : "01/01/2009", + "enddate" : "01/05/2009" + }, + { + "startdate" : "01/26/2009", + "enddate" : "01/31/2009" + } + ] + } + } + </data> + + <data id="hotel"> + { + "hotel" : + { + "stay" : + { + "delete" : "foo" + }, + "adults" : 1, + "children" : 0, + "rooms" : 1, + "rate" : null + } + } + </data> + + </datamodel> + + <state id="start"> + <onentry> + <log label="subtree copy - delete (should be foo)" expr="hotel.hotel.stay['delete']"/> + <assign location="hotel.hotel.stay" expr="airline.flight.dates[1]"/> + <log label="subtree copy - delete (should be null)" expr="hotel.hotel.stay['delete']"/> + </onentry> + <transition cond="hotel.hotel.stay.startdate == '01/26/2009'" target="end" /> + </state> + + <final id="end"/> + +</scxml> + http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/javascript/example-01.xml ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/scxml2/env/javascript/example-01.xml b/src/test/java/org/apache/commons/scxml2/env/javascript/example-01.xml index 5fbd7a7..72898d5 100644 --- a/src/test/java/org/apache/commons/scxml2/env/javascript/example-01.xml +++ b/src/test/java/org/apache/commons/scxml2/env/javascript/example-01.xml @@ -27,16 +27,21 @@ <datamodel> <data id='jungle'> - <animals xmlns=''> - <lion> - <name>Simba</name> - <age>12</age> - </lion> - <tiger> - <name>Sher Khan</name> - <age>13</age> - </tiger> - </animals> + { + "animals" : + { + "lion" : + { + "name" : "Simba", + "age" : 12 + }, + "tiger" : + { + "name" : "Sher Khan", + "age" : 13 + } + } + } </data> </datamodel> @@ -88,11 +93,11 @@ <state id='javascript.datamodel'> <onentry> - <log expr='"Lion : " + Data("string(jungle/animals/lion/name)") + "," + Data("string(jungle/animals/lion/age)")' /> - <log expr='"Tiger: " + Data("string(jungle/animals/tiger/name)") + "," + Data("string(jungle/animals/tiger/age)")' /> - <assign location='Location("jungle/animals/lion/age")' expr='Data("jungle/animals/tiger/age")' type="replace"/> - <log expr='"Lion : " + Data("string(jungle/animals/lion/name)") + "," + Data("string(jungle/animals/lion/age)")' /> - <log expr='"Tiger: " + Data("string(jungle/animals/tiger/name)") + "," + Data("string(jungle/animals/tiger/age)")' /> + <log expr='"Lion : " + jungle.animals.lion.name + "," + jungle.animals.lion.age' /> + <log expr='"Tiger: " + jungle.animals.tiger.name + "," + jungle.animals.tiger.age' /> + <assign location='jungle.animals.lion.age' expr='jungle.animals.tiger.age'/> + <log expr='"Lion : " + jungle.animals.lion.name + "," + jungle.animals.lion.age' /> + <log expr='"Tiger: " + jungle.animals.tiger.name + "," + jungle.animals.tiger.age' /> </onentry> <transition target='javascript.functions.inline' /> </state> @@ -128,11 +133,11 @@ <state id='javascript.functions.print'> <onentry> <log expr='function debug(msg) - { println("** " + msg + " **"); + { print("** " + msg + " **"); return "ok" } - debug("This is the Javascript println() function")' /> + debug("This is the Javascript print() function")' /> </onentry> <transition target='javascript.eventdatamap.example' /> </state> http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-01.xml ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-01.xml b/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-01.xml index d6b4e7c..5e87087 100644 --- a/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-01.xml +++ b/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-01.xml @@ -16,8 +16,7 @@ * limitations under the License. --> <!-- A fictitious state machine used by test cases. - Meant to illustrate the usage of SCXML <datamodel> element - and the Commons SCXML Data() function --> + Meant to illustrate the usage of SCXML <datamodel> element --> <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" datamodel="jexl" @@ -25,13 +24,7 @@ <!-- Root or document datamodel --> <datamodel> - <data id="docdata"> - <root xmlns=""> - <foo> - <bar>alpha</bar> - </foo> - </root> - </data> + <data id="docdata">{ "root" : { "foo" : { "bar" : "alpha" } } }</data> </datamodel> <state id="main"> @@ -44,37 +37,19 @@ <datamodel> <!-- Degenerate usage, similar to the <var> element --> <data id="mainvar" expr="0" /> - <!-- Usage where the value is an XML data tree --> - <data id="maindata"> - <root xmlns=""> - <a> - <b> - <c>beta</c> - <d>123</d> - <e>456.789</e> - </b> - </a> - </root> - </data> + <!-- Usage where the value is an JSON model --> + <data id="maindata">{ "root" : { "a" : { "b" : { "c" : "beta", "d" : 123, "e" : 456.789 } } } }</data> </datamodel> <state id="ten"> <onentry> - <!-- Assign Usage 1: location is previously defined - <var> or degenerate <data> (as in this case) --> <assign location="mainvar" expr="10" /> </onentry> - <!-- Commons SCXML defines a Data() function to use in conjunction - with the Commons JEXL expression language. The - argument is the XPath expression to a node whose value is to be - examined --> <transition event="done.state.ten" - cond="mainvar eq 10 and Data('string($maindata/root/a/b/c)') eq 'beta'" + cond="mainvar eq 10 and maindata.root.a.b.c eq 'beta'" target="twenty" /> <onexit> - <!-- Assign Usage 2: location must point to an existing - node --> - <assign location="Location('$maindata/root/a/b/c')" expr="'gamma'" /> + <assign location="maindata.root.a.b.c" expr="'gamma'" /> </onexit> </state> @@ -83,24 +58,21 @@ <assign location="mainvar" expr="20" /> </onentry> <transition event="done.state.twenty" - cond="Data('string(maindata/root/a/b/c)') eq 'gamma' and mainvar eq 20" + cond="maindata.root.a.b.c eq 'gamma' and mainvar eq 20" target="thirty" /> <onexit> - <!-- Assign Usage 3: location points to an existing - node, and expr points to an existing node. - In this case, location adopts expr's child nodes. --> - <assign location="Location('$docdata/root/foo')" - expr="Data('$maindata/root/*')" /> + <assign location="docdata.root.foo" + expr="maindata.root" /> </onexit> </state> <state id="thirty"> - <!-- Arithmetic operations are possible with results from - the Data() function. Note that data "docdata" - did not have a node at 'root/foo/a/b/d' to begin with, - the XML tree was manipulated by the <assign> above --> + <!-- Arithmetic operations. + Note that data "docdata" + did not have data at 'root.foo.a.b.d' to begin with, + the data model was manipulated by the <assign> above --> <transition event="done.state.thirty" - cond="Data('number($docdata/root/foo/a/b/d)') + Data('number($docdata/root/foo/a/b/e)') eq 579.789" + cond="docdata.root.foo.a.b.d + docdata.root.foo.a.b.e eq 579.789" target="forty" /> </state>