Author: ate
Date: Sat Nov 15 03:07:58 2014
New Revision: 1639829

URL: http://svn.apache.org/r1639829
Log:
SCXML-213: Fixing the datamodel handling and bringing it more in line with the 
SCXML specification
This is a very large commit as so many of the needed changes turned out to be 
interdependent,
and committing these in separate logical steps simply wouldn't work without 
complete intermediate breakage of the build.
For background and more high-level details concerning these changes, see: 
https://issues.apache.org/jira/browse/SCXML-213

Important new features and changes:
- complete replacing the JAXP xpath usage with Commons JXPath
- re-implement the xpath Data() builtin function and introducing the xpath 
Location() builtin function
- simplify (strip) the corresponding Builtin class and adding the XPathBuiltin 
to handle the xpath specific features separately
- extend the Evaluator interface and corresponding language specific 
implementations to support all the SCXML spec <assign> xpath requirements using 
the XPathEvaluator
- complete the <send> action implementation proper, and the default 
SimpleDispatcher implementation with it (dropping the SimpleScheduler)
- implement the SCXML spec requirements for the _ioprocessors services lookup 
and proper handling of internal/external SCXML I/O Event Processors
- also largely improve the <invoke> implementation and execution, although 
there remains several things TODO for it to be fully SCXML spec compliant

Added:
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/InvokerManager.java
   (with props)
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java
   (with props)
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java
   (with props)
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Content.java
   (with props)
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/ContentContainer.java
   (with props)
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/NamelistHolder.java
   (with props)
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/ParamsContainer.java
   (with props)
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/PayloadProvider.java
   (with props)
Removed:
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleScheduler.java
Modified:
    commons/proper/scxml/trunk/src/   (props changed)
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Builtin.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Context.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Evaluator.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/EvaluatorFactory.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/EventDispatcher.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCInstance.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLExecutionContext.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLExecutor.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLIOProcessor.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLSystemContext.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleContext.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleDispatcher.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContext.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlContext.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/xpath/XPathFunctions.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/Invoker.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/SimpleSCXMLInvoker.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/ModelUpdater.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLWriter.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Action.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Assign.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Invoke.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Log.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Param.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/SCXML.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Send.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/TransitionalState.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/semantics/ErrorConstants.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/semantics/SCXMLSemanticsImpl.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/test/StandaloneUtils.java
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/EventDataTest.java
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/WizardsTest.java
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/custom-hello-world-04-jexl.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/SimpleContextTest.java
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/GroovyContextTest.java
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluatorTest.java
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/StaticMethodTest.java
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/groovy-closure.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/microwave-01.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/microwave-02.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/microwave-03.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/microwave-04.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/groovy/microwave-05.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/javascript/JSEvaluatorTest.java
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/javascript/example-01.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/javascript/script-01.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/JexlContextTest.java
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-01.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-02.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-03.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-04.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-05.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/eventdata-03.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/foreach.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/microwave-01.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/microwave-02.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/microwave-03.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/microwave-04.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/microwave-05.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/script-01.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/stateless-01.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/jexl/wizard-02.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/xpath/example-01.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/invoke/InvokeParamNameTest.java
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/invoke/invoker-04.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/SCXMLRequiredAttributesTest.java
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/ParallelTest.java
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/actions-initial-test.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/actions-parallel-test.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/actions-state-test.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/assign-test-01.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/assign-test-02.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/parallel-03.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/send-01.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/send-02.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/transitions-02.xml
    
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/transitions-with-cond-01.xml

Propchange: commons/proper/scxml/trunk/src/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Sat Nov 15 03:07:58 2014
@@ -0,0 +1 @@
+w3c

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Builtin.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Builtin.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Builtin.java 
(original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Builtin.java 
Sat Nov 15 03:07:58 2014
@@ -17,23 +17,12 @@
 package org.apache.commons.scxml2;
 
 import java.io.Serializable;
-import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
-import org.apache.commons.jxpath.JXPathContext;
-import org.apache.commons.jxpath.JXPathException;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.apache.commons.scxml2.model.TransitionTarget;
-import org.w3c.dom.*;
 
 /**
- * Implementations of builtin functions defined by the SCXML
- * specification.
- *
- * The current version of the specification defines one builtin
- * predicate In()
+ * Implementation of the SCXML specification required In() builtin predicate.
  */
 public class Builtin implements Serializable {
 
@@ -47,154 +36,38 @@ public class Builtin implements Serializ
      * name chosen is different since &quot;in&quot; is a reserved token
      * in some expression languages.
      *
-     * Does this state belong to the given Set of States.
      * Simple ID based comparator, assumes IDs are unique.
      *
-     * @param allStates The Set of State objects to look in
+     * @param ctx variable context
      * @param state The State ID to compare with
-     * @return Whether this State belongs to this Set
-     */
-    public static boolean isMember(final Set<? extends TransitionTarget> 
allStates,
-            final String state) {
-        for (TransitionTarget tt : allStates) {
-            if (state.equals(tt.getId())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Implements the Data() function for Commons SCXML documents, that
-     * can be used to obtain a node from one of the XML data trees.
-     * Manifests within "location" attribute of &lt;assign&gt; element,
-     * for Commons JEXL and Commons EL based documents.
-     *
-     * @param namespaces The current document namespaces map at XPath location
-     * @param data The context Node, though the method accepts an Object
-     *             so error is reported by Commons SCXML, rather
-     *             than the underlying expression language.
-     * @param path The XPath expression.
-     * @return The first node matching the path, or null if no nodes match.
+     * @return Whether this State is current active
      */
-    public static Node dataNode(final Map<String, String> namespaces, final 
Object data,
-            final String path) {
-        if (data == null || !(data instanceof Node)) {
-            Log log = LogFactory.getLog(Builtin.class);
-            log.error("Data(): Cannot evaluate an XPath expression"
-                + " in the absence of a context Node, null returned");
-            return null;
-        }
-        Node dataNode = (Node) data;
-        List result;
-        try {
-            JXPathContext context = JXPathContext.newContext(dataNode);
-            if (namespaces == null || namespaces.size() == 0) {
-                Log log = LogFactory.getLog(Builtin.class);
-                if (log.isDebugEnabled()) {
-                    log.debug("Turning off namespaced XPath evaluation since "
-                        + "no namespace information is available for path: "
-                        + path);
-                }
-            } else {
-                for (String prefix : namespaces.keySet()) {
-                    context.registerNamespace(prefix, namespaces.get(prefix));
-                }
-            }
-            result = context.selectNodes(path);
-        } catch (JXPathException xee) {
-            Log log = LogFactory.getLog(Builtin.class);
-            log.error(xee.getMessage(), xee);
-            return null;
-        }
-        int length = result.size();
-        if (length == 0) {
-            Log log = LogFactory.getLog(Builtin.class);
-            log.warn("Data(): No nodes matching the XPath expression \""
-                + path + "\", returning null");
-            return null;
-        } else {
-            if (length > 1) {
-                Log log = LogFactory.getLog(Builtin.class);
-                log.warn("Data(): Multiple (" + length + ") nodes matching 
XPath expression \""
-                    + path + "\", returning first");
-            }
-            return (Node)result.get(0);
-        }
+    @SuppressWarnings("unchecked")
+    public static boolean isMember(final Context ctx, final String state) {
+        return isMember((Set<? extends 
TransitionTarget>)ctx.getSystemContext().get(SCXMLSystemContext.ALL_STATES_KEY),
 state);
     }
 
     /**
-     * A variant of the Data() function for Commons SCXML documents,
-     * coerced to a Double, a Long or a String, whichever succeeds,
-     * in that order.
-     * Manifests within rvalue expressions in the document,
-     * for Commons JEXL and Commons EL based documents..
+     * Implements the In() predicate for SCXML documents. The method
+     * name chosen is different since &quot;in&quot; is a reserved token
+     * in some expression languages.
      *
-     * @param namespaces The current document namespaces map at XPath location
-     * @param data The context Node, though the method accepts an Object
-     *             so error is reported by Commons SCXML, rather
-     *             than the underlying expression language.
-     * @param path The XPath expression.
-     * @return The first node matching the path, coerced to a String, or null
-     *         if no nodes match.
-     */
-    public static Object data(final Map<String, String> namespaces, final 
Object data, final String path) {
-        Object retVal = null;
-        String strVal = getNodeValue(dataNode(namespaces, data, path));
-        // try as a double
-        try {
-            double d = Double.parseDouble(strVal);
-            retVal = new Double(d);
-        } catch (NumberFormatException notADouble) {
-            // else as a long
-            try {
-                long l = Long.parseLong(strVal);
-                retVal = new Long(l);
-            } catch (NumberFormatException notALong) {
-                // fallback to string
-                retVal = strVal;
-            }
-        }
-        return retVal;
-    }
-
-    /**
-     * Retrieve a DOM node value as a string depending on its type.
+     * Does this state belong to the given Set of States.
+     * Simple ID based comparator, assumes IDs are unique.
      *
-     * @param node A node to be retrieved
-     * @return The value as a string
+     * @param allStates The Set of State objects to look in
+     * @param state The State ID to compare with
+     * @return Whether this State belongs to this Set
      */
-    private static String getNodeValue(final Node node) {
-        String result = "";
-        if (node == null) {
-            return result;
-        }
-        switch(node.getNodeType()) {
-            case Node.ATTRIBUTE_NODE:
-                result = node.getNodeValue();
-                break;
-            case Node.ELEMENT_NODE:
-                if (node.hasChildNodes()) {
-                    Node child = node.getFirstChild();
-                    StringBuilder buf = new StringBuilder();
-                    while (child != null) {
-                        if (child.getNodeType() == Node.TEXT_NODE) {
-                            buf.append(((CharacterData) child).getData());
-                        }
-                        child = child.getNextSibling();
-                    }
-                    result = buf.toString();
+    public static boolean isMember(final Set<? extends TransitionTarget> 
allStates, final String state) {
+        if (allStates != null) {
+            for (TransitionTarget tt : allStates) {
+                if (state.equals(tt.getId())) {
+                    return true;
                 }
-                break;
-            case Node.TEXT_NODE:
-            case Node.CDATA_SECTION_NODE:
-                result = ((CharacterData) node).getData();
-                break;
-            default:
-                String err = "Trying to get value of a strange Node type: " + 
node.getNodeType();
-                throw new IllegalArgumentException(err);
+            }
         }
-        return result.trim();
+        return false;
     }
 }
 

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Context.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Context.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Context.java 
(original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Context.java 
Sat Nov 15 03:07:58 2014
@@ -94,4 +94,11 @@ public interface Context {
      */
     Context getParent();
 
+    /**
+     * Get the SCXMLSystemContext for this Context, should not be null unless 
this is the root Context
+     *
+     * @return The SCXMLSystemContext in a chained Context environment
+     */
+    SCXMLSystemContext getSystemContext();
+
 }

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Evaluator.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Evaluator.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Evaluator.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Evaluator.java
 Sat Nov 15 03:07:58 2014
@@ -16,8 +16,6 @@
  */
 package org.apache.commons.scxml2;
 
-import org.w3c.dom.Node;
-
 /**
  * Interface for a component that may be used by the SCXML engines to
  * evaluate the expressions within the SCXML document.
@@ -25,6 +23,52 @@ import org.w3c.dom.Node;
  */
 public interface Evaluator {
 
+    /** SCXML 1.0 Null Data Model name **/
+    String NULL_DATA_MODEL = "null";
+
+    /** SCXML 1.0 ECMAScript Data Model name **/
+    String ECMASCRIPT_DATA_MODEL = "ecmascript";
+
+    /** SCXML 1.0 XPath Data Model name **/
+    String XPATH_DATA_MODEL = "xpath";
+
+    /** Default Data Model name **/
+    String DEFAULT_DATA_MODEL = "";
+
+    /**
+     * The allowable types of <assign/> including and in particular when using 
XPath
+     */
+    enum AssignType {
+
+        REPLACE_CHILDREN("replacechildren"),
+        FIRST_CHILD("firstchild"),
+        LAST_CHILD("lastchild"),
+        PREVIOUS_SIBLING("previoussibling"),
+        NEXT_SIBLING("nextsibling"),
+        REPLACE("replace"),
+        DELETE("delete"),
+        ADD_ATTRIBUTE("addattribute");
+
+        private final String value;
+
+        private AssignType(String value) {
+            this.value = value;
+        }
+
+        public String value() {
+            return value;
+        }
+
+        public static AssignType fromValue(String value) {
+            for (AssignType type : AssignType.values()) {
+                if (type.value().equals(value)) {
+                    return type;
+                }
+            }
+            return null;
+        }
+    }
+
     /**
      * Get the datamodel type supported by this Evaluator
      * @return The supported datamodel type
@@ -32,12 +76,12 @@ public interface Evaluator {
     String getSupportedDatamodel();
 
     /**
-     * Evaluate an expression.
+     * Evaluate an expression returning a data value
      *
      * @param ctx variable context
      * @param expr expression
-     * @return a result of the evaluation
-     * @throws SCXMLExpressionException A malformed exception
+     * @return the result of the evaluation
+     * @throws SCXMLExpressionException A malformed expression exception
      */
     Object eval(Context ctx, String expr)
     throws SCXMLExpressionException;
@@ -50,24 +94,37 @@ public interface Evaluator {
      * @param ctx variable context
      * @param expr expression
      * @return true/false
-     * @throws SCXMLExpressionException A malformed exception
+     * @throws SCXMLExpressionException A malformed expression exception
      */
     Boolean evalCond(Context ctx, String expr)
     throws SCXMLExpressionException;
 
     /**
-     * Evaluate a location that returns a Node within an XML data tree.
+     * Evaluate a location that returns a data assignable reference or list of 
references.
      * Manifests as "location" attributes of &lt;assign&gt; element.
      *
      * @param ctx variable context
      * @param expr expression
-     * @return The location node.
-     * @throws SCXMLExpressionException A malformed exception
+     * @return The location result.
+     * @throws SCXMLExpressionException A malformed expression exception
      */
-    Node evalLocation(Context ctx, String expr)
+    Object evalLocation(Context ctx, String expr)
     throws SCXMLExpressionException;
 
     /**
+     * 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 
AssignType#REPLACE_CHILDREN}
+     * @param attr the name of the attribute to add when using type {@link 
AssignType#ADD_ATTRIBUTE}
+     * @throws SCXMLExpressionException A malformed expression exception
+     */
+    void evalAssign(Context ctx, String location, Object data, AssignType 
type, String attr)
+            throws SCXMLExpressionException;
+
+    /**
      * Evaluate a script.
      * Manifests as &lt;script&gt; element.
      *

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/EvaluatorFactory.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/EvaluatorFactory.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/EvaluatorFactory.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/EvaluatorFactory.java
 Sat Nov 15 03:07:58 2014
@@ -25,6 +25,7 @@ import org.apache.commons.scxml2.env.jex
 import org.apache.commons.scxml2.env.xpath.XPathEvaluator;
 import org.apache.commons.scxml2.model.ModelException;
 import org.apache.commons.scxml2.model.SCXML;
+import static org.apache.commons.scxml2.Evaluator.DEFAULT_DATA_MODEL;
 
 /**
  * A static singleton factory for {@link EvaluatorProvider}s by supported 
SCXML datamodel type.
@@ -35,7 +36,7 @@ import org.apache.commons.scxml2.model.S
  * <p>
  *  The builtin supported providers are:
  *  <ul>
- *      <li>no datamodel (default) or datamodel="jexl": {@link 
JexlEvaluator.JexlEvaluatorProvider}</li>
+ *      <li>no or empty datamodel (default) or datamodel="jexl": {@link 
JexlEvaluator.JexlEvaluatorProvider}</li>
  *      <li>datamodel="ecmascript": {@link 
JSEvaluator.JSEvaluatorProvider}</li>
  *      <li>datamodel="groovy": {@link 
GroovyEvaluator.GroovyEvaluatorProvider}</li>
  *      <li>datamodel="xpath": {@link 
XPathEvaluator.XPathEvaluatorProvider}</li>
@@ -47,8 +48,8 @@ import org.apache.commons.scxml2.model.S
  *  </p>
  *  <p>
  *  The default provider can be overridden using the {@link 
#setDefaultProvider(EvaluatorProvider)} which will
- *  register the provider under an empty ("") value for the datamodel.<br/>
- *  Note: this is <em>not</em> the same as datamodel="null" (which currently 
is not (yet) supported)!
+ *  register the provider under the {@link Evaluator#DEFAULT_DATA_MODEL} ("") 
value for the datamodel.<br/>
+ *  Note: this is <em>not</em> the same as datamodel="null"!
  * </p>
  */
 public class EvaluatorFactory {
@@ -58,45 +59,49 @@ public class EvaluatorFactory {
     private final Map<String, EvaluatorProvider> providers = new 
ConcurrentHashMap<String, EvaluatorProvider>();
 
     private EvaluatorFactory() {
-        providers.put("xpath", new XPathEvaluator.XPathEvaluatorProvider());
-        providers.put("ecmascript", new JSEvaluator.JSEvaluatorProvider());
-        providers.put("groovy", new GroovyEvaluator.GroovyEvaluatorProvider());
-        providers.put("jexl", new JexlEvaluator.JexlEvaluatorProvider());
-        providers.put("", providers.get("jexl"));
+        providers.put(XPathEvaluator.SUPPORTED_DATA_MODEL, new 
XPathEvaluator.XPathEvaluatorProvider());
+        providers.put(JSEvaluator.SUPPORTED_DATA_MODEL, new 
JSEvaluator.JSEvaluatorProvider());
+        providers.put(GroovyEvaluator.SUPPORTED_DATA_MODEL, new 
GroovyEvaluator.GroovyEvaluatorProvider());
+        providers.put(JexlEvaluator.SUPPORTED_DATA_MODEL, new 
JexlEvaluator.JexlEvaluatorProvider());
+        providers.put(DEFAULT_DATA_MODEL, 
providers.get(JexlEvaluator.SUPPORTED_DATA_MODEL));
     }
 
     public static void setDefaultProvider(EvaluatorProvider defaultProvider) {
-        INSTANCE.providers.put("", defaultProvider);
+        INSTANCE.providers.put(DEFAULT_DATA_MODEL, defaultProvider);
     }
 
+    @SuppressWarnings("unused")
     public static EvaluatorProvider getDefaultProvider() {
-        return INSTANCE.providers.get("");
+        return INSTANCE.providers.get(DEFAULT_DATA_MODEL);
     }
 
-    public static EvaluatorProvider getEvaluatorProvider(String datamodelType) 
{
-        return INSTANCE.providers.get(datamodelType == null ? "" : 
datamodelType);
+    @SuppressWarnings("unused")
+    public static EvaluatorProvider getEvaluatorProvider(String datamodelName) 
{
+        return INSTANCE.providers.get(datamodelName == null ? 
DEFAULT_DATA_MODEL : datamodelName);
     }
 
+    @SuppressWarnings("unused")
     public static void registerEvaluatorProvider(EvaluatorProvider provider) {
         INSTANCE.providers.put(provider.getSupportedDatamodel(), provider);
     }
 
-    public static void unregisterEvaluatorProvider(String datamodelType) {
-        INSTANCE.providers.remove(datamodelType == null ? "" : datamodelType);
+    @SuppressWarnings("unused")
+    public static void unregisterEvaluatorProvider(String datamodelName) {
+        INSTANCE.providers.remove(datamodelName == null ? DEFAULT_DATA_MODEL : 
datamodelName);
     }
 
     /**
-     * Returns a dedicated Evaluator instance for a specific SCXML document 
its documentmodel type.
+     * Returns a dedicated Evaluator instance for a specific SCXML document 
its documentmodel.
      * <p>If no SCXML document is provided a default Evaluator will be 
returned.</p>
      * @param document The document to return a dedicated Evaluator for. May 
be null to retrieve the default Evaluator.
      * @return a new and not sharable Evaluator instance for the provided 
document, or a default Evaluator otherwise
-     * @throws ModelException If the SCXML document datamodel type is not 
supported.
+     * @throws ModelException If the SCXML document datamodel is not supported.
      */
     public static Evaluator getEvaluator(SCXML document) throws ModelException 
{
-        String datamodelType = document != null ? document.getDatamodelType() 
: null;
-        EvaluatorProvider provider = INSTANCE.providers.get(datamodelType == 
null ? "" : datamodelType);
+        String datamodelName = document != null ? document.getDatamodelName() 
: null;
+        EvaluatorProvider provider = INSTANCE.providers.get(datamodelName == 
null ? DEFAULT_DATA_MODEL : datamodelName);
         if (provider == null) {
-            throw new ModelException("Unsupported SCXML document datamodel 
type \""+(datamodelType)+"\"");
+            throw new ModelException("Unsupported SCXML document datamodel 
\""+(datamodelName)+"\"");
         }
         return document != null ? provider.getEvaluator(document) : 
provider.getEvaluator();
     }

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/EventDispatcher.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/EventDispatcher.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/EventDispatcher.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/EventDispatcher.java
 Sat Nov 15 03:07:58 2014
@@ -16,11 +16,8 @@
  */
 package org.apache.commons.scxml2;
 
-import java.util.List;
 import java.util.Map;
 
-import org.w3c.dom.Node;
-
 /**
  * The event controller interface used to send messages containing
  * events or other information directly to another SCXML Interpreter,
@@ -40,22 +37,19 @@ public interface EventDispatcher {
     /**
      * Send this message to the target.
      *
+     * @param ioProcessors the available SCXMLIOProcessors, the same map as 
the SCXML system variable _ioprocessors
      * @param id The ID of the send message
      * @param target An expression returning the target location of the event
      * @param type The type of the Event I/O Processor that the event should
      *  be dispatched to
      * @param event The type of event being generated.
-     * @param params A list of zero or more whitespace separated variable
-     *  names to be included with the event.
+     * @param data The event payload
      * @param hints The data containing information which may be
      *  used by the implementing platform to configure the event processor
      * @param delay The event is dispatched after the delay interval elapses
-     * @param externalNodes The list of external nodes associated with
-     *  the &lt;send&gt; element.
      */
-    void send(String id, String target, String type,
-            String event, Map<String, Object> params, Object hints,
-            long delay, List<Node> externalNodes);
+    void send(Map<String, SCXMLIOProcessor> ioProcessors, String id, String 
target, String type, String event,
+              Object data, Object hints, long delay);
 
 }
 

Added: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/InvokerManager.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/InvokerManager.java?rev=1639829&view=auto
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/InvokerManager.java
 (added)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/InvokerManager.java
 Sat Nov 15 03:07:58 2014
@@ -0,0 +1,48 @@
+/*
+ * 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.invoke.Invoker;
+import org.apache.commons.scxml2.invoke.InvokerException;
+import org.apache.commons.scxml2.model.Invoke;
+
+/**
+ * InvokerManager provides the ability to an Invoke action to
+ * create and register an active Invoker instance
+ */
+public interface InvokerManager {
+
+    /**
+     * Create a new {@link Invoker}
+     *
+     * @param type The type of the target being invoked.
+     * @return An {@link Invoker} for the specified type, if an
+     *         invoker class is registered against that type,
+     *         <code>null</code> otherwise.
+     * @throws InvokerException When a suitable {@link Invoker} cannot be 
instantiated.
+     */
+    Invoker newInvoker(final String type) throws InvokerException;
+
+    /**
+     * Registers the active {@link Invoker} for an {@link Invoke}
+     *
+     * @param invoke The Invoke.
+     * @param invoker The Invoker.
+     * @throws InvokerException when the Invoker doesn't have an invokerId
+     */
+    void registerInvoker(final Invoke invoke, final Invoker invoker) throws 
InvokerException;
+}

Propchange: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/InvokerManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/InvokerManager.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCInstance.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCInstance.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCInstance.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCInstance.java
 Sat Nov 15 03:07:58 2014
@@ -25,6 +25,10 @@ import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.scxml2.env.SimpleContext;
 import org.apache.commons.scxml2.model.Data;
 import org.apache.commons.scxml2.model.Datamodel;
 import org.apache.commons.scxml2.model.EnterableState;
@@ -33,6 +37,8 @@ import org.apache.commons.scxml2.model.M
 import org.apache.commons.scxml2.model.SCXML;
 import org.apache.commons.scxml2.model.TransitionalState;
 import org.apache.commons.scxml2.semantics.ErrorConstants;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 
 /**
@@ -144,8 +150,8 @@ public class SCInstance implements Seria
         if (evaluator == null) {
             evaluator = EvaluatorFactory.getEvaluator(stateMachine);
         }
-        if (stateMachine.getDatamodelType() != null && 
!stateMachine.getDatamodelType().equals(evaluator.getSupportedDatamodel())) {
-            throw new ModelException("Incompatible SCXML document datamodel 
type \""+stateMachine.getDatamodelType()+"\""
+        if (stateMachine.getDatamodelName() != null && 
!stateMachine.getDatamodelName().equals(evaluator.getSupportedDatamodel())) {
+            throw new ModelException("Incompatible SCXML document datamodel 
\""+stateMachine.getDatamodelName()+"\""
                     + " for evaluator "+evaluator.getClass().getName()+" 
supported datamodel \""+evaluator.getSupportedDatamodel()+"\"");
         }
         if (errorReporter == null) {
@@ -170,13 +176,14 @@ public class SCInstance implements Seria
      * </p>
      */
     protected void detach() {
+        this.internalIOProcessor = null;
         this.evaluator = null;
         this.errorReporter = null;
     }
 
     /**
      * Sets the I/O Processor for the internal event queue
-     * @param internalIOProcessor
+     * @param internalIOProcessor the I/O Processor
      */
     protected void setInternalIOProcessor(SCXMLIOProcessor 
internalIOProcessor) {
         this.internalIOProcessor = internalIOProcessor;
@@ -256,7 +263,7 @@ public class SCInstance implements Seria
      */
     protected void cloneDatamodel(final Datamodel datamodel, final Context 
ctx, final Evaluator evaluator,
                                       final ErrorReporter errorReporter) {
-        if (datamodel == null) {
+        if (datamodel == null || 
Evaluator.NULL_DATA_MODEL.equals(evaluator.getSupportedDatamodel())) {
             return;
         }
         List<Data> data = datamodel.getData();
@@ -264,6 +271,10 @@ public class SCInstance implements Seria
             return;
         }
         for (Data datum : data) {
+            if (ctx.has(datum.getId())) {
+                // earlier or externally defined 'initial' value found: do not 
overwrite
+                continue;
+            }
             Node datumNode = datum.getNode();
             Node valueNode = null;
             if (datumNode != null) {
@@ -273,7 +284,7 @@ public class SCInstance implements Seria
             if (datum.getSrc() != null) {
                 ctx.setLocal(datum.getId(), valueNode);
             } else if (datum.getExpr() != null) {
-                Object value = null;
+                Object value;
                 try {
                     ctx.setLocal(Context.NAMESPACES_KEY, 
datum.getNamespaces());
                     value = evaluator.eval(ctx, datum.getExpr());
@@ -283,8 +294,33 @@ public class SCInstance implements Seria
                         internalIOProcessor.addEvent(new 
TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
                     }
                     errorReporter.onError(ErrorConstants.EXPRESSION_ERROR, 
see.getMessage(), datum);
+                    continue;
+                }
+                if 
(Evaluator.XPATH_DATA_MODEL.equals(evaluator.getSupportedDatamodel())) {
+                    try {
+                        Document document = 
DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+                        // TODO: should use SCXML namespace here?
+                        Element dataNode = document.createElement("data");
+                        dataNode.setAttribute("id", datum.getId());
+                        ctx.setLocal(datum.getId(), dataNode);
+                        evaluator.evalAssign(ctx, "$" + datum.getId(), value, 
Evaluator.AssignType.REPLACE_CHILDREN, null);
+                    }
+                    catch (ParserConfigurationException pce) {
+                        if (internalIOProcessor != null) {
+                            internalIOProcessor.addEvent(new 
TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
+                        }
+                        errorReporter.onError(ErrorConstants.EXECUTION_ERROR, 
pce.getMessage(), datum);
+                    }
+                    catch (SCXMLExpressionException see) {
+                        if (internalIOProcessor != null) {
+                            internalIOProcessor.addEvent(new 
TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
+                        }
+                        errorReporter.onError(ErrorConstants.EXPRESSION_ERROR, 
see.getMessage(), datum);
+                    }
+                }
+                else {
+                    ctx.setLocal(datum.getId(), value);
                 }
-                ctx.setLocal(datum.getId(), value);
             } else {
                 ctx.setLocal(datum.getId(), valueNode);
             }
@@ -325,7 +361,8 @@ public class SCInstance implements Seria
      */
     public Context getRootContext() {
         if (rootContext == null && evaluator != null) {
-            rootContext = evaluator.newContext(null);
+            rootContext = 
Evaluator.NULL_DATA_MODEL.equals(evaluator.getSupportedDatamodel())
+                    ? new SimpleContext() : evaluator.newContext(null);
         }
         return rootContext;
     }
@@ -354,7 +391,9 @@ public class SCInstance implements Seria
             // force initialization of rootContext
             getRootContext();
             if (rootContext != null) {
-                systemContext = new 
SCXMLSystemContext(evaluator.newContext(rootContext));
+                Context internalContext = 
Evaluator.NULL_DATA_MODEL.equals(evaluator.getSupportedDatamodel()) ?
+                        new SimpleContext(systemContext) : 
evaluator.newContext(rootContext);
+                systemContext = new SCXMLSystemContext(internalContext);
                 
systemContext.getContext().set(SCXMLSystemContext.SESSIONID_KEY, 
UUID.randomUUID().toString());
                 String _name = stateMachine != null && stateMachine.getName() 
!= null ? stateMachine.getName() : "";
                 
systemContext.getContext().set(SCXMLSystemContext.SCXML_NAME_KEY, _name);

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLExecutionContext.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLExecutionContext.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLExecutionContext.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLExecutionContext.java
 Sat Nov 15 03:07:58 2014
@@ -17,11 +17,11 @@
 package org.apache.commons.scxml2;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Map;
 import java.util.Queue;
-import java.util.UUID;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -37,7 +37,7 @@ import org.apache.commons.scxml2.model.S
  * SCXMLExecutionContext provides all the services and internal data used 
during the interpretation of an SCXML
  * statemachine across micro and macro steps
  */
-public class SCXMLExecutionContext implements SCXMLIOProcessor {
+public class SCXMLExecutionContext implements SCXMLIOProcessor, InvokerManager 
{
 
     /**
      * SCXML Execution Logger for the application.
@@ -100,6 +100,11 @@ public class SCXMLExecutionContext imple
     private final Map<String, Invoker> invokers = new HashMap<String, 
Invoker>();
 
     /**
+     * The Map of the current ioProcessors
+     */
+    private final Map<String, SCXMLIOProcessor> ioProcessors = new 
HashMap<String, SCXMLIOProcessor>();
+
+    /**
      * Constructor
      *
      * @param externalIOProcessor The external IO Processor
@@ -117,6 +122,11 @@ public class SCXMLExecutionContext imple
 
         this.scInstance = new SCInstance(this, this.evaluator, 
this.errorReporter);
         this.actionExecutionContext = new ActionExecutionContext(this);
+
+        ioProcessors.put(SCXMLIOProcessor.DEFAULT_EVENT_PROCESSOR, 
getExternalIOProcessor());
+        ioProcessors.put(SCXMLIOProcessor.SCXML_EVENT_PROCESSOR, 
getExternalIOProcessor());
+        ioProcessors.put(SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR, 
getInternalIOProcessor());
+        initializeIOProcessors();
     }
 
     public SCXMLIOProcessor getExternalIOProcessor() {
@@ -162,6 +172,7 @@ public class SCXMLExecutionContext imple
         }
         internalEventQueue.clear();
         scInstance.initialize();
+        initializeIOProcessors();
         scInstance.setRunning(true);
     }
 
@@ -192,6 +203,16 @@ public class SCXMLExecutionContext imple
         scInstance.setStateMachine(stateMachine);
         // synchronize possible derived evaluator
         this.evaluator = scInstance.getEvaluator();
+        initializeIOProcessors();
+    }
+
+    /**
+     * The SCXML specification section "C.1.1 _ioprocessors Value" states that 
the SCXMLEventProcessor <em>must</em>
+     * maintain a 'location' field inside its entry in the _ioprocessors 
environment variable.
+     * @return the 'location' of the SCXMLEventProcessor
+     */
+    public String getLocation() {
+        return null;
     }
 
     /**
@@ -221,6 +242,7 @@ public class SCXMLExecutionContext imple
         scInstance.setEvaluator(evaluator, false);
         // synchronize possible derived evaluator
         this.evaluator = scInstance.getEvaluator();
+        initializeIOProcessors();
     }
 
     /**
@@ -269,6 +291,15 @@ public class SCXMLExecutionContext imple
     }
 
     /**
+     * Initialize the _ioprocessors environment variable, which only can be 
done when the evaluator is available
+     */
+    protected void initializeIOProcessors() {
+        if (scInstance.getEvaluator() != null) {
+            
getScInstance().getSystemContext().setLocal(SCXMLSystemContext.IOPROCESSORS_KEY,
 Collections.unmodifiableMap(ioProcessors));
+        }
+    }
+
+    /**
      * Detach the current SCInstance to allow external serialization.
      * <p>
      * {@link #attachInstance(SCInstance)} can be used to re-attach a 
previously detached instance
@@ -278,6 +309,9 @@ public class SCXMLExecutionContext imple
     protected SCInstance detachInstance() {
         SCInstance instance = scInstance;
         scInstance.detach();
+        Map<String, Object> systemVars = 
scInstance.getSystemContext().getVars();
+        systemVars.remove(SCXMLSystemContext.IOPROCESSORS_KEY);
+        systemVars.remove(SCXMLSystemContext.EVENT_KEY);
         scInstance = null;
         return instance;
     }
@@ -297,8 +331,10 @@ public class SCXMLExecutionContext imple
         if (scInstance != null) {
             scInstance.detach();
             try {
+                scInstance.setInternalIOProcessor(this);
                 scInstance.setEvaluator(evaluator, true);
                 scInstance.setErrorReporter(errorReporter);
+                initializeIOProcessors();
             }
             catch (ModelException me) {
                 // should not happen
@@ -362,20 +398,19 @@ public class SCXMLExecutionContext imple
     }
 
     /**
-     * Set the {@link Invoker} for a {@link Invoke} and returns the unique 
invokerId for the Invoker
+     * Register the active {@link Invoker} for a {@link Invoke}
      *
      * @param invoke The Invoke.
      * @param invoker The Invoker.
-     * @return The invokeId
+     * @throws InvokerException when the Invoker doesn't have an invokerId
      */
-    public String setInvoker(final Invoke invoke, final Invoker invoker) {
-        String invokeId = invoke.getId();
+    public void registerInvoker(final Invoke invoke, final Invoker invoker) 
throws InvokerException {
+        String invokeId = invoker.getInvokeId();
         if (invokeId == null) {
-            invokeId = UUID.randomUUID().toString();
+            throw new InvokerException("Registering an Invoker without 
invokerId");
         }
         invokeIds.put(invoke, invokeId);
         invokers.put(invokeId, invoker);
-        return invokeId;
     }
 
     /**

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLExecutor.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLExecutor.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLExecutor.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLExecutor.java
 Sat Nov 15 03:07:58 2014
@@ -44,11 +44,6 @@ import org.apache.commons.scxml2.semanti
 public class SCXMLExecutor implements SCXMLIOProcessor {
 
     /**
-     * SCXMLExecutor put into motion without setting a model (state machine).
-     */
-    private static final String ERR_NO_STATE_MACHINE = "SCXMLExecutor: State 
machine not set";
-
-    /**
      * The Logger for the SCXMLExecutor.
      */
     private Log log = LogFactory.getLog(SCXMLExecutor.class);

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLIOProcessor.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLIOProcessor.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLIOProcessor.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLIOProcessor.java
 Sat Nov 15 03:07:58 2014
@@ -23,6 +23,21 @@ package org.apache.commons.scxml2;
 public interface SCXMLIOProcessor {
 
     /**
+     * The name of the default SCXML I/O Event Processor
+     */
+    String DEFAULT_EVENT_PROCESSOR = 
"http://www.w3.org/TR/scxml/#SCXMLEventProcessor";;
+
+    /**
+     * Default SCXML I/O Event Processor alias
+     */
+    String SCXML_EVENT_PROCESSOR = "scxml";
+
+    /**
+     * The name of the internal Event Processor
+     */
+    String INTERNAL_EVENT_PROCESSOR = "#_internal";
+
+    /**
      * Send an event into the SCXML processor queue
      * <p>
      * @param event the event to send

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLSystemContext.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLSystemContext.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLSystemContext.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLSystemContext.java
 Sat Nov 15 03:07:58 2014
@@ -141,6 +141,11 @@ public class SCXMLSystemContext implemen
         return systemContext.getParent();
     }
 
+    @Override
+    public SCXMLSystemContext getSystemContext() {
+        return this;
+    }
+
     /**
      * @return Returns the wrapped (modifiable) system context
      */

Added: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java?rev=1639829&view=auto
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java
 (added)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java
 Sat Nov 15 03:07:58 2014
@@ -0,0 +1,93 @@
+/*
+ * 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 &lt;assign&gt; 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);
+    }
+}

Propchange: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleContext.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleContext.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleContext.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleContext.java
 Sat Nov 15 03:07:58 2014
@@ -41,6 +41,8 @@ public class SimpleContext implements Co
     /** The Map of variables and their values in this Context. */
     private Map<String, Object> vars;
 
+    protected final SCXMLSystemContext systemContext;
+
     /**
      * Constructor.
      *
@@ -57,14 +59,6 @@ public class SimpleContext implements Co
     public SimpleContext(final Context parent) {
         this(parent, null);
     }
-    /**
-     * Constructor.
-     *
-     * @param initialVars A pre-populated initial variables map
-     */
-    public SimpleContext(final Map<String, Object> initialVars) {
-        this(null, initialVars);
-    }
 
     /**
      * Constructor.
@@ -74,6 +68,8 @@ public class SimpleContext implements Co
      */
     public SimpleContext(final Context parent, final Map<String, Object> 
initialVars) {
         this.parent = parent;
+        this.systemContext = parent instanceof SCXMLSystemContext ?
+                (SCXMLSystemContext) parent : parent != null ? 
parent.getSystemContext() : null;
         if (initialVars == null) {
             setVars(new HashMap<String, Object>());
         } else {
@@ -160,6 +156,15 @@ public class SimpleContext implements Co
     }
 
     /**
+     * Get the SCXMLSystemContext for this Context, should not be null unless 
this is the root Context
+     *
+     * @return The SCXMLSystemContext in a chained Context environment
+     */
+    public final SCXMLSystemContext getSystemContext() {
+        return systemContext;
+    }
+
+    /**
      * Assigns a new value to an existing variable or creates a new one.
      * The method allows to shaddow a variable of the same name up the
      * Context chain.

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleDispatcher.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleDispatcher.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleDispatcher.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleDispatcher.java
 Sat Nov 15 03:07:58 2014
@@ -17,31 +17,125 @@
 package org.apache.commons.scxml2.env;
 
 import java.io.Serializable;
-import java.util.List;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.scxml2.EventDispatcher;
-import org.w3c.dom.Node;
+import org.apache.commons.scxml2.SCXMLIOProcessor;
+import org.apache.commons.scxml2.TriggerEvent;
 
 /**
- * Trivial EventDispatcher implementation.
- * No remote eventing.
+ * <p>EventDispatcher implementation that can schedule <code>delay</code>ed
+ * &lt;send&gt; events for the &quot;scxml&quot; <code>type</code>
+ * attribute value (which is also the default). This implementation uses
+ * J2SE <code>Timer</code>s.</p>
+ *
+ * <p>No other <code>type</code>s are processed. Subclasses may support
+ * additional <code>type</code>s by overriding the
+ * <code>send(...)</code> and <code>cancel(...)</code> methods and
+ * delegating to their <code>super</code> counterparts for the
+ * &quot;scxml&quot; <code>type</code>.</p>
  *
  */
-public final class SimpleDispatcher implements EventDispatcher, Serializable {
+public class SimpleDispatcher implements EventDispatcher, Serializable {
 
      /** Serial version UID. */
     private static final long serialVersionUID = 1L;
+
+    /**
+     * TimerTask implementation.
+     */
+    class DelayedEventTask extends TimerTask {
+
+        /**
+         * The ID of the &lt;send&gt; element.
+         */
+        private String id;
+
+        /**
+         * The event name.
+         */
+        private String event;
+
+        /**
+         * The event payload, if any.
+         */
+        private Object payload;
+
+        /**
+         * The target io processor
+         */
+        private SCXMLIOProcessor target;
+
+        /**
+         * Constructor for events with payload.
+         *
+         * @param id The ID of the send element.
+         * @param event The name of the event to be triggered.
+         * @param payload The event payload, if any.
+         * @param target The target io processor
+         */
+        DelayedEventTask(final String id, final String event, final Object 
payload, SCXMLIOProcessor target) {
+            super();
+            this.id = id;
+            this.event = event;
+            this.payload = payload;
+            this.target = target;
+        }
+
+        /**
+         * What to do when timer expires.
+         */
+        @Override
+        public void run() {
+            timers.remove(id);
+            target.addEvent(new TriggerEvent(event, TriggerEvent.SIGNAL_EVENT, 
payload));
+            if (log.isDebugEnabled()) {
+                log.debug("Fired event '" + event + "' as scheduled by "
+                        + "<send> with id '" + id + "'");
+            }
+        }
+    }
+
     /** Implementation independent log category. */
      private Log log = LogFactory.getLog(EventDispatcher.class);
 
     /**
-     *  Constructor.
+     * The <code>Map</code> of active <code>Timer</code>s, keyed by
+     * &lt;send&gt; element <code>id</code>s.
+     */
+    private Map<String, Timer> timers = Collections.synchronizedMap(new 
HashMap<String, Timer>());
+
+    /**
+     * Get the log instance.
+     *
+     * @return The current log instance
+     */
+    protected Log getLog() {
+        return log;
+    }
+
+    /**
+     * Sets the log instance
+     *
+     * @param log the new log instance
+     */
+    protected void setLog(Log log) {
+        this.log = log;
+    }
+
+    /**
+     * Get the current timers.
+     *
+     * @return The currently scheduled timers
      */
-    public SimpleDispatcher() {
-        super();
+    protected Map<String, Timer> getTimers() {
+        return timers;
     }
 
     /**
@@ -51,29 +145,94 @@ public final class SimpleDispatcher impl
         if (log.isInfoEnabled()) {
             log.info("cancel( sendId: " + sendId + ")");
         }
+        if (!timers.containsKey(sendId)) {
+            return; // done, we don't track this one or its already expired
+        }
+        Timer timer = timers.get(sendId);
+        if (timer != null) {
+            timer.cancel();
+            if (log.isDebugEnabled()) {
+                log.debug("Cancelled event scheduled by <send> with id '"
+                        + sendId + "'");
+            }
+        }
+        timers.remove(sendId);
     }
 
     /**
-    @see EventDispatcher#send(String,String,String,String,Map,Object,long,List)
+    @see EventDispatcher#send(java.util.Map, String, String, String, String, 
Object, Object, long)
      */
-    public void send(final String id, final String target,
-            final String type, final String event,
-            final Map<String, Object> params, final Object hints, final long 
delay,
-            final List<Node> externalNodes) {
+    public void send(final Map<String, SCXMLIOProcessor> ioProcessors, final 
String id, final String target,
+            final String type, final String event, final Object data, final 
Object hints, final long delay) {
         if (log.isInfoEnabled()) {
-            StringBuffer buf = new StringBuffer();
+            StringBuilder buf = new StringBuilder();
             buf.append("send ( id: ").append(id);
             buf.append(", target: ").append(target);
             buf.append(", type: ").append(type);
             buf.append(", event: ").append(event);
-            buf.append(", params: ").append(String.valueOf(params));
+            buf.append(", data: ").append(String.valueOf(data));
             buf.append(", hints: ").append(String.valueOf(hints));
             buf.append(", delay: ").append(delay);
             buf.append(')');
             log.info(buf.toString());
         }
 
-    }
+        // We only handle the "scxml" type (which is the default too) and 
optionally the #_internal target
+
+        if (type == null || 
type.equalsIgnoreCase(SCXMLIOProcessor.SCXML_EVENT_PROCESSOR) ||
+                type.equals(SCXMLIOProcessor.DEFAULT_EVENT_PROCESSOR)) {
+
+            SCXMLIOProcessor ioProcessor;
+
+            boolean internal = false;
 
+            if (target == null) {
+                ioProcessor = 
ioProcessors.get(SCXMLIOProcessor.SCXML_EVENT_PROCESSOR);
+            }
+            else if (SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR.equals(target)) 
{
+                ioProcessor = 
ioProcessors.get(SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR);
+                internal = true;
+            }
+            else {
+                // We know of no other target
+                if (log.isWarnEnabled()) {
+                    log.warn("<send>: Unavailable target - " + target);
+                }
+                ioProcessors.get(SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR).
+                        addEvent(new 
TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
+                return; // done
+            }
+
+            if (event == null) {
+                if (log.isWarnEnabled()) {
+                    log.warn("<send>: Cannot send without event name");
+                }
+                ioProcessors.get(SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR).
+                        addEvent(new 
TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
+            }
+
+            else if (!internal && delay > 0L) {
+                // Need to schedule this one
+                Timer timer = new Timer(true);
+                timer.schedule(new DelayedEventTask(id, event, data, 
ioProcessor), delay);
+                timers.put(id, timer);
+                if (log.isDebugEnabled()) {
+                    log.debug("Scheduled event '" + event + "' with delay "
+                            + delay + "ms, as specified by <send> with id '"
+                            + id + "'");
+                }
+            }
+            else {
+                ioProcessor.addEvent(new TriggerEvent(event, 
TriggerEvent.SIGNAL_EVENT, data));
+            }
+        }
+        else {
+            if (log.isWarnEnabled()) {
+                log.warn("<send>: Unsupported type - " + type);
+            }
+            ioProcessors.get(SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR).
+                    addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, 
TriggerEvent.ERROR_EVENT));
+        }
+    }
 }
 

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContext.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContext.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContext.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyContext.java
 Sat Nov 15 03:07:58 2014
@@ -41,12 +41,6 @@ public class GroovyContext extends Simpl
 
     private static final Log log = LogFactory.getLog(GroovyContext.class);
 
-    /**
-     * Internal flag to indicate whether it is to evaluate a location
-     * that returns a Node within an XML data tree.
-     */
-    private boolean evaluatingLocation = false;
-
     private String scriptBaseClass;
     private GroovyEvaluator evaluator;
     private GroovyContextBinding binding;
@@ -71,8 +65,8 @@ public class GroovyContext extends Simpl
      *
      * @param initialVars The initial set of variables.
      */
-    public GroovyContext(final Map<String, Object> initialVars, 
GroovyEvaluator evaluator) {
-        super(initialVars);
+    public GroovyContext(final Context parent, final Map<String, Object> 
initialVars, GroovyEvaluator evaluator) {
+        super(parent, initialVars);
         this.evaluator = evaluator;
     }
 
@@ -94,22 +88,6 @@ public class GroovyContext extends Simpl
         this.evaluator = evaluator;
     }
 
-    /**
-     * Returns the internal flag to indicate whether it is to evaluate a 
location
-     * that returns a Node within an XML data tree.
-     */
-    public boolean isEvaluatingLocation() {
-        return evaluatingLocation;
-    }
-
-    /**
-     * Sets the internal flag to indicate whether it is to evaluate a location
-     * that returns a Node within an XML data tree.
-     */
-    public void setEvaluatingLocation(boolean evaluatingLocation) {
-        this.evaluatingLocation = evaluatingLocation;
-    }
-
     @Override
     public Map<String, Object> getVars() {
         return vars;

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java
 Sat Nov 15 03:07:58 2014
@@ -22,6 +22,7 @@ import java.io.Serializable;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.UUID;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -30,9 +31,9 @@ import org.apache.commons.scxml2.Evaluat
 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.EffectiveContextMap;
 import org.apache.commons.scxml2.model.SCXML;
-import org.w3c.dom.Node;
 
 /**
  * Evaluator implementation enabling use of Groovy expressions in SCXML 
documents.
@@ -45,13 +46,18 @@ public class GroovyEvaluator implements 
     /** Serial version UID. */
     private static final long serialVersionUID = 1L;
 
-    private static final String SUPPORTED_DATAMODEL = "groovy";
+    /**
+     * Unique context variable name used for temporary reference to assign 
data (thus must be a valid variable name)
+     */
+    private static final String ASSIGN_VARIABLE_NAME = 
"a"+UUID.randomUUID().toString().replace('-','x');
+
+    public static final String SUPPORTED_DATA_MODEL = "groovy";
 
     public static class GroovyEvaluatorProvider implements EvaluatorProvider {
 
         @Override
         public String getSupportedDatamodel() {
-            return SUPPORTED_DATAMODEL;
+            return SUPPORTED_DATA_MODEL;
         }
 
         @Override
@@ -153,7 +159,7 @@ public class GroovyEvaluator implements 
 
     @Override
     public String getSupportedDatamodel() {
-        return SUPPORTED_DATAMODEL;
+        return SUPPORTED_DATA_MODEL;
     }
 
     /**
@@ -175,13 +181,14 @@ public class GroovyEvaluator implements 
             throw new SCXMLExpressionException(ERR_CTX_TYPE);
         }
 
-        GroovyContext groovyCtx = (GroovyContext) ctx;
+        final GroovyContext groovyCtx = (GroovyContext) ctx;
         if (groovyCtx.getGroovyEvaluator() == null) {
             groovyCtx.setGroovyEvaluator(this);
         }
         try {
             return getScript(getEffectiveContext(groovyCtx), 
groovyCtx.getScriptBaseClass(), expr).run();
-        } catch (Exception e) {
+        }
+        catch (Exception e) {
             String exMessage = e.getMessage() != null ? e.getMessage() : 
e.getClass().getCanonicalName();
             throw new SCXMLExpressionException("eval('" + expr + "'): " + 
exMessage, e);
         }
@@ -200,12 +207,13 @@ public class GroovyEvaluator implements 
             throw new SCXMLExpressionException(ERR_CTX_TYPE);
         }
 
-        GroovyContext groovyCtx = (GroovyContext) ctx;
+        final GroovyContext groovyCtx = (GroovyContext) ctx;
         if (groovyCtx.getGroovyEvaluator() == null) {
             groovyCtx.setGroovyEvaluator(this);
         }
         try {
-            return (Boolean)getScript(getEffectiveContext(groovyCtx), 
groovyCtx.getScriptBaseClass(), expr).run();
+            final Object result = getScript(getEffectiveContext(groovyCtx), 
groovyCtx.getScriptBaseClass(), expr).run();
+            return result == null ? Boolean.FALSE : (Boolean)result;
         } catch (Exception e) {
             String exMessage = e.getMessage() != null ? e.getMessage() : 
e.getClass().getCanonicalName();
             throw new SCXMLExpressionException("evalCond('" + expr + "'): " + 
exMessage, e);
@@ -216,10 +224,13 @@ public class GroovyEvaluator implements 
      * @see Evaluator#evalLocation(Context, String)
      */
     @Override
-    public Node evalLocation(final Context ctx, final String expr) throws 
SCXMLExpressionException {
+    public Object evalLocation(final Context ctx, final String expr) throws 
SCXMLExpressionException {
         if (expr == null) {
             return null;
         }
+        else if (ctx.has(expr)) {
+            return expr;
+        }
 
         if (!(ctx instanceof GroovyContext)) {
             throw new SCXMLExpressionException(ERR_CTX_TYPE);
@@ -231,8 +242,7 @@ public class GroovyEvaluator implements 
         }
         try {
             final GroovyContext effective = getEffectiveContext(groovyCtx);
-            effective.setEvaluatingLocation(true);
-            return (Node)getScript(effective, groovyCtx.getScriptBaseClass(), 
expr).run();
+            return getScript(effective, groovyCtx.getScriptBaseClass(), 
expr).run();
         } catch (Exception e) {
             String exMessage = e.getMessage() != null ? e.getMessage() : 
e.getClass().getCanonicalName();
             throw new SCXMLExpressionException("evalLocation('" + expr + "'): 
" + exMessage, e);
@@ -240,6 +250,34 @@ public class GroovyEvaluator implements 
     }
 
     /**
+     * @see Evaluator#evalAssign(Context, String, Object, AssignType, String)
+     */
+    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);
+                }
+            }
+        }
+        else {
+            throw new SCXMLExpressionException("evalAssign - cannot resolve 
location: '" + location + "'");
+        }
+    }
+
+    /**
      * @see Evaluator#evalScript(Context, String)
      */
     @Override
@@ -252,22 +290,21 @@ public class GroovyEvaluator implements 
             throw new SCXMLExpressionException(ERR_CTX_TYPE);
         }
 
-        GroovyContext groovyCtx = (GroovyContext) ctx;
+        final GroovyContext groovyCtx = (GroovyContext) ctx;
         if (groovyCtx.getGroovyEvaluator() == null) {
             groovyCtx.setGroovyEvaluator(this);
         }
         try {
             final GroovyContext effective = getEffectiveContext(groovyCtx);
-            effective.setEvaluatingLocation(true);
-            boolean inGlobalContext = groovyCtx.getParent() instanceof 
SCXMLSystemContext;
-            Script script = getScript(effective, 
groovyCtx.getScriptBaseClass(), scriptSource);
-            Object result = script.run();
+            final boolean inGlobalContext = groovyCtx.getParent() instanceof 
SCXMLSystemContext;
+            final Script script = getScript(effective, 
groovyCtx.getScriptBaseClass(), scriptSource);
+            final Object result = script.run();
             if (inGlobalContext && useInitialScriptAsBaseScript) {
                 groovyCtx.setScriptBaseClass(script.getClass().getName());
             }
             return result;
         } catch (Exception e) {
-            String exMessage = e.getMessage() != null ? e.getMessage() : 
e.getClass().getCanonicalName();
+            final String exMessage = e.getMessage() != null ? e.getMessage() : 
e.getClass().getCanonicalName();
             throw new SCXMLExpressionException("evalScript('" + scriptSource + 
"'): " + exMessage, e);
         }
     }
@@ -297,7 +334,7 @@ public class GroovyEvaluator implements 
      * @return The effective GroovyContext for the path leading up to
      *         document root.
      */
-    private GroovyContext getEffectiveContext(final GroovyContext nodeCtx) {
-        return new GroovyContext(new EffectiveContextMap(nodeCtx), this);
+    protected GroovyContext getEffectiveContext(final GroovyContext nodeCtx) {
+        return new GroovyContext(nodeCtx, new EffectiveContextMap(nodeCtx), 
this);
     }
 }
\ No newline at end of file

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java?rev=1639829&r1=1639828&r2=1639829&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java
 Sat Nov 15 03:07:58 2014
@@ -19,20 +19,19 @@ package org.apache.commons.scxml2.env.gr
 import java.lang.reflect.Array;
 import java.util.Collection;
 import java.util.Map;
-import java.util.Set;
 
 import org.apache.commons.scxml2.Builtin;
-import org.apache.commons.scxml2.Context;
-import org.apache.commons.scxml2.SCXMLSystemContext;
-import org.apache.commons.scxml2.model.EnterableState;
+import org.apache.commons.scxml2.SCXMLExpressionException;
+import org.apache.commons.scxml2.XPathBuiltin;
 
 import groovy.lang.Binding;
 import groovy.lang.MissingPropertyException;
 import groovy.lang.Script;
 
 /**
- * Groovy {@link Script} base class for SCXML, providing the standard 
'builtin' functions {@link #In(String)} and {@link #Data(Object, 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' 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)}.
  */
 public abstract class GroovySCXMLScript extends Script {
 
@@ -51,46 +50,30 @@ public abstract class GroovySCXMLScript 
     }
 
     /**
-     * Gets the ALL_NAMESPACES map from context.
-     * @return the ALL_NAMESPACES map
-     */
-    @SuppressWarnings("unchecked")
-    private Map<String, String> getNamespaces() {
-        return (Map<String, String>) context.get(Context.NAMESPACES_KEY);
-    }
-
-    /**
-     * Gets the ALL_STATES set from context.
-     * @return the ALL_STATES set
+     * Implements the In() predicate for SCXML documents ( see 
Builtin#isMember )
+     * @param state The State ID to compare with
+     * @return Whether this State belongs to this Set
      */
-    @SuppressWarnings("unchecked")
-    private Set<EnterableState> getAllStates() {
-        return (Set<EnterableState>) 
context.get(SCXMLSystemContext.ALL_STATES_KEY);
+    public boolean In(final String state) {
+        return Builtin.isMember(context, state);
     }
 
     /**
-     * Implements the Data() predicate for SCXML documents ( see Builtin#data 
).
-     * @param data the context node
-     * @param path the XPath expression
-     * @return the first node matching the path
+     * Implements the Data() predicate for SCXML documents.
+     * @param expression the XPath expression
+     * @return the data matching the expression
      */
-    public Object Data(final Object data, final String path) {
-        // first call maps delegates to dataNode(), subsequent ones to data()
-        if (context.isEvaluatingLocation()) {
-            context.setEvaluatingLocation(false);
-            return Builtin.dataNode(getNamespaces(), data, path);
-        } else {
-            return Builtin.data(getNamespaces(), data, path);
-        }
+    public Object Data(final String expression) throws 
SCXMLExpressionException {
+        return XPathBuiltin.eval(context, expression);
     }
 
     /**
-     * Implements the In() predicate for SCXML documents ( see 
Builtin#isMember )
-     * @param state The State ID to compare with
-     * @return Whether this State belongs to this Set
+     * Implements the Location() predicate for SCXML documents.
+     * @param location the XPath expression
+     * @return the location list for the location expression
      */
-    public boolean In(final String state) {
-        return Builtin.isMember(getAllStates(), state);
+    public Object Location(final String location) throws 
SCXMLExpressionException {
+        return XPathBuiltin.evalLocation(context, location);
     }
 
     /**


Reply via email to