You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by at...@apache.org on 2014/04/03 09:13:44 UTC

svn commit: r1584272 [1/6] - in /commons/proper/scxml/trunk/src: main/java/org/apache/commons/scxml2/ main/java/org/apache/commons/scxml2/env/ main/java/org/apache/commons/scxml2/env/groovy/ main/java/org/apache/commons/scxml2/env/javascript/ main/java...

Author: ate
Date: Thu Apr  3 07:13:42 2014
New Revision: 1584272

URL: http://svn.apache.org/r1584272
Log:
SCXML-196: Redefine SCXMLSemantics to align with the Algorithm for SCXML Interpretation as described in the SCXML specification
SCXML-197: Better separation of concern between SCXMLExecutor and SCInstance and introducing a new SCXMLExecutionContext
See: http://issues.apache.org/jira/browse/SCXML-196 and http://issues.apache.org/jira/browse/SCXML-197
This replaces the existing SCXMLSemantics completely with a new definition and implementation conforming to the current SCXML specification: http://www.w3.org/TR/2014/CR-scxml-20140313/#AlgorithmforSCXMLInterpretation
As this also required major structural changes, which actually 'fitted well' with SCXML-197, the result is also a far better, almost complete, separation of concerns between SCXMLExecutor, SCInstance and SCXMLExecutionContext.
For more details please check the above issue links

Added:
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLIOProcessor.java   (with props)
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/semantics/Step.java
      - copied, changed from r1583086, commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Step.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/TransitionTargetTest.java   (with props)
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/semantics/
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/semantics/SCXMLSemanticsImplTest.java   (with props)
Removed:
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLHelper.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Step.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Path.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCXMLHelperTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/PathTest.java
Modified:
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/ActionExecutionContext.java
    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/NotificationRegistry.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/SCXMLListener.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLSemantics.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/Status.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/TriggerEvent.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/AbstractSCXMLListener.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/AbstractStateMachine.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/LogUtils.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/SimpleErrorReporter.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleSCXMLListener.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleScheduler.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/Tracer.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/xpath/FunctionResolver.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/invoke/AsyncTrigger.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/CustomAction.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/EnterableState.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Final.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/OnEntry.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/OnExit.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Parallel.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/SimpleTransition.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/State.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Transition.java
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/TransitionTarget.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/site/xdoc/guide/scxml-documents.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/NamespacePrefixedXPathsTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCInstanceTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCXMLExecutorTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCXMLTestHelper.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/StatusTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/TieBreakerTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/AbstractSCXMLListenerTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/AbstractStateMachineTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/LogUtilsTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/StopWatch.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/StopWatchDisplay.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/env/StopWatchTest.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/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/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/stateless-01.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/history-deep-01.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/history-shallow-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-01.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/invoke/invoker-02.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/invoke/invoker-03.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/SCXMLReaderTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/src-test-1.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/src-test-2.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/src-test-4.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/src-test-5.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/issues/issue62-02.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/issues/issue62-03.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/DatamodelTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/HistoryTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/ScxmlInitialAttributeTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/StatelessModelTest.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/model/TransitionTest.java
    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/model/stateless-parallel-01.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/prefix-01.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/tie-breaker-01.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/tie-breaker-02.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/tie-breaker-03.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/transitions-01.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-03.xml
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/transitions-04.xml

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/ActionExecutionContext.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/ActionExecutionContext.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/ActionExecutionContext.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/ActionExecutionContext.java Thu Apr  3 07:13:42 2014
@@ -42,8 +42,8 @@ public class ActionExecutionContext {
     /**
      * @return Returns the state machine
      */
-    public SCXML getStatemachine() {
-        return exctx.getStatemachine();
+    public SCXML getStateMachine() {
+        return exctx.getStateMachine();
     }
 
     /**

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=1584272&r1=1584271&r2=1584272&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 Thu Apr  3 07:13:42 2014
@@ -32,8 +32,7 @@ import javax.xml.xpath.XPathFactory;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.scxml2.model.TransitionTarget;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
+import org.w3c.dom.*;
 
 /**
  * Implementations of builtin functions defined by the SCXML
@@ -144,11 +143,9 @@ public class Builtin implements Serializ
      * @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) {
+    public static Object data(final Map<String, String> namespaces, final Object data, final String path) {
         Object retVal = null;
-        String strVal = SCXMLHelper.getNodeValue(dataNode(namespaces,
-            data, path));
+        String strVal = getNodeValue(dataNode(namespaces, data, path));
         // try as a double
         try {
             double d = Double.parseDouble(strVal);
@@ -167,6 +164,45 @@ public class Builtin implements Serializ
     }
 
     /**
+     * Retrieve a DOM node value as a string depending on its type.
+     *
+     * @param node A node to be retreived
+     * @return The value as a string
+     */
+    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();
+                }
+                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();
+    }
+
+    /**
      * XPath {@link NamespaceContext} for Commons SCXML expressions.
      *
      * <b>Code duplication:</b> Also in XPathEvaluator.java. Class is not

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=1584272&r1=1584271&r2=1584272&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 Thu Apr  3 07:13:42 2014
@@ -23,6 +23,12 @@ import java.util.Map;
  * a SCXML root or State object.
  */
 public interface Context {
+
+    /**
+     * Current namespaces are saved under this key in the context.
+     */
+    String NAMESPACES_KEY = "_ALL_NAMESPACES";
+
     /**
      * Assigns a new value to an existing variable or creates a new one.
      * The method searches the chain of parent Contexts for variable

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/NotificationRegistry.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/NotificationRegistry.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/NotificationRegistry.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/NotificationRegistry.java Thu Apr  3 07:13:42 2014
@@ -129,15 +129,16 @@ public final class NotificationRegistry 
      * @param from The source EnterableState
      * @param to The destination EnterableState
      * @param transition The Transition that was taken
+     * @param event The event name triggering the transition
      */
     public synchronized void fireOnTransition(final Observable source,
             final TransitionTarget from, final TransitionTarget to,
-            final Transition transition) {
+            final Transition transition, final String event) {
         if (source != null && source.getObservableId() != null) {
             Set<SCXMLListener> entries = regs.get(source.getObservableId());
             if (entries != null) {
                 for (SCXMLListener lst : entries) {
-                    lst.onTransition(from, to, transition);
+                    lst.onTransition(from, to, transition, event);
                 }
             }
         }

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=1584272&r1=1584271&r2=1584272&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 Thu Apr  3 07:13:42 2014
@@ -19,15 +19,20 @@ package org.apache.commons.scxml2;
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 
+import org.apache.commons.scxml2.model.Data;
 import org.apache.commons.scxml2.model.Datamodel;
 import org.apache.commons.scxml2.model.EnterableState;
 import org.apache.commons.scxml2.model.History;
+import org.apache.commons.scxml2.model.ModelException;
 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.Node;
 
 /**
  * The <code>SCInstance</code> performs book-keeping functions for
@@ -42,6 +47,26 @@ public class SCInstance implements Seria
     private static final long serialVersionUID = 2L;
 
     /**
+     * SCInstance cannot be initialized without setting a state machine.
+     */
+    private static final String ERR_NO_STATE_MACHINE = "SCInstance: State machine not set";
+
+    /**
+     * SCInstance cannot be initialized without setting an evaluator.
+     */
+    private static final String ERR_NO_EVALUATOR = "SCInstance: Evaluator not set";
+
+    /**
+     * SCInstance cannot be initialized without setting an error reporter.
+     */
+    private static final String ERR_NO_ERROR_REPORTER = "SCInstance: ErrorReporter not set";
+
+    /**
+     * Flag indicating the state machine instance has been initialized (before).
+     */
+    private boolean initialized;
+
+    /**
      * The stateMachine being executed.
      */
     private SCXML stateMachine;
@@ -52,27 +77,24 @@ public class SCInstance implements Seria
     private final Status currentStatus;
 
     /**
-     * The owning state machine executor.
+     * The Evaluator used for this state machine instance.
      */
-    private transient SCXMLExecutor executor;
+    private transient Evaluator evaluator;
 
     /**
-     * The <code>Map</code> of <code>Context</code>s per
-     * <code>EnterableState</code>.
+     * The error reporter.
      */
-    private final Map<EnterableState, Context> contexts;
+    private transient ErrorReporter errorReporter = null;
 
     /**
-     * The <code>Map</code> of last known configurations per
-     * <code>History</code>.
+     * The map of contexts per EnterableState.
      */
-    private final Map<History, Set<EnterableState>> histories;
+    private final Map<EnterableState, Context> contexts = new HashMap<EnterableState, Context>();
 
     /**
-     * <code>Map</code> for recording the run to completion status of
-     * composite states.
+     * The map of last known configurations per History.
      */
-    private final Map<EnterableState, Boolean> completions;
+    private final Map<History, Set<EnterableState>> histories = new HashMap<History, Set<EnterableState>>();
 
     /**
      * The root context.
@@ -92,14 +114,86 @@ public class SCInstance implements Seria
     /**
      * Constructor
      *
-     * @param executor The executor that this instance is attached to.
+     * @param evaluator The evaluator
+     * @param errorReporter The error reporter
      */
-    SCInstance(final SCXMLExecutor executor) {
+    protected SCInstance(final Evaluator evaluator, final ErrorReporter errorReporter) {
+        this.evaluator = evaluator;
+        this.errorReporter = errorReporter;
         this.currentStatus = new Status();
-        this.executor = executor;
-        this.contexts = new HashMap<EnterableState, Context>();
-        this.histories = new HashMap<History, Set<EnterableState>>();
-        this.completions = new HashMap<EnterableState, Boolean>();
+    }
+
+    /**
+     * (re)Initializes the state machine instance, clearing all variable contexts, histories and current status,
+     * and clones the SCXML root datamodel into the root context.
+     * @throws ModelException if the state machine hasn't been setup for this instance
+     */
+    protected void initialize() throws ModelException {
+        if (stateMachine == null) {
+            throw new ModelException(ERR_NO_STATE_MACHINE);
+        }
+        if (evaluator == null) {
+            throw new ModelException(ERR_NO_EVALUATOR);
+        }
+        if (errorReporter == null) {
+            throw new ModelException(ERR_NO_ERROR_REPORTER);
+        }
+        systemContext = null;
+        globalContext = null;
+        contexts.clear();
+        histories.clear();
+        currentStatus.clear();
+
+        // Clone root datamodel
+        Datamodel rootdm = stateMachine.getDatamodel();
+        cloneDatamodel(rootdm, getRootContext(), evaluator, errorReporter);
+        initialized = true;
+    }
+
+    /**
+     * Detach this state machine instance to allow external serialization.
+     * <p>
+     * This clears the evaluator and errorReporter members.
+     * </p>
+     */
+    protected void detach() {
+        this.evaluator = null;
+        this.errorReporter = null;
+    }
+
+    /**
+     * Set or re-attach the evaluator
+     * <p>
+     * If this state machine instance has been initialized before, it will be initialized again, destroying all existing
+     * state!
+     * </p>
+     * @param evaluator The evaluator for this state machine instance.
+     * @throws ModelException if an attempt is made to set a null value for the evaluator
+     */
+    protected void setEvaluator(Evaluator evaluator) throws ModelException {
+        if (evaluator == null) {
+            throw new ModelException(ERR_NO_EVALUATOR);
+        }
+        if (this.evaluator != null && initialized) {
+            this.evaluator = evaluator;
+            // change of evaluator after initialization: re-initialize
+            initialize();
+        }
+        else {
+            this.evaluator = evaluator;
+        }
+    }
+
+    /**
+     * Set or re-attach the error reporter
+     * @param errorReporter The error reporter for this state machine instance.
+     * @throws ModelException if an attempt is made to set a null value for the error reporter
+     */
+    protected void setErrorReporter(ErrorReporter errorReporter) throws ModelException {
+        if (errorReporter == null) {
+            throw new ModelException(ERR_NO_ERROR_REPORTER);
+        }
+        this.errorReporter = errorReporter;
     }
 
     /**
@@ -110,35 +204,75 @@ public class SCInstance implements Seria
     }
 
     /**
-     * Sets the state machine for this instance
+     * Sets the state machine for this instance.
+     * <p>
+     * If this state machine instance has been initialized before, it will be initialized again, destroying all existing
+     * state!
+     * </p>
      * @param stateMachine The state machine for this instance
+     * @throws ModelException if an attempt is made to set a null value for the state machine
      */
-    void setStateMachine(SCXML stateMachine) {
-        this.stateMachine = stateMachine;
-        currentStatus.getStates().clear();
-        contexts.clear();
-        histories.clear();
-        completions.clear();
-        if (systemContext != null) {
-            // reset _name system variable
-            String scxmlName = stateMachine.getName() != null ? stateMachine.getName() : "";
-            systemContext.getContext().set(SCXMLSystemContext.VARIABLE_NAME, scxmlName);
+    protected void setStateMachine(SCXML stateMachine) throws ModelException {
+        if (stateMachine == null) {
+            throw new ModelException(ERR_NO_STATE_MACHINE);
+        }
+        if (this.stateMachine != null && initialized) {
+            this.stateMachine = stateMachine;
+            // change of state machine after initialization: re-initialize
+            initialize();
+        }
+        else {
+            this.stateMachine = stateMachine;
         }
     }
 
     /**
-     * @return Returns the current status (active atomic states) for this instance
-     */
-    public Status getCurrentStatus() {
-        return currentStatus;
+     * Clone data model.
+     *
+     * @param ctx The context to clone to.
+     * @param datamodel The datamodel to clone.
+     * @param evaluator The expression evaluator.
+     * @param errorReporter The error reporter
+     */
+    protected void cloneDatamodel(final Datamodel datamodel, final Context ctx, final Evaluator evaluator,
+                                      final ErrorReporter errorReporter) {
+        if (datamodel == null) {
+            return;
+        }
+        List<Data> data = datamodel.getData();
+        if (data == null) {
+            return;
+        }
+        for (Data datum : data) {
+            Node datumNode = datum.getNode();
+            Node valueNode = null;
+            if (datumNode != null) {
+                valueNode = datumNode.cloneNode(true);
+            }
+            // prefer "src" over "expr" over "inline"
+            if (datum.getSrc() != null) {
+                ctx.setLocal(datum.getId(), valueNode);
+            } else if (datum.getExpr() != null) {
+                Object value = null;
+                try {
+                    ctx.setLocal(Context.NAMESPACES_KEY, datum.getNamespaces());
+                    value = evaluator.eval(ctx, datum.getExpr());
+                    ctx.setLocal(Context.NAMESPACES_KEY, null);
+                } catch (SCXMLExpressionException see) {
+                    errorReporter.onError(ErrorConstants.EXPRESSION_ERROR, see.getMessage(), datum);
+                }
+                ctx.setLocal(datum.getId(), value);
+            } else {
+                ctx.setLocal(datum.getId(), valueNode);
+            }
+        }
     }
 
     /**
-     * Re-attach the executor
-     * @param executor The executor that this instance will be re-attached to.
+     * @return Returns the current status (active atomic states) for this instance
      */
-    void setExecutor(SCXMLExecutor executor) {
-        this.executor = executor;
+    public Status getCurrentStatus() {
+        return currentStatus;
     }
 
     /**
@@ -147,24 +281,24 @@ public class SCInstance implements Seria
      * @return The root context.
      */
     public Context getRootContext() {
-        if (rootContext == null && executor.getEvaluator() != null) {
-            rootContext = executor.getEvaluator().newContext(null);
+        if (rootContext == null && evaluator != null) {
+            rootContext = evaluator.newContext(null);
         }
         return rootContext;
     }
 
     /**
-     * Set the root context.
-     * <p>
-     * Note: clears all other contexts!
-     * </p>
-     *
+     * Set or replace the root context.
      * @param context The new root context.
      */
-    void setRootContext(final Context context) {
+    protected void setRootContext(final Context context) {
         this.rootContext = context;
-        globalContext = null;
-        contexts.clear();
+        // force initialization of rootContext
+        getRootContext();
+        if (systemContext != null) {
+            // re-parent the system context
+            systemContext.setSystemContext(evaluator.newContext(rootContext));
+        }
     }
 
     /**
@@ -172,37 +306,39 @@ public class SCInstance implements Seria
      *
      * @return The unwrapped system context.
      */
-    Context getSystemContext() {
+    public Context getSystemContext() {
         if (systemContext == null) {
             // force initialization of rootContext
             getRootContext();
             if (rootContext != null) {
-                systemContext = new SCXMLSystemContext(executor.getEvaluator().newContext(rootContext));
-                systemContext.getContext().set(SCXMLSystemContext.VARIABLE_SESSIONID, UUID.randomUUID().toString());
+                systemContext = new SCXMLSystemContext(evaluator.newContext(rootContext));
+                systemContext.getContext().set(SCXMLSystemContext.SESSIONID_KEY, UUID.randomUUID().toString());
                 String _name = stateMachine != null && stateMachine.getName() != null ? stateMachine.getName() : "";
-                systemContext.getContext().set(SCXMLSystemContext.VARIABLE_NAME, _name);
+                systemContext.getContext().set(SCXMLSystemContext.SCXML_NAME_KEY, _name);
             }
         }
         return systemContext != null ? systemContext.getContext() : null;
     }
 
+    /**
+     * @return Returns the global context, which is the top context <em>within</em> the state machine.
+     */
     public Context getGlobalContext() {
         if (globalContext == null) {
             // force initialization of systemContext
             getSystemContext();
             if (systemContext != null) {
-                globalContext = executor.getEvaluator().newContext(systemContext);
+                globalContext = evaluator.newContext(systemContext);
             }
         }
         return globalContext;
     }
 
     /**
-     * Get the <code>Context</code> for this <code>EnterableState</code>.
-     * If one is not available it is created.
+     * Get the context for an EnterableState or create one if not created before.
      *
      * @param state The EnterableState.
-     * @return The Context.
+     * @return The context.
      */
     public Context getContext(final EnterableState state) {
         Context context = contexts.get(state);
@@ -210,13 +346,13 @@ public class SCInstance implements Seria
             EnterableState parent = state.getParent();
             if (parent == null) {
                 // docroot
-                context = executor.getEvaluator().newContext(getGlobalContext());
+                context = evaluator.newContext(getGlobalContext());
             } else {
-                context = executor.getEvaluator().newContext(getContext(parent));
+                context = evaluator.newContext(getContext(parent));
             }
             if (state instanceof TransitionalState) {
                 Datamodel datamodel = ((TransitionalState)state).getDatamodel();
-                SCXMLHelper.cloneDatamodel(datamodel, context, executor.getEvaluator(), null);
+                cloneDatamodel(datamodel, context, evaluator, errorReporter);
             }
             contexts.put(state, context);
         }
@@ -224,21 +360,24 @@ public class SCInstance implements Seria
     }
 
     /**
-     * Get the <code>Context</code> for this <code>EnterableState</code>.
-     * May return <code>null</code>.
+     * Get the context for an EnterableState if available.
+     *
+     * <p>Note: used for testing purposes only</p>
      *
-     * @param state The <code>EnterableState</code>.
-     * @return The Context.
+     * @param state The EnterableState
+     * @return The context or null if not created yet.
      */
     Context lookupContext(final EnterableState state) {
         return contexts.get(state);
     }
 
     /**
-     * Set the <code>Context</code> for this <code>EnterableState</code>.
+     * Set the context for an EnterableState
+     *
+     * <p>Note: used for testing purposes only</p>
      *
      * @param state The EnterableState.
-     * @param context The Context.
+     * @param context The context.
      */
     void setContext(final EnterableState state,
             final Context context) {
@@ -287,8 +426,9 @@ public class SCInstance implements Seria
     /**
      * Resets the history state.
      *
+     * <p>Note: used for testing purposes only</p>
+     *
      * @param history The history.
-     * @see org.apache.commons.scxml2.SCXMLExecutor#reset()
      */
     public void reset(final History history) {
         Set<EnterableState> lastConfiguration = histories.get(history);
@@ -296,37 +436,5 @@ public class SCInstance implements Seria
             lastConfiguration.clear();
         }
     }
-
-    /**
-     * Get the completion status for this composite
-     * {@link EnterableState}.
-     *
-     * @param state The <code>EnterableState</code>.
-     * @return The completion status.
-     *
-     * @since 0.7
-     */
-    @SuppressWarnings("boxing")
-    public boolean isDone(final EnterableState state) {
-        if (completions.containsKey(state)) {
-            return completions.get(state);
-        }
-        return false;
-    }
-
-    /**
-     * Set the completion status for this composite
-     * {@link EnterableState}.
-     *
-     * @param state The EnterableState.
-     * @param done The completion status.
-     *
-     * @since 0.7
-     */
-    @SuppressWarnings("boxing")
-    public void setDone(final EnterableState state,
-            final boolean done) {
-        completions.put(state, done);
-    }
 }
 

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=1584272&r1=1584271&r2=1584272&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 Thu Apr  3 07:13:42 2014
@@ -25,9 +25,12 @@ import java.util.UUID;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.commons.scxml2.env.SimpleDispatcher;
+import org.apache.commons.scxml2.env.SimpleErrorReporter;
 import org.apache.commons.scxml2.invoke.Invoker;
 import org.apache.commons.scxml2.invoke.InvokerException;
 import org.apache.commons.scxml2.model.Invoke;
+import org.apache.commons.scxml2.model.ModelException;
 import org.apache.commons.scxml2.model.SCXML;
 
 /**
@@ -42,14 +45,39 @@ public class SCXMLExecutionContext {
     private Log appLog = LogFactory.getLog(SCXMLExecutionContext.class);
 
     /**
-     * The executor this execution context belongs to.
+     * The action execution context instance, providing restricted access to this execution context
      */
-    private final SCXMLExecutor executor;
+    private final ActionExecutionContext actionExecutionContext;
 
     /**
-     * The action execution context instance, providing restricted access to this execution context
+     * The SCInstance.
      */
-    private final ActionExecutionContext actionExecutionContext;
+    private SCInstance scInstance;
+
+    /**
+     * The evaluator for expressions.
+     */
+    private Evaluator evaluator;
+
+    /**
+     * The external IOProcessor for Invokers to communicate back on
+     */
+    private SCXMLIOProcessor externalIOProcessor;
+
+    /**
+     * The event dispatcher to interface with external documents etc.
+     */
+    private EventDispatcher eventdispatcher;
+
+    /**
+     * The environment specific error reporter.
+     */
+    private ErrorReporter errorReporter = null;
+
+    /**
+     * The notification registry.
+     */
+    private NotificationRegistry notificationRegistry;
 
     /**
      * The internal event queue
@@ -57,6 +85,11 @@ public class SCXMLExecutionContext {
     private final Queue<TriggerEvent> internalEventQueue = new LinkedList<TriggerEvent>();
 
     /**
+     * The Invoker classes map, keyed by invoke target types (specified using "type" attribute).
+     */
+    private final Map<String, Class<? extends Invoker>> invokerClasses = new HashMap<String, Class<? extends Invoker>>();
+
+    /**
      * The map storing the unique invokeId for an Invoke with an active Invoker
      */
     private final Map<Invoke, String> invokeIds = new HashMap<Invoke, String>();
@@ -73,12 +106,26 @@ public class SCXMLExecutionContext {
 
     /**
      * Constructor
-     * @param executor the executor this execution context belongs to
-     */
-    SCXMLExecutionContext(SCXMLExecutor executor) {
-        this.executor = executor;
+     *
+     * @param externalIOProcessor The external IO Processor
+     * @param evaluator The evaluator
+     * @param eventDispatcher The event dispatcher, if null a SimpleDispatcher instance will be used
+     * @param errorReporter The error reporter, if null a SimpleErrorReporter instance will be used
+     */
+    protected SCXMLExecutionContext(SCXMLIOProcessor externalIOProcessor, Evaluator evaluator,
+                                    EventDispatcher eventDispatcher, ErrorReporter errorReporter) {
+        this.externalIOProcessor = externalIOProcessor;
+        this.evaluator = evaluator;
+        this.eventdispatcher = eventDispatcher != null ? eventDispatcher : new SimpleDispatcher();
+        this.errorReporter = errorReporter != null ? errorReporter : new SimpleErrorReporter();
+        this.notificationRegistry = new NotificationRegistry();
+
+        this.scInstance = new SCInstance(this.evaluator, this.errorReporter);
         this.actionExecutionContext = new ActionExecutionContext(this);
-        running = true;
+    }
+
+    public SCXMLIOProcessor getExternalIOProcessor() {
+        return externalIOProcessor;
     }
 
     /**
@@ -103,16 +150,20 @@ public class SCXMLExecutionContext {
     }
 
     /**
-     * Internal reset which will cancel all current active Invokers, clear the internal event queue and mark the
+     * Initialize method which will cancel all current active Invokers, clear the internal event queue and mark the
      * state machine process as running (again).
+     *
+     * @throws ModelException if the state machine instance failed to initialize.
      */
-    void reset() {
+    public void initialize() throws ModelException {
+        running = false;
         if (!invokeIds.isEmpty()) {
             for (Invoke invoke : new ArrayList<Invoke>(invokeIds.keySet())) {
                 cancelInvoker(invoke);
             }
         }
         internalEventQueue.clear();
+        scInstance.initialize();
         running = true;
     }
 
@@ -126,56 +177,153 @@ public class SCXMLExecutionContext {
     /**
      * @return Returns the state machine
      */
-    public SCXML getStatemachine() {
-        return executor.getStateMachine();
+    public SCXML getStateMachine() {
+        return scInstance.getStateMachine();
+    }
+
+    /**
+     * Set or replace the state machine to be executed
+     * <p>
+     * If the state machine instance has been initialized before, it will be initialized again, destroying all existing
+     * state!
+     * </p>
+     * @param stateMachine The state machine to set
+     * @throws ModelException if attempting to set a null value or the state machine instance failed to re-initialize
+     */
+    protected void setStateMachine(SCXML stateMachine) throws ModelException {
+        scInstance.setStateMachine(stateMachine);
     }
 
     /**
      * @return Returns the SCInstance
      */
     public SCInstance getScInstance() {
-        return executor.getSCInstance();
+        return scInstance;
     }
 
     /**
      * @return Returns The evaluator.
      */
     public Evaluator getEvaluator() {
-        return executor.getEvaluator();
+        return evaluator;
+    }
+
+    /**
+     * Set or replace the evaluator
+     * <p>
+     * If the state machine instance has been initialized before, it will be initialized again, destroying all existing
+     * state!
+     * </p>
+     * @param evaluator The evaluator to set
+     * @throws ModelException if attempting to set a null value or the state machine instance failed to re-initialize
+     */
+    protected void setEvaluator(Evaluator evaluator) throws ModelException {
+        scInstance.setEvaluator(evaluator);
+        this.evaluator = evaluator;
     }
 
     /**
      * @return Returns the error reporter
      */
     public ErrorReporter getErrorReporter() {
-        return executor.getErrorReporter();
+        return errorReporter;
+    }
+
+    /**
+     * Set or replace the error reporter
+     *
+     * @param errorReporter The error reporter to set, if null a SimpleErrorReporter instance will be used instead
+     */
+    protected void setErrorReporter(ErrorReporter errorReporter) {
+        this.errorReporter = errorReporter != null ? errorReporter : new SimpleErrorReporter();
+        try {
+            scInstance.setErrorReporter(errorReporter);
+        }
+        catch (ModelException me) {
+            // won't happen
+            return;
+        }
     }
 
     /**
      * @return Returns the event dispatcher
      */
     public EventDispatcher getEventDispatcher() {
-        return executor.getEventdispatcher();
+        return eventdispatcher;
+    }
+
+    /**
+     * Set or replace the event dispatch
+     *
+     * @param eventdispatcher The event dispatcher to set, if null a SimpleDispatcher instance will be used instead
+     */
+    protected void setEventdispatcher(EventDispatcher eventdispatcher) {
+        this.eventdispatcher = eventdispatcher != null ? eventdispatcher : new SimpleDispatcher();
     }
 
     /**
      * @return Returns the notification registry
      */
     public NotificationRegistry getNotificationRegistry() {
-        return executor.getNotificationRegistry();
+        return notificationRegistry;
     }
 
     /**
-     * Get the {@link Invoker} for this {@link Invoke}.
-     * May return <code>null</code>. A non-null {@link Invoker} will be
-     * returned if and only if the {@link Invoke} parent TransitionalState is
-     * currently active and contains the &lt;invoke&gt; child.
+     * Detach the current SCInstance to allow external serialization.
+     * <p>
+     * {@link #attachInstance(SCInstance)} can be used to re-attach a previously detached instance
+     * </p>
+     * @return the detached instance
+     */
+    protected SCInstance detachInstance() {
+        SCInstance instance = scInstance;
+        scInstance.detach();
+        scInstance = null;
+        return instance;
+    }
+
+    /**
+     * Re-attach a previously detached SCInstance.
+     * <p>
+     * Note: an already attached instance will get overwritten (and thus lost).
+     * </p>
+     * @param instance An previously detached SCInstance
+     */
+    protected void attachInstance(SCInstance instance) {
+        if (scInstance != null ) {
+            scInstance.detach();
+        }
+        scInstance = instance;
+        if (scInstance != null) {
+            scInstance.detach();
+            try {
+                scInstance.setEvaluator(evaluator);
+                scInstance.setErrorReporter(errorReporter);
+            }
+            catch (ModelException me) {
+                // should not happen
+                return;
+            }
+        }
+    }
+
+    /**
+     * Register an Invoker for this target type.
      *
-     * @param invoke The <code>Invoke</code>.
-     * @return The Invoker.
+     * @param type The target type (specified by "type" attribute of the invoke element).
+     * @param invokerClass The Invoker class.
      */
-    public Invoker getInvoker(final Invoke invoke) {
-        return invokers.get(invokeIds.get(invoke));
+    protected void registerInvokerClass(final String type, final Class<? extends Invoker> invokerClass) {
+        invokerClasses.put(type, invokerClass);
+    }
+
+    /**
+     * Remove the Invoker registered for this target type (if there is one registered).
+     *
+     * @param type The target type (specified by "type" attribute of the invoke element).
+     */
+    protected void unregisterInvokerClass(final String type) {
+        invokerClasses.remove(type);
     }
 
     /**
@@ -185,11 +333,33 @@ public class SCXMLExecutionContext {
      * @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.
+     * @throws InvokerException When a suitable {@link Invoker} cannot be instantiated.
      */
-    public Invoker newInvoker(String type) throws InvokerException {
-        return executor.newInvoker(type);
+    public Invoker newInvoker(final String type) throws InvokerException {
+        Class<? extends Invoker> invokerClass = invokerClasses.get(type);
+        if (invokerClass == null) {
+            throw new InvokerException("No Invoker registered for type \"" + type + "\"");
+        }
+        try {
+            return invokerClass.newInstance();
+        } catch (InstantiationException ie) {
+            throw new InvokerException(ie.getMessage(), ie.getCause());
+        } catch (IllegalAccessException iae) {
+            throw new InvokerException(iae.getMessage(), iae.getCause());
+        }
+    }
+
+    /**
+     * Get the {@link Invoker} for this {@link Invoke}.
+     * May return <code>null</code>. A non-null {@link Invoker} will be
+     * returned if and only if the {@link Invoke} parent TransitionalState is
+     * currently active and contains the &lt;invoke&gt; child.
+     *
+     * @param invoke The <code>Invoke</code>.
+     * @return The Invoker.
+     */
+    public Invoker getInvoker(final Invoke invoke) {
+        return invokers.get(invokeIds.get(invoke));
     }
 
     /**
@@ -201,7 +371,7 @@ public class SCXMLExecutionContext {
      */
     public String setInvoker(final Invoke invoke, final Invoker invoker) {
         String invokeId = invoke.getId();
-        if (SCXMLHelper.isStringEmpty(invokeId)) {
+        if (invokeId == null) {
             invokeId = UUID.randomUUID().toString();
         }
         invokeIds.put(invoke, invokeId);
@@ -236,8 +406,7 @@ public class SCXMLExecutionContext {
             try {
                 invokers.get(invokeId).cancel();
             } catch (InvokerException ie) {
-                TriggerEvent te = new TriggerEvent(invokeId
-                        + ".invoke.cancel.failed", TriggerEvent.ERROR_EVENT);
+                TriggerEvent te = new TriggerEvent("failed.invoke.cancel."+invokeId, TriggerEvent.ERROR_EVENT);
                 addInternalEvent(te);
             }
             removeInvoker(invoke);
@@ -245,7 +414,7 @@ public class SCXMLExecutionContext {
     }
 
     /**
-     * Add an event to the internal queue
+     * Add an event to the internal event queue
      * @param event The event
      */
     public void addInternalEvent(TriggerEvent event) {
@@ -253,9 +422,16 @@ public class SCXMLExecutionContext {
     }
 
     /**
-     * @return Returns the next event from the internal queue, if available
+     * @return Returns the next event from the internal event queue, if available
      */
-    TriggerEvent nextInternalEvent() {
+    public TriggerEvent nextInternalEvent() {
         return internalEventQueue.poll();
     }
+
+    /**
+     * @return Returns true if the internal event queue isn't empty
+     */
+    public boolean hasPendingInternalEvent() {
+        return !internalEventQueue.isEmpty();
+    }
 }

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=1584272&r1=1584271&r2=1584272&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 Thu Apr  3 07:13:42 2014
@@ -16,25 +16,17 @@
  */
 package org.apache.commons.scxml2;
 
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Queue;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.scxml2.invoke.Invoker;
-import org.apache.commons.scxml2.invoke.InvokerException;
-import org.apache.commons.scxml2.model.Datamodel;
 import org.apache.commons.scxml2.model.EnterableState;
-import org.apache.commons.scxml2.model.History;
 import org.apache.commons.scxml2.model.ModelException;
 import org.apache.commons.scxml2.model.Observable;
 import org.apache.commons.scxml2.model.SCXML;
-import org.apache.commons.scxml2.model.TransitionTarget;
-import org.apache.commons.scxml2.model.TransitionalState;
 import org.apache.commons.scxml2.semantics.SCXMLSemanticsImpl;
-import org.apache.commons.scxml2.system.EventVariable;
 
 /**
  * <p>The SCXML &quot;engine&quot; that executes SCXML documents. The
@@ -44,10 +36,12 @@ import org.apache.commons.scxml2.system.
  * <p>The default implementation is
  * <code>org.apache.commons.scxml2.semantics.SCXMLSemanticsImpl</code></p>
  *
+ * <p>The executor uses SCXMLExecutionContext to manage the state and
+ * provide all the services to the SCXMLSemantics implementation.</p>
+ *
  * @see SCXMLSemantics
  */
-@SuppressWarnings("unused") // TODO: remove again after refactoring is done
-public class SCXMLExecutor {
+public class SCXMLExecutor implements SCXMLIOProcessor {
 
     /**
      * SCXMLExecutor put into motion without setting a model (state machine).
@@ -60,144 +54,19 @@ public class SCXMLExecutor {
     private Log log = LogFactory.getLog(SCXMLExecutor.class);
 
     /**
-     * The evaluator for expressions.
-     */
-    private Evaluator evaluator;
-
-    /**
-     * The event dispatcher to interface with external documents etc.
-     */
-    private EventDispatcher eventdispatcher;
-
-    /**
-     * The environment specific error reporter.
-     */
-    private ErrorReporter errorReporter = null;
-
-    /**
-     * The notification registry.
-     */
-    private NotificationRegistry notificationRegistry;
-
-    /**
-     * Run-to-completion.
-     */
-    private boolean superStep = true;
-
-    /**
      *  Interpretation semantics.
      */
     private SCXMLSemantics semantics;
 
     /**
-     * The SCInstance.
-     */
-    private SCInstance scInstance;
-
-    /**
-     * The external event queue
-     */
-    private final Queue<TriggerEvent> externalEventQueue = new ConcurrentLinkedQueue<TriggerEvent>();
-
-    /**
-     * The <code>Invoker</code> classes <code>Map</code>, keyed by
-     * &lt;invoke&gt; target types (specified using "type" attribute).
-     */
-    private final Map<String, Class<? extends Invoker>> invokerClasses;
-
-    /**
      * The state machine execution context
      */
     private SCXMLExecutionContext exctx;
 
     /**
-     * Get the state chart instance for this executor.
-     *
-     * @return The SCInstance for this executor.
-     */
-    SCInstance getSCInstance() {
-        return scInstance;
-    }
-
-    /**
-     * Detach the current SCInstance to allow external serialization.
-     * <p>
-     * {@link #attachInstance(SCInstance)} can be used to re-attach a previously detached instance
-     * </p>
-     * <p>
-     * Note: until an instance is re-attached, no operations are allowed (and probably throw exceptions) except
-     * for {@link #addEvent(TriggerEvent)} which might still be used (concurrently) by running Invokers, or
-     * {@link #hasPendingEvents()} to check for possible pending events.
-     * </p>
-     * @return the detached instance
-     */
-    public SCInstance detachInstance() {
-        SCInstance instance = scInstance;
-        scInstance.setExecutor(null);
-        scInstance = null;
-        return instance;
-    }
-
-    /**
-     * Re-attach a previously detached SCInstance.
-     * <p>
-     * Note: an already attached instance will get overwritten (and thus lost).
-     * </p>
-     * @param instance An previously detached SCInstance
-     */
-    public void attachInstance(SCInstance instance) {
-        if (scInstance != null ) {
-            scInstance.setExecutor(null);
-        }
-        scInstance = instance;
-        if (scInstance != null) {
-            scInstance.setExecutor(this);
-        }
-    }
-
-    /**
-     * Log the current set of active states.
-     */
-    private void logState() {
-        if (log.isDebugEnabled()) {
-            StringBuilder sb = new StringBuilder("Current States: [ ");
-            for (EnterableState es : getCurrentStatus().getStates()) {
-                sb.append(es.getId()).append(", ");
-            }
-            int length = sb.length();
-            sb.delete(length - 2, length).append(" ]");
-            log.debug(sb.toString());
-        }
-    }
-
-    /**
-     * @param step The most recent Step
-     */
-    private void updateStatus(final Step step) {
-        getCurrentStatus().getStates().clear();
-        getCurrentStatus().getStates().addAll(step.getAfterStatus().getStates());
-        scInstance.getSystemContext().setLocal(SCXMLSystemContext.VARIABLE_ALL_STATES, getCurrentStatus().getAllStates());
-    }
-
-    /**
-     * @param evt The event being triggered.
+     * The external event queue
      */
-    private void setSystemEventVariable(final TriggerEvent evt, boolean internalQueue) {
-        Context systemContext = scInstance.getSystemContext();
-        EventVariable eventVar = null;
-        if (evt != null) {
-            String eventType = internalQueue ? EventVariable.TYPE_INTERNAL : EventVariable.TYPE_EXTERNAL;
-
-            final int triggerEventType = evt.getType();
-            if (triggerEventType == TriggerEvent.ERROR_EVENT || triggerEventType == TriggerEvent.CHANGE_EVENT) {
-                eventType = EventVariable.TYPE_PLATFORM;
-            }
-
-            // TODO: determine sendid, origin, originType and invokeid based on context later.
-            eventVar = new EventVariable(evt.getName(), eventType, null, null, null, null, evt.getPayload());
-        }
-        systemContext.setLocal(SCXMLSystemContext.VARIABLE_EVENT, eventVar);
-    }
+    private final Queue<TriggerEvent> externalEventQueue = new ConcurrentLinkedQueue<TriggerEvent>();
 
     /**
      * Convenience constructor.
@@ -229,38 +98,33 @@ public class SCXMLExecutor {
     public SCXMLExecutor(final Evaluator expEvaluator,
                          final EventDispatcher evtDisp, final ErrorReporter errRep,
                          final SCXMLSemantics semantics) {
-        this.evaluator = expEvaluator;
-        this.eventdispatcher = evtDisp;
-        this.errorReporter = errRep;
-        if (semantics == null) {
-            // Use default semantics, if none provided
-            this.semantics = new SCXMLSemanticsImpl();
-        } else {
-            this.semantics = semantics;
-        }
-        this.scInstance = new SCInstance(this);
-        this.notificationRegistry = new NotificationRegistry();
-        this.invokerClasses = new HashMap<String, Class<? extends Invoker>>();
-        this.exctx = new SCXMLExecutionContext(this);
+        this.semantics = semantics != null ? semantics : new SCXMLSemanticsImpl();
+        this.exctx = new SCXMLExecutionContext(this, expEvaluator, evtDisp, errRep);
     }
 
     /**
-     * Get the current status.
+     * Get the current state machine instance status.
      *
      * @return The current Status
      */
     public synchronized Status getCurrentStatus() {
-        return scInstance.getCurrentStatus();
+        return exctx.getScInstance().getCurrentStatus();
     }
 
     /**
-     * Set the expression evaluator.
-     * <b>NOTE:</b> Should only be used before the executor is set in motion.
-     *
-     * @param evaluator The evaluator to set.
+     * Set or replace the expression evaluator
+     * <p>
+     * If the state machine instance has been initialized before, it will be initialized again, destroying all existing
+     * state!
+     * </p>
+     * <p>
+     * Also the external event queue will be cleared.
+     * </p>
+     * @param evaluator The evaluator to set
+     * @throws ModelException if attempting to set a null value or the state machine instance failed to re-initialize
      */
-    public void setEvaluator(final Evaluator evaluator) {
-        this.evaluator = evaluator;
+    public void setEvaluator(final Evaluator evaluator) throws ModelException {
+        exctx.setEvaluator(evaluator);
     }
 
     /**
@@ -269,53 +133,58 @@ public class SCXMLExecutor {
      * @return Evaluator The evaluator in use.
      */
     public Evaluator getEvaluator() {
-        return evaluator;
+        return exctx.getEvaluator();
     }
 
     /**
-     * Set the root context for this execution.
-     * <b>NOTE:</b> Should only be used before the executor is set in motion.
+     * Get the root context for the state machine execution.
      *
-     * @param rootContext The Context that ties to the host environment.
+     * @return Context The root context.
      */
-    public void setRootContext(final Context rootContext) {
-        this.scInstance.setRootContext(rootContext);
+    public Context getRootContext() {
+        return exctx.getScInstance().getRootContext();
     }
 
     /**
-     * Get the root context for this execution.
+     * Set the root context for the state machine execution.
+     * <b>NOTE:</b> Should only be used before the executor is set in motion.
      *
-     * @return Context The root context.
+     * @param rootContext The Context that ties to the host environment.
      */
-    public Context getRootContext() {
-        return scInstance.getRootContext();
+    public void setRootContext(final Context rootContext) {
+        exctx.getScInstance().setRootContext(rootContext);
     }
 
     /**
      * Get the state machine that is being executed.
      * <b>NOTE:</b> This is the state machine definition or model used by this
      * executor instance. It may be shared across multiple executor instances
-     * and as a best practice, should not be altered. Also note that
+     * and should not be altered once in use. Also note that
      * manipulation of instance data for the executor should happen through
      * its root context or state contexts only, never through the direct
-     * manipulation of any {@link Datamodel}s associated with this state
+     * manipulation of any {@link org.apache.commons.scxml2.model.Datamodel}s associated with this state
      * machine definition.
      *
      * @return Returns the stateMachine.
      */
     public SCXML getStateMachine() {
-        return scInstance.getStateMachine();
+        return exctx.getStateMachine();
     }
 
     /**
-     * Set the state machine to be executed.
-     * <b>NOTE:</b> Should only be used before the executor is set in motion.
-     *
-     * @param stateMachine The stateMachine to set.
+     * Set or replace the state machine to be executed
+     * <p>
+     * If the state machine instance has been initialized before, it will be initialized again, destroying all existing
+     * state!
+     * </p>
+     * <p>
+     * Also the external event queue will be cleared.
+     * </p>
+     * @param stateMachine The state machine to set
+     * @throws ModelException if attempting to set a null value or the state machine instance failed to re-initialize
      */
-    public void setStateMachine(final SCXML stateMachine) {
-        exctx.reset();
-        scInstance.setStateMachine(semantics.normalizeStateMachine(stateMachine, errorReporter));
+    public void setStateMachine(final SCXML stateMachine) throws ModelException {
+        exctx.setStateMachine(semantics.normalizeStateMachine(stateMachine, exctx.getErrorReporter()));
         externalEventQueue.clear();
     }
 
@@ -325,16 +194,16 @@ public class SCXMLExecutor {
      * @return Returns the errorReporter.
      */
     public ErrorReporter getErrorReporter() {
-        return errorReporter;
+        return exctx.getErrorReporter();
     }
 
     /**
-     * Set the environment specific error reporter.
+     * Set or replace the error reporter
      *
-     * @param errorReporter The errorReporter to set.
+     * @param errorReporter The error reporter to set, if null a SimpleErrorReporter instance will be used instead
      */
     public void setErrorReporter(final ErrorReporter errorReporter) {
-        this.errorReporter = errorReporter;
+        exctx.setErrorReporter(errorReporter);
     }
 
     /**
@@ -343,16 +212,16 @@ public class SCXMLExecutor {
      * @return Returns the eventdispatcher.
      */
     public EventDispatcher getEventdispatcher() {
-        return eventdispatcher;
+        return exctx.getEventDispatcher();
     }
 
     /**
-     * Set the event dispatcher.
+     * Set or replace the event dispatch
      *
-     * @param eventdispatcher The eventdispatcher to set.
+     * @param eventdispatcher The event dispatcher to set, if null a SimpleDispatcher instance will be used instead
      */
     public void setEventdispatcher(final EventDispatcher eventdispatcher) {
-        this.eventdispatcher = eventdispatcher;
+        exctx.setEventdispatcher(eventdispatcher);
     }
 
     /**
@@ -361,43 +230,81 @@ public class SCXMLExecutor {
      * @return The notification registry.
      */
     public NotificationRegistry getNotificationRegistry() {
-        return notificationRegistry;
+        return exctx.getNotificationRegistry();
+    }
+
+    /**
+     * Add a listener to the {@link Observable}.
+     *
+     * @param observable The {@link Observable} to attach the listener to.
+     * @param listener The SCXMLListener.
+     */
+    public void addListener(final Observable observable, final SCXMLListener listener) {
+        exctx.getNotificationRegistry().addListener(observable, listener);
     }
 
     /**
-     * Set the notification registry.
+     * Remove this listener from the {@link Observable}.
      *
-     * @param notifRegistry The notification registry.
+     * @param observable The {@link Observable}.
+     * @param listener The SCXMLListener to be removed.
      */
-    @SuppressWarnings("unused")
-    void setNotificationRegistry(final NotificationRegistry notifRegistry) {
-        this.notificationRegistry = notifRegistry;
+    public void removeListener(final Observable observable,
+                               final SCXMLListener listener) {
+        exctx.getNotificationRegistry().removeListener(observable, listener);
     }
 
     /**
-     * Use &quot;super-step&quot;, default is <code>true</code>
-     * (that is, run-to-completion is default).
+     * Register an Invoker for this target type.
      *
-     * @return Returns the superStep property.
-     * @see #setSuperStep(boolean)
+     * @param type The target type (specified by "type" attribute of the invoke element).
+     * @param invokerClass The Invoker class.
      */
-    public boolean isSuperStep() {
-        return superStep;
+    public void registerInvokerClass(final String type, final Class<? extends Invoker> invokerClass) {
+        exctx.registerInvokerClass(type, invokerClass);
     }
 
     /**
-     * Set the super step.
+     * Remove the Invoker registered for this target type (if there is one registered).
      *
-     * @param superStep
-     * if true, the internal derived events are also processed
-     *    (run-to-completion);
-     * if false, the internal derived events are stored in the
-     * CurrentStatus property and processed within the next
-     * triggerEvents() invocation, also the immediate (empty event) transitions
-     * are deferred until the next step
+     * @param type The target type (specified by "type" attribute of the invoke element).
      */
-    public void setSuperStep(final boolean superStep) {
-        this.superStep = superStep;
+    public void unregisterInvokerClass(final String type) {
+        exctx.unregisterInvokerClass(type);
+    }
+
+    /**
+     * Detach the current SCInstance to allow external serialization.
+     * <p>
+     * {@link #attachInstance(SCInstance)} can be used to re-attach a previously detached instance
+     * </p>
+     * <p>
+     * Note: until an instance is re-attached, no operations are allowed (and probably throw exceptions) except
+     * for {@link #addEvent(TriggerEvent)} which might still be used (concurrently) by running Invokers, or
+     * {@link #hasPendingEvents()} to check for possible pending events.
+     * </p>
+     * @return the detached instance
+     */
+    public SCInstance detachInstance() {
+        return exctx.detachInstance();
+    }
+
+    /**
+     * Re-attach a previously detached SCInstance.
+     * <p>
+     * Note: an already attached instance will get overwritten (and thus lost).
+     * </p>
+     * @param instance An previously detached SCInstance
+     */
+    public void attachInstance(SCInstance instance) {
+        exctx.attachInstance(instance);
+    }
+
+    /**
+     * @return Returns true if the state machine is running
+     */
+    public boolean isRunning() {
+        return exctx.isRunning();
     }
 
     /**
@@ -412,67 +319,52 @@ public class SCXMLExecutor {
     }
 
     /**
-     * Clear all state and begin from &quot;initialstate&quot; indicated
-     * on root SCXML element.
+     * Clear all state and begin executing the state machine
      *
-     * @throws ModelException in case there is a fatal SCXML object
-     *         model problem.
+     * @throws ModelException if the state machine instance failed to initialize
      */
-    public synchronized void reset() throws ModelException {
-        if (getStateMachine() == null) {
-            log.error(ERR_NO_STATE_MACHINE);
-            throw new ModelException(ERR_NO_STATE_MACHINE);
-        }
-        // Reset all variable contexts
-        exctx.reset();
-        Context rootContext = scInstance.getRootContext();
-        // Clone root datamodel
-        SCXML stateMachine = getStateMachine();
-        Datamodel rootdm = stateMachine.getDatamodel();
-        SCXMLHelper.cloneDatamodel(rootdm, rootContext, getEvaluator(), log);
-        if (scInstance.getGlobalContext() != null) {
-            scInstance.getGlobalContext().reset();
-        }
-        // all states and parallels, only states have variable contexts
-        for (TransitionTarget tt : stateMachine.getTargets().values()) {
-            if (tt instanceof EnterableState) {
-                Context context = scInstance.lookupContext((EnterableState)tt);
-                if (context != null) {
-                    context.reset();
-                    if (tt instanceof TransitionalState) {
-                        Datamodel dm = ((TransitionalState)tt).getDatamodel();
-                        SCXMLHelper.cloneDatamodel(dm, context, getEvaluator(), log);
-                    }
-                }
-            } else if (tt instanceof History) {
-                scInstance.reset((History) tt);
-            }
+    public void reset() throws ModelException {
+        // clear any pending external events
+        externalEventQueue.clear();
+
+        // go
+        semantics.firstStep(exctx);
+
+        if (!exctx.isRunning()) {
+            semantics.finalStep(exctx);
         }
-        // Clear currentStatus
-        getCurrentStatus().getStates().clear();
-        Step step = new Step(null, getCurrentStatus());
-        // execute global script if defined
-        semantics.executeGlobalScript(exctx, step);
-        // DetermineInitialStates
-        semantics.determineInitialStates(exctx, step);
-        // enter initial states
-        semantics.enterStates(exctx, step);
-        // AssignCurrentStatus
-        updateStatus(step);
-        // Execute Immediate Transitions
-
-        TriggerEvent event = exctx.nextInternalEvent();
-
-        if (event != null) {
-            handleEvent(event);
-        } else {
-            // InitiateInvokes only after state machine has stabilized
-            semantics.initiateInvokes(this, exctx, step);
-            logState();
+
+        logState();
+    }
+
+    /**
+     * Add a new external event, which may be done concurrently, and even when the current SCInstance is detached.
+     * <p>
+     * No processing of the vent will be done, until the next triggerEvent methods is invoked.
+     * </p>
+     * @param evt an external event
+     */
+    public void addEvent(final TriggerEvent evt) {
+        if (evt != null) {
+            externalEventQueue.add(evt);
         }
     }
 
     /**
+     * @return Returns true if there are pending external events to be processed.
+     */
+    public boolean hasPendingEvents() {
+        return !externalEventQueue.isEmpty();
+    }
+
+    /**
+     * @return Returns the current number of pending external events to be processed.
+     */
+    public int getPendingEvents() {
+        return externalEventQueue.size();
+    }
+
+    /**
      * Convenience method when only one event needs to be triggered.
      *
      * @param evt
@@ -512,148 +404,47 @@ public class SCXMLExecutor {
     }
 
     /**
-     * Add a new external event, which may be done concurrently, and even when the current SCInstance is detached.
-     * <p>
-     * No processing of the vent will be done, until the next triggerEvent methods is invoked.
-     * </p>
-     * @param evt an external event
-     */
-    public void addEvent(final TriggerEvent evt) {
-        if (evt != null) {
-            externalEventQueue.add(evt);
-        }
-    }
-
-    /**
-     * @return Returns true if there are pending external events to be processed.
-     */
-    public boolean hasPendingEvents() {
-        return !externalEventQueue.isEmpty();
-    }
-
-    /**
      * Trigger all pending and incoming events, until there are no more pending events
      * @throws ModelException in case there is a fatal SCXML object model problem.
      */
     public void triggerEvents() throws ModelException {
         TriggerEvent evt;
-        while ((evt = externalEventQueue.poll()) != null) {
-            // Forward events (external only) to any existing invokes,
-            // and finalize processing
-            semantics.processInvokes(exctx, evt);
-            handleEvent(evt);
+        while (exctx.isRunning() && (evt = externalEventQueue.poll()) != null) {
+            eventStep(evt);
         }
     }
 
-    /**
-     * The internal worker method for handling the next external event
-     * @param evt an external event
-     * @throws ModelException in case there is a fatal SCXML object model problem.
-     */
-    protected void handleEvent(final TriggerEvent evt)
-            throws ModelException {
-        TriggerEvent event = evt;
-
-        Step step;
-
-        boolean internalQueue = false;
-
-        do {
-            setSystemEventVariable(event, internalQueue);
-
-            // CreateStep
-            step = new Step(event, getCurrentStatus());
-            // EnumerateReachableTransitions
-            semantics.enumerateReachableTransitions(exctx, step);
-            // FilterTransitionSet
-            semantics.filterTransitionsSet(exctx, step);
-            // FollowTransitions
-            semantics.followTransitions(exctx, step);
-            // UpdateHistoryStates
-            semantics.updateHistoryStates(exctx, step);
-            // ExecuteActions
-            semantics.executeActions(exctx, step);
-            // AssignCurrentStatus
-            updateStatus(step);
-
-            internalQueue = true;
-            event = exctx.nextInternalEvent();
+    protected void eventStep(TriggerEvent event) throws ModelException {
+        semantics.nextStep(exctx, event);
 
-        } while (event != null);
-
-        // InitiateInvokes only after state machine has stabilized
-        semantics.initiateInvokes(this, exctx, step);
+        if (!exctx.isRunning()) {
+            semantics.finalStep(exctx);
+        }
 
         logState();
     }
 
     /**
-     * Add a listener to the {@link Observable}.
-     *
-     * @param observable The {@link Observable} to attach the listener to.
-     * @param listener The SCXMLListener.
-     */
-    public void addListener(final Observable observable, final SCXMLListener listener) {
-        notificationRegistry.addListener(observable, listener);
-    }
-
-    /**
-     * Remove this listener from the {@link Observable}.
-     *
-     * @param observable The {@link Observable}.
-     * @param listener The SCXMLListener to be removed.
-     */
-    public void removeListener(final Observable observable,
-            final SCXMLListener listener) {
-        notificationRegistry.removeListener(observable, listener);
-    }
-
-    /**
-     * Register an <code>Invoker</code> for this target type.
-     *
-     * @param type The target type (specified by "type"
-     *             attribute of &lt;invoke&gt; tag).
-     * @param invokerClass The <code>Invoker</code> <code>Class</code>.
-     */
-    public void registerInvokerClass(final String type,
-            final Class<? extends Invoker> invokerClass) {
-        invokerClasses.put(type, invokerClass);
-    }
-
-    /**
-     * Remove the <code>Invoker</code> registered for this target
-     * type (if there is one registered).
+     * Get the state chart instance for this executor.
      *
-     * @param type The target type (specified by "type"
-     *             attribute of &lt;invoke&gt; tag).
+     * @return The SCInstance for this executor.
      */
-    public void unregisterInvokerClass(final String type) {
-        invokerClasses.remove(type);
+    protected SCInstance getSCInstance() {
+        return exctx.getScInstance();
     }
 
     /**
-     * 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 org.apache.commons.scxml2.invoke.InvokerException When a suitable {@link Invoker} cannot
-     *                          be instantiated.
+     * Log the current set of active states.
      */
-    Invoker newInvoker(final String type)
-            throws InvokerException {
-        Class<? extends Invoker> invokerClass = invokerClasses.get(type);
-        if (invokerClass == null) {
-            throw new InvokerException("No Invoker registered for type \""
-                    + type + "\"");
-        }
-        try {
-            return invokerClass.newInstance();
-        } catch (InstantiationException ie) {
-            throw new InvokerException(ie.getMessage(), ie.getCause());
-        } catch (IllegalAccessException iae) {
-            throw new InvokerException(iae.getMessage(), iae.getCause());
+    protected void logState() {
+        if (log.isDebugEnabled()) {
+            StringBuilder sb = new StringBuilder("Current States: [ ");
+            for (EnterableState es : getCurrentStatus().getStates()) {
+                sb.append(es.getId()).append(", ");
+            }
+            int length = sb.length();
+            sb.delete(length - 2, length).append(" ]");
+            log.debug(sb.toString());
         }
     }
 }

Added: 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=1584272&view=auto
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLIOProcessor.java (added)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLIOProcessor.java Thu Apr  3 07:13:42 2014
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+/**
+ * The SCXML I/O Processor provides the interface for an external system or invoked child SCXML process
+ * ({@link org.apache.commons.scxml2.invoke.Invoker}) to asynchronously send events to the SCXMLExecutor.
+ */
+public interface SCXMLIOProcessor {
+
+    /**
+     * Send an asynchronous event to the SCXMLExecutor
+     * <p>
+     * @param event the event to send
+     */
+    void addEvent(TriggerEvent event);
+}

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

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

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLListener.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLListener.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLListener.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLListener.java Thu Apr  3 07:13:42 2014
@@ -52,9 +52,10 @@ public interface SCXMLListener {
      * @param from The source TransitionTarget
      * @param to The destination TransitionTarget
      * @param transition The Transition taken
+     * @param event The event name triggering the transition
      */
     void onTransition(TransitionTarget from, TransitionTarget to,
-            Transition transition);
+            Transition transition, String event);
 
 }