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 [2/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...

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLSemantics.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLSemantics.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLSemantics.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCXMLSemantics.java Thu Apr  3 07:13:42 2014
@@ -24,10 +24,44 @@ import org.apache.commons.scxml2.model.S
  * <a href="http://www.w3.org/TR/2014/CR-scxml-20140313/#AlgorithmforSCXMLInterpretation">
  *     W3C SCXML Algorithm for SCXML Interpretation</a>
  * from the <code>SCXMLExecutor</code> and therefore make it pluggable.</p>
- *
- * <p>Semantics agnostic utility functions and common operators as defined in
- * UML can be found in the <code>SCXMLHelper</code> or attached directly to
- * the SCXML model elements.</p>
+ * <p>
+ * From an SCXML execution POV, there are only three entry points needed into the Algorithm, namely:
+ * <ul>
+ *     <li>Performing the initialization of the state machine and completing a first macro step,
+ *     see: {@link #firstStep(SCXMLExecutionContext)}. The state machine thereafter should be ready
+ *     for processing external events (or be terminated already)</li>
+ *     <li>Processing a single external event and completing the macro step for it, after which the
+ *     state machine should be ready for processing another external event (if any), or be terminated already.
+ *     See: {@link #nextStep(SCXMLExecutionContext, TriggerEvent)}.
+ *     </li>
+ *     <li>Finally, if the state machine terminated ({@link SCXMLExecutionContext#isRunning()} == false), after either
+ *     of the above steps, finalize the state machine by performing the final step.
+ *     See: {@link #finalStep(SCXMLExecutionContext)}.
+ *     </li>
+ * </ul>
+ * </p>
+ * <p>After a state machine has been terminated you can re-initialize the execution context, and start again.</p>
+ * <p>
+ * Except for the loading of the SCXML document and (re)initializing the {@link SCXMLExecutionContext}, the above steps
+ * represent the <b>interpret</b>,<b>mainEventLoop</b> and <b>exitInterpreter</b> entry points specified in Algorithm
+ * for SCXML Interpretation, but more practically and logically broken into separate steps so that the blocking wait
+ * for external events can be handled externally.
+ * </p>
+ * <p>
+ *  These three entry points are the only interface methods used by the SCXMLExecutor. It is up to the
+ *  specific SCXMLSemantics implementation to provide the concrete handling for these according to the Algorithm in
+ *  the SCXML specification (or possibly something else/different).
+ * </p>
+ * <p>
+ * The default {@link org.apache.commons.scxml2.semantics.SCXMLSemanticsImpl} provides an implementation of the
+ * specification, and can easily be overridden/customized as a whole or only on specific parts of the Algorithm
+ * implementation.
+ * </p>
+ * <p>
+ * Note that both the {@link #firstStep(SCXMLExecutionContext)} and {@link #nextStep(SCXMLExecutionContext, TriggerEvent)}
+ * first run to completion for any internal events raised before returning, as expected and required by the SCXML
+ * specification, so it is currently not possible to 'manage' internal event processing externally.
+ * </p>
  *
  * <p>Specific semantics can be created by subclassing
  * <code>org.apache.commons.scxml2.semantics.SCXMLSemanticsImpl</code>.</p>
@@ -44,89 +78,76 @@ public interface SCXMLSemantics {
      */
     SCXML normalizeStateMachine(final SCXML input, final ErrorReporter errRep);
 
-    public void executeGlobalScript(final SCXMLExecutionContext context, final Step step) throws ModelException;
-
-    public void exitStates(final SCXMLExecutionContext ctx, final Step step) throws ModelException;
-
-    public void executeTransitionContent(final SCXMLExecutionContext ctx, final Step step) throws ModelException;
-
-    public void enterStates(final SCXMLExecutionContext ctx, final Step step) throws ModelException;
-
-    /**
-     * Determining the initial state(s) for this state machine.
-     *
-     * @param ctx  provides the execution context
-     * @param step provides target states and entry list to fill in [out]
-     *
-     * @throws org.apache.commons.scxml2.model.ModelException in case there is a fatal SCXML object model problem.
-     */
-    void determineInitialStates(final SCXMLExecutionContext ctx, final Step step) throws ModelException;
-
-    /**
-     * Executes all OnExit/Transition/OnEntry transitional actions.
-     *
-     * @param ctx  provides the execution context
-     * @param step provides EntryList, TransitList, ExitList gets updated its AfterStatus/Events
-     *
-     * @throws org.apache.commons.scxml2.model.ModelException in case there is a fatal SCXML object model problem.
-     */
-    void executeActions(final SCXMLExecutionContext ctx, final Step step) throws ModelException;
-
-    /**
-     * Enumerate all the reachable transitions.
-     *
-     * @param ctx  provides the execution context
-     * @param step with current status and list of transitions to populate
-     */
-    void enumerateReachableTransitions(final SCXMLExecutionContext ctx, final Step step);
-
-    /**
-     * Filter the transitions set, eliminate those whose guard conditions
-     * are not satisfied.
-     *
-     * @param ctx  provides the execution context
-     * @param step with current status
-     *
-     * @throws org.apache.commons.scxml2.model.ModelException in case there is a fatal SCXML object model problem.
-     */
-    void filterTransitionsSet(final SCXMLExecutionContext ctx, final Step step) throws ModelException;
-
-    /**
-     * Follow the candidate transitions for this execution Step, and update the
-     * lists of entered and exited states accordingly.
-     *
-     * @param ctx  provides the execution context
-     * @param step The current Step
-     *
-     * @throws org.apache.commons.scxml2.model.ModelException in case there is a fatal SCXML object model problem.
-     */
-    void followTransitions(final SCXMLExecutionContext ctx, final Step step) throws ModelException;
-
-    /**
-     * Go over the exit list and update history information for
-     * relevant states.
-     *
-     * @param ctx  provides the execution context
-     * @param step The current Step
-     */
-    void updateHistoryStates(final SCXMLExecutionContext ctx, final Step step);
-
-    /**
-     * Forward events to invoked activities, execute finalize handlers.
-     *
-     * @param ctx    provides the execution context
-     * @param event The event to be forwarded
-     *
-     * @throws org.apache.commons.scxml2.model.ModelException in case there is a fatal SCXML object model problem.
-     */
-    void processInvokes(final SCXMLExecutionContext ctx, final TriggerEvent event) throws ModelException;
-
     /**
-     * Initiate any new invoked activities.
-     *
-     * @param ctx  provides the execution context
-     * @param step The current Step
+     * First step in the execution of an SCXML state machine.
+     * <p>
+     * In the default implementation, this will first (re)initialize the state machine instance, destroying any existing
+     * state!
+     * </p>
+     * <p>
+     * The first step is corresponding to the Algorithm for SCXML processing from the interpret() procedure to the
+     * mainLoop() procedure up to the blocking wait for an external event.
+     * </p>
+     * <p>
+     * This step should complete the SCXML initial execution and a subsequent macroStep to stabilize the state machine
+     * again before returning.
+     * </p>
+     * <p>
+     * If the state machine no longer is running after all this, first the {@link #finalStep(SCXMLExecutionContext)}
+     * should be called for cleanup before returning.
+     * </p>
+     * @param exctx The execution context for this step
+     * @throws ModelException if the state machine instance failed to initialize or a SCXML model error occurred during
+     * the execution.
+     */
+    void firstStep(final SCXMLExecutionContext exctx) throws ModelException;
+
+    /**
+     * Next step in the execution of an SCXML state machine.
+     * <p>
+     * The next step is corresponding to the Algorithm for SCXML processing mainEventLoop() procedure after receiving an
+     * external event, up to the blocking wait for another external event.
+     * </p>
+     * <p>
+     * If the state machine isn't {@link SCXMLExecutionContext#isRunning()} (any more), this method should do nothing.
+     * </p>
+     * <p>
+     * If the provided event is a {@link TriggerEvent#CANCEL_EVENT}, the state machine should stop running.
+     * </p>
+     * <p>
+     * Otherwise, the event must be set in the {@link SCXMLSystemContext} and processing of the event then should start,
+     * and if the event leads to any transitions a microStep for this event should be performed, followed up by a
+     * macroStep to stabilize the state machine again before returning.
+     * </p>
+     * <p>
+     * If the state machine no longer is running after all this, first the {@link #finalStep(SCXMLExecutionContext)}
+     * should be called for cleanup before returning.
+     * </p>
+     * @param exctx The execution context for this step
+     * @param event The event to process
+     * @throws ModelException if a SCXML model error occurred during the execution.
+     */
+    void nextStep(final SCXMLExecutionContext exctx, final TriggerEvent event) throws ModelException;
+
+    /**
+     * The final step in the execution of an SCXML state machine.
+     * <p>
+     * This final step is corresponding to the Algorithm for SCXML processing exitInterpreter() procedure, after the
+     * state machine stopped running.
+     * </p>
+     * <p>
+     * If the state machine still is {@link SCXMLExecutionContext#isRunning()} invoking this method should simply
+     * do nothing.
+     * </p>
+     * <p>
+     * This final step should first exit all remaining active states and cancel any active invokers, before handling
+     * the possible donedata element for the last final state.
+     * </p>
+     * <p>
+     *  <em>NOTE: the current implementation does not yet provide final donedata handling.</em>
+     * </p>
+     * @param exctx The execution context for this step
+     * @throws ModelException if a SCXML model error occurred during the execution.
      */
-    void initiateInvokes(final SCXMLExecutor executor, final SCXMLExecutionContext ctx, final Step step);
+    void finalStep(final SCXMLExecutionContext exctx) throws ModelException;
 }
-

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=1584272&r1=1584271&r2=1584272&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 Thu Apr  3 07:13:42 2014
@@ -40,24 +40,23 @@ public class SCXMLSystemContext implemen
      * The protected system variables names as defined in the SCXML specification
      * @see <a href="http://www.w3.org/TR/scxml/#SystemVariables">http://www.w3.org/TR/scxml/#SystemVariables</a>
      */
-    public static final String VARIABLE_EVENT = "_event";
-    public static final String VARIABLE_SESSIONID = "_sessionid";
-    public static final String VARIABLE_NAME = "_name";
-    public static final String VARIABLE_IOPROCESSORS = "_ioprocessors";
-    public static final String VARIABLE_X = "_x";
+    public static final String EVENT_KEY = "_event";
+    public static final String SESSIONID_KEY = "_sessionid";
+    public static final String SCXML_NAME_KEY = "_name";
+    public static final String IOPROCESSORS_KEY = "_ioprocessors";
+    public static final String X_KEY = "_x";
 
     /**
      * Commons SCXML internal system variable holding the current SCXML configuration of all (including ancestors)
      * active states.
      */
-    public static final String VARIABLE_ALL_STATES = "_ALL_STATES";
+    public static final String ALL_STATES_KEY = "_ALL_STATES";
 
     /**
      * The set of protected system variables names
      */
     private static final Set<String> PROTECTED_NAMES = new HashSet<String>(Arrays.asList(
-            new String[] { VARIABLE_EVENT, VARIABLE_SESSIONID, VARIABLE_NAME, VARIABLE_IOPROCESSORS, VARIABLE_X
-                    , VARIABLE_ALL_STATES }
+            new String[] {EVENT_KEY, SESSIONID_KEY, SCXML_NAME_KEY, IOPROCESSORS_KEY, X_KEY, ALL_STATES_KEY}
     ));
 
     /**
@@ -67,13 +66,25 @@ public class SCXMLSystemContext implemen
     private Context systemContext;
 
     /**
+     * Initialize or replace systemContext
+     * @param systemContext the system context to set
+     */
+    void setSystemContext(Context systemContext) {
+        if (this.systemContext != null) {
+            // replace systemContext
+            systemContext.getVars().putAll(this.systemContext.getVars());
+        }
+        this.systemContext = systemContext;
+        this.protectedVars = Collections.unmodifiableMap(systemContext.getVars());
+    }
+
+    /**
      * The unmodifiable wrapped variables map from the wrapped system context
      */
     private Map<String, Object> protectedVars;
 
     public SCXMLSystemContext(Context systemContext) {
-        this.systemContext = systemContext;
-        this.protectedVars = Collections.unmodifiableMap(systemContext.getVars());
+        setSystemContext(systemContext);
     }
 
     @Override

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Status.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Status.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Status.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/Status.java Thu Apr  3 07:13:42 2014
@@ -37,22 +37,17 @@ public class Status implements Serializa
     /**
      * The states that are currently active.
      */
-    private Set<EnterableState> states;
+    private final Set<EnterableState> states = new HashSet<EnterableState>();
 
     /**
-     * Have we reached a final configuration for this state machine.
-     *
-     * True - if all the states are final and there are not events
-     * pending from the last step. False - otherwise.
-     *
-     * @return Whether a final configuration has been reached.
+     * @return Whether the state machine terminated AND we reached a top level Final state.
      */
     public boolean isFinal() {
         return getFinalState() != null;
     }
 
     /**
-     * @return Returns the single top level active final state or null otherwise
+     * @return Returns the single top level final state in which the state machine terminated, or null otherwise
      */
     public Final getFinalState() {
         if (states.size() == 1) {
@@ -65,13 +60,6 @@ public class Status implements Serializa
     }
 
     /**
-     * Constructor.
-     */
-    public Status() {
-        states = new HashSet<EnterableState>();
-    }
-
-    /**
      * Get the states configuration (leaf only).
      *
      * @return Returns the states configuration - simple (leaf) states only.
@@ -87,8 +75,21 @@ public class Status implements Serializa
      *         complex ancestors up to the root.
      */
     public Set<EnterableState> getAllStates() {
-        return SCXMLHelper.getAncestorClosure(states, null);
+        Set<EnterableState> allStates = new HashSet<EnterableState>(states.size() * 2);
+        for (EnterableState es : states) {
+            EnterableState state = es;
+            while (state != null && allStates.add(state)) {
+                state = state.getParent();
+            }
+        }
+        return allStates;
     }
 
+    /**
+     * Clears the status
+     */
+    public void clear() {
+        states.clear();
+    }
 }
 

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/TriggerEvent.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/TriggerEvent.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/TriggerEvent.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/TriggerEvent.java Thu Apr  3 07:13:42 2014
@@ -86,6 +86,12 @@ public class TriggerEvent implements Ser
     public static final int ERROR_EVENT = 5;
 
     /**
+     * <code>CANCEL_EVENT</code>.
+     *
+     */
+    public static final int CANCEL_EVENT = 6;
+
+    /**
      * The event name.
      *
      */

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/AbstractSCXMLListener.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/AbstractSCXMLListener.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/AbstractSCXMLListener.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/AbstractSCXMLListener.java Thu Apr  3 07:13:42 2014
@@ -45,10 +45,10 @@ public abstract class AbstractSCXMLListe
     }
 
     /**
-* @see SCXMLListener#onTransition(TransitionTarget,TransitionTarget,Transition)
+* @see SCXMLListener#onTransition(TransitionTarget,TransitionTarget,Transition,String)
      */
     public void onTransition(final TransitionTarget from,
-            final TransitionTarget to, final Transition transition) {
+            final TransitionTarget to, final Transition transition, final String event) {
         // empty
     }
 

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/AbstractStateMachine.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/AbstractStateMachine.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/AbstractStateMachine.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/AbstractStateMachine.java Thu Apr  3 07:13:42 2014
@@ -99,7 +99,7 @@ public abstract class AbstractStateMachi
      *                      describes the &quot;lifecycle&quot; of the
      *                      instances of this class.
      */
-    public AbstractStateMachine(final URL scxmlDocument) {
+    public AbstractStateMachine(final URL scxmlDocument) throws ModelException {
         // default is JEXL
         this(scxmlDocument, new JexlContext(), new JexlEvaluator());
     }
@@ -117,7 +117,7 @@ public abstract class AbstractStateMachi
      * @see Evaluator
      */
     public AbstractStateMachine(final URL scxmlDocument,
-            final Context rootCtx, final Evaluator evaluator) {
+            final Context rootCtx, final Evaluator evaluator) throws ModelException {
         log = LogFactory.getLog(this.getClass());
         try {
             stateMachine = SCXMLReader.read(scxmlDocument);
@@ -140,7 +140,7 @@ public abstract class AbstractStateMachi
      *
      * @since 0.7
      */
-    public AbstractStateMachine(final SCXML stateMachine) {
+    public AbstractStateMachine(final SCXML stateMachine) throws ModelException {
         // default is JEXL
         this(stateMachine, new JexlContext(), new JexlEvaluator());
     }
@@ -160,7 +160,7 @@ public abstract class AbstractStateMachi
      * @since 0.7
      */
     public AbstractStateMachine(final SCXML stateMachine,
-            final Context rootCtx, final Evaluator evaluator) {
+            final Context rootCtx, final Evaluator evaluator) throws ModelException {
         log = LogFactory.getLog(this.getClass());
         initialize(stateMachine, rootCtx, evaluator);
     }
@@ -173,11 +173,10 @@ public abstract class AbstractStateMachi
      * @param evaluator The expression evaluator
      */
     private void initialize(final SCXML stateMachine,
-            final Context rootCtx, final Evaluator evaluator) {
+            final Context rootCtx, final Evaluator evaluator) throws ModelException {
         engine = new SCXMLExecutor(evaluator, new SimpleDispatcher(),
             new SimpleErrorReporter());
         engine.setStateMachine(stateMachine);
-        engine.setSuperStep(true);
         engine.setRootContext(rootCtx);
         engine.addListener(stateMachine, new EntryListener());
         try {
@@ -308,9 +307,10 @@ public abstract class AbstractStateMachi
          * @param from The &quot;source&quot; transition target.
          * @param to The &quot;destination&quot; transition target.
          * @param transition The transition being followed.
+         * @param event The event triggering the transition
          */
         public void onTransition(final TransitionTarget from,
-                final TransitionTarget to, final Transition transition) {
+                final TransitionTarget to, final Transition transition, final String event) {
             // nothing to do
         }
 

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/LogUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/LogUtils.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/LogUtils.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/LogUtils.java Thu Apr  3 07:13:42 2014
@@ -34,9 +34,9 @@ public final class LogUtils {
      * @return String The human readable log entry
      */
     public static String transToString(final TransitionTarget from,
-            final TransitionTarget to, final Transition transition) {
-        StringBuffer buf = new StringBuffer("transition (");
-        buf.append("event = ").append(transition.getEvent());
+            final TransitionTarget to, final Transition transition, String event) {
+        StringBuffer buf = new StringBuffer("(");
+        buf.append("event = ").append(event);
         buf.append(", cond = ").append(transition.getCond());
         buf.append(", from = ").append(getTTPath(from));
         buf.append(", to = ").append(getTTPath(to));

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=1584272&r1=1584271&r2=1584272&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 Thu Apr  3 07:13:42 2014
@@ -168,7 +168,7 @@ public class SimpleContext implements Co
      */
     public void setLocal(final String name, final Object value) {
         getVars().put(name, value);
-        if (log.isDebugEnabled() && !name.equals(SCXMLSystemContext.VARIABLE_ALL_STATES)) {
+        if (log.isDebugEnabled() && !name.equals(SCXMLSystemContext.ALL_STATES_KEY)) {
             log.debug(name + " = " + String.valueOf(value));
         }
     }

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleErrorReporter.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleErrorReporter.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleErrorReporter.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleErrorReporter.java Thu Apr  3 07:13:42 2014
@@ -24,6 +24,7 @@ import java.util.Set;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.scxml2.ErrorReporter;
+import org.apache.commons.scxml2.model.Data;
 import org.apache.commons.scxml2.model.EnterableState;
 import org.apache.commons.scxml2.model.Executable;
 import org.apache.commons.scxml2.model.SCXML;
@@ -105,6 +106,10 @@ public class SimpleErrorReporter impleme
                 TransitionTarget parent = ((Executable) errCtx).getParent();
                 msg.append("Expression error inside " + LogUtils.getTTPath(parent));
             }
+            else if (errCtx instanceof Data) {
+                // Data expression error
+                msg.append("Expression error for data element with id "+((Data)errCtx).getId());
+            }
             else if (errCtx instanceof SCXML) {
                 // Global Script
                 msg.append("Expression error inside the global script");

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleSCXMLListener.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleSCXMLListener.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleSCXMLListener.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleSCXMLListener.java Thu Apr  3 07:13:42 2014
@@ -42,7 +42,7 @@ public class SimpleSCXMLListener impleme
      */
     public void onEntry(final EnterableState state) {
         if (log.isInfoEnabled()) {
-            log.info(LogUtils.getTTPath(state));
+            log.info("enter " + LogUtils.getTTPath(state));
         }
     }
 
@@ -51,17 +51,17 @@ public class SimpleSCXMLListener impleme
      */
     public void onExit(final EnterableState state) {
         if (log.isInfoEnabled()) {
-            log.info(LogUtils.getTTPath(state));
+            log.info("exit " + LogUtils.getTTPath(state));
         }
     }
 
     /**
-* @see SCXMLListener#onTransition(TransitionTarget,TransitionTarget,Transition)
+* @see SCXMLListener#onTransition(TransitionTarget,TransitionTarget,Transition,String)
      */
     public void onTransition(final TransitionTarget from,
-            final TransitionTarget to, final Transition transition) {
+            final TransitionTarget to, final Transition transition, String event) {
         if (log.isInfoEnabled()) {
-            log.info(LogUtils.transToString(from, to, transition));
+            log.info("transition " + LogUtils.transToString(from, to, transition, event));
         }
     }
 

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleScheduler.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleScheduler.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleScheduler.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/SimpleScheduler.java Thu Apr  3 07:13:42 2014
@@ -28,7 +28,6 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.scxml2.EventDispatcher;
 import org.apache.commons.scxml2.SCXMLExecutor;
-import org.apache.commons.scxml2.SCXMLHelper;
 import org.apache.commons.scxml2.TriggerEvent;
 import org.apache.commons.scxml2.model.ModelException;
 import org.w3c.dom.Node;
@@ -120,10 +119,9 @@ public class SimpleScheduler implements 
         }
 
         // We only handle the "scxml" type (which is the default too)
-        if (SCXMLHelper.isStringEmpty(type)
-                || type.trim().equalsIgnoreCase(TYPE_SCXML)) {
+        if (type == null || type.equalsIgnoreCase(TYPE_SCXML)) {
 
-            if (!SCXMLHelper.isStringEmpty(target)) {
+            if (target != null) {
                 // We know of no other target
                 if (log.isWarnEnabled()) {
                     log.warn("<send>: Unavailable target - " + target);

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/Tracer.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/Tracer.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/Tracer.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/Tracer.java Thu Apr  3 07:13:42 2014
@@ -107,11 +107,11 @@ public class Tracer implements ErrorHand
     }
 
     /**
-     * @see SCXMLListener#onTransition(TransitionTarget,TransitionTarget,Transition)
+     * @see SCXMLListener#onTransition(TransitionTarget,TransitionTarget,Transition,String)
      */
     public void onTransition(final TransitionTarget from,
-            final TransitionTarget to, final Transition transition) {
-        scxmlListener.onTransition(from, to, transition);
+            final TransitionTarget to, final Transition transition, final String event) {
+        scxmlListener.onTransition(from, to, transition, event);
     }
 
     /**

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=1584272&r1=1584271&r2=1584272&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 Thu Apr  3 07:13:42 2014
@@ -22,6 +22,7 @@ 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;
 
@@ -55,7 +56,7 @@ public abstract class GroovySCXMLScript 
      */
     @SuppressWarnings("unchecked")
     private Map<String, String> getNamespaces() {
-        return (Map<String, String>) context.get("_ALL_NAMESPACES");
+        return (Map<String, String>) context.get(Context.NAMESPACES_KEY);
     }
 
     /**
@@ -64,7 +65,7 @@ public abstract class GroovySCXMLScript 
      */
     @SuppressWarnings("unchecked")
     private Set<EnterableState> getAllStates() {
-        return (Set<EnterableState>) context.get(SCXMLSystemContext.VARIABLE_ALL_STATES);
+        return (Set<EnterableState>) context.get(SCXMLSystemContext.ALL_STATES_KEY);
     }
 
     /**

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java Thu Apr  3 07:13:42 2014
@@ -28,6 +28,7 @@ import org.apache.commons.scxml2.Builtin
 import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.SCXMLExpressionException;
+import org.apache.commons.scxml2.SCXMLSystemContext;
 import org.w3c.dom.Node;
 
 /**
@@ -101,8 +102,8 @@ public class JSEvaluator implements Eval
             Bindings     bindings = engine.getBindings     (ScriptContext.ENGINE_SCOPE);
 
             // ... replace built-in functions
-            String jsExpression = IN_FN.matcher(expression).replaceAll("_builtin.isMember(_ALL_STATES, ");
-            jsExpression = DATA_FN.matcher(jsExpression).replaceAll("_builtin.data(_ALL_NAMESPACES, ");
+            String jsExpression = IN_FN.matcher(expression).replaceAll("_builtin.isMember("+SCXMLSystemContext.ALL_STATES_KEY +", ");
+            jsExpression = DATA_FN.matcher(jsExpression).replaceAll("_builtin.data("+Context.NAMESPACES_KEY+", ");
 
             // ... evaluate
             return engine.eval(jsExpression,new JSBindings(context,bindings));
@@ -161,8 +162,8 @@ public class JSEvaluator implements Eval
 
             // ... replace built-in functions
             String jsExpression = IN_FN.matcher(expression).replaceAll("_builtin.isMember(_ALL_STATES, ");
-            jsExpression = DATA_FN.matcher(jsExpression).replaceFirst("_builtin.dataNode(_ALL_NAMESPACES, ");
-            jsExpression = DATA_FN.matcher(jsExpression).replaceAll("_builtin.data(_ALL_NAMESPACES, ");
+            jsExpression = DATA_FN.matcher(jsExpression).replaceFirst("_builtin.dataNode("+Context.NAMESPACES_KEY+", ");
+            jsExpression = DATA_FN.matcher(jsExpression).replaceAll("_builtin.data("+Context.NAMESPACES_KEY+", ");
 
             // ... evaluate
             return (Node) engine.eval(jsExpression,new JSBindings(context,bindings));

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java Thu Apr  3 07:13:42 2014
@@ -20,6 +20,7 @@ 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;
 
@@ -47,7 +48,7 @@ public final class JexlBuiltin {
      */
     @SuppressWarnings("unchecked")
     private Map<String, String> getNamespaces() {
-        return (Map<String, String>) context.get("_ALL_NAMESPACES");
+        return (Map<String, String>) context.get(Context.NAMESPACES_KEY);
     }
 
     /**
@@ -56,7 +57,7 @@ public final class JexlBuiltin {
      */
     @SuppressWarnings("unchecked")
     private Set<EnterableState> getAllStates() {
-        return (Set<EnterableState>) context.get(SCXMLSystemContext.VARIABLE_ALL_STATES);
+        return (Set<EnterableState>) context.get(SCXMLSystemContext.ALL_STATES_KEY);
     }
 
     /**

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/xpath/FunctionResolver.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/xpath/FunctionResolver.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/xpath/FunctionResolver.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/xpath/FunctionResolver.java Thu Apr  3 07:13:42 2014
@@ -45,9 +45,7 @@ public class FunctionResolver implements
     private static final String NAMESPACE_COMMONS_SCXML =
         "http://commons.apache.org/scxml";
     /** The {@link Context} key to retrieve all the current states. */
-    private static final String STATES = SCXMLSystemContext.VARIABLE_ALL_STATES;
-    /** The {@link Context} key to retrieve all the current namespaces. */
-    private static final String NAMESPACES = "_ALL_NAMESPACES";
+    private static final String STATES = SCXMLSystemContext.ALL_STATES_KEY;
 
     /** Functions map. */
     private final Map<FunctionKey, XPathFunction> functions =
@@ -138,7 +136,7 @@ public class FunctionResolver implements
         @SuppressWarnings("unchecked")
         public Object evaluate(final List args) throws XPathFunctionException {
             Map<String, String> namespaces =
-                (Map<String, String>) xctx.get(NAMESPACES);
+                (Map<String, String>) xctx.get(Context.NAMESPACES_KEY);
             Object node = xctx.get((String) args.get(0));
             return Builtin.data(namespaces, node, (String) args.get(1));
         }
@@ -163,7 +161,7 @@ public class FunctionResolver implements
         @SuppressWarnings("unchecked")
         public Object evaluate(final List args) throws XPathFunctionException {
             Map<String, String> namespaces =
-                (Map<String, String>) xctx.get(NAMESPACES);
+                (Map<String, String>) xctx.get(Context.NAMESPACES_KEY);
             Object node = xctx.get((String) args.get(0));
             return Builtin.dataNode(namespaces, node, (String) args.get(1));
         }

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java Thu Apr  3 07:13:42 2014
@@ -152,7 +152,7 @@ public class XPathEvaluator implements E
         fnResolver.setContext(xctx);
         XPath xpath = factory.newXPath();
         NamespaceContext nsCtx =
-            new ExpressionNSContext((Map<String, String>) ctx.get("_ALL_NAMESPACES"));
+            new ExpressionNSContext((Map<String, String>) ctx.get(Context.NAMESPACES_KEY));
         xpath.setNamespaceContext(nsCtx);
         return xpath;
     }

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/AsyncTrigger.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/AsyncTrigger.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/AsyncTrigger.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/AsyncTrigger.java Thu Apr  3 07:13:42 2014
@@ -16,7 +16,7 @@
  */
 package org.apache.commons.scxml2.invoke;
 
-import org.apache.commons.scxml2.SCXMLExecutor;
+import org.apache.commons.scxml2.SCXMLIOProcessor;
 import org.apache.commons.scxml2.TriggerEvent;
 
 /**
@@ -25,19 +25,19 @@ import org.apache.commons.scxml2.Trigger
  */
 class AsyncTrigger implements Runnable {
 
-    /** The state machine executor. */
-    private final SCXMLExecutor executor;
+    /** The SCXML state machine I/O Processor to deliver the event to. */
+    private final SCXMLIOProcessor ioProcessor;
     /** The event to be triggered. */
     private final TriggerEvent event;
 
     /**
      * Constructor.
      *
-     * @param executor The {@link SCXMLExecutor} to trigger the event on.
+     * @param ioProcessor The {@link org.apache.commons.scxml2.SCXMLIOProcessor} to trigger the event on.
      * @param event The {@link TriggerEvent}.
      */
-    AsyncTrigger(final SCXMLExecutor executor, final TriggerEvent event) {
-        this.executor = executor;
+    AsyncTrigger(final SCXMLIOProcessor ioProcessor, final TriggerEvent event) {
+        this.ioProcessor = ioProcessor;
         this.event = event;
     }
 
@@ -52,7 +52,7 @@ class AsyncTrigger implements Runnable {
      * Fire the event(s).
      */
     public void run() {
-        executor.addEvent(event);
+        ioProcessor.addEvent(event);
     }
 
 }

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/Invoker.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/Invoker.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/Invoker.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/Invoker.java Thu Apr  3 07:13:42 2014
@@ -18,7 +18,8 @@ package org.apache.commons.scxml2.invoke
 
 import java.util.Map;
 
-import org.apache.commons.scxml2.SCXMLExecutor;
+import org.apache.commons.scxml2.Evaluator;
+import org.apache.commons.scxml2.SCXMLIOProcessor;
 import org.apache.commons.scxml2.TriggerEvent;
 
 /**
@@ -28,10 +29,10 @@ import org.apache.commons.scxml2.Trigger
  *
  * <p>Invocable activities must first register an Invoker implementation class
  * for the appropriate "target" (attribute of &lt;invoke&gt;) with the
- * parent <code>SCXMLExecutor</code>.</p>
+ * parent <code>SCXMLParentIOProcessor</code>.</p>
  *
  * <p>The communication link between the parent state machine executor and
- * the invoked activity is a bi-directional events pipe.</p>
+ * the invoked activity is a asynchronous bi-directional events pipe.</p>
  *
  * <p>All events triggered on the parent state machine get forwarded to the
  * invoked activity. The processing semantics for these events depend
@@ -42,16 +43,15 @@ import org.apache.commons.scxml2.Trigger
  * when it concludes. It may fire additional events before the "done"
  * event. The semantics of any additional events depend upon the
  * "target". The invoked activity must not fire any events after the "done"
- * event. The name of the special "done" event must be the ID of the parent
- * state wherein the corresponding &lt;invoke&gt; resides, with the String
- * ".invoke.done" appended.</p>
+ * event. The name of the special "done" event must be "done.invoke.id" with
+ * the ID of the parent state wherein the corresponding &lt;invoke&gt; resides,</p>
  *
  * <p>The Invoker "lifecycle" is outlined below:
  *  <ol>
  *   <li>Instantiation via {@link Class#newInstance()}
  *       (Invoker implementation requires accessible constructor).</li>
- *   <li>Configuration (setters for parent state ID and
- *       {@link SCXMLExecutor}).</li>
+ *   <li>Configuration (setters for invoke ID and
+ *       {@link org.apache.commons.scxml2.SCXMLIOProcessor}).</li>
  *   <li>Initiation of invoked activity via invoke() method, passing
  *       the source URI and the map of params.</li>
  *   <li>Zero or more bi-directional event triggering.</li>
@@ -61,29 +61,35 @@ import org.apache.commons.scxml2.Trigger
  *
  * <p><b>Note:</b> The semantics of &lt;invoke&gt; are necessarily
  * asynchronous, tending towards long(er) running interactions with external
- * processes. Implementations must not communicate with the parent state
+ * processes. Implementations cannot communicate with the parent state
  * machine executor in a synchronous manner. For synchronous
  * communication semantics, use &lt;event&gt; or custom actions instead.</p>
  */
 public interface Invoker {
 
     /**
-     * Set the state ID of the owning state for the &lt;invoke&gt;.
+     * Set the invoke ID provided by the parent state machine executor
      * Implementations must use this ID for constructing the event name for
      * the special "done" event (and optionally, for other event names
      * as well).
      *
-     * @param parentStateId The ID of the parent state.
+     * @param invokeId The invoke ID provided by the parent state machine executor.
      */
-    void setParentStateId(String parentStateId);
+    void setInvokeId(String invokeId);
 
     /**
-     * Set the execution "context" of the parent state machine, which provides the
+     * Set I/O Processor of the parent state machine, which provides the
      * channel.
      *
-     * @param parentExecutor The execution "context" of the parent state machine.
+     * @param parentIOProcessor The I/O Processor of the parent state machine.
      */
-    void setParentExecutor(SCXMLExecutor parentExecutor);
+    void setParentIOProcessor(SCXMLIOProcessor parentIOProcessor);
+
+    /**
+     * Set the Evaluator to be used by the child state machine (to ensure/enforce a compatible data model)
+     * @param evaluator the Evaluator to be used
+     */
+    void setEvaluator(Evaluator evaluator);
 
     /**
      * Begin this invocation.
@@ -97,18 +103,18 @@ public interface Invoker {
     throws InvokerException;
 
     /**
-     * Forwards the events triggered on the parent state machine
+     * Forwards the event triggered on the parent state machine
      * on to the invoked activity.
      *
-     * @param evts
-     *            an array of external events which triggered during the last
+     * @param event
+     *            an external event which triggered during the last
      *            time quantum
      *
      * @throws InvokerException In case there is a fatal problem with
      *                          processing the events forwarded by the
      *                          parent state machine.
      */
-    void parentEvents(TriggerEvent[] evts)
+    void parentEvent(TriggerEvent event)
     throws InvokerException;
 
     /**

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/SimpleSCXMLInvoker.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/SimpleSCXMLInvoker.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/SimpleSCXMLInvoker.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/invoke/SimpleSCXMLInvoker.java Thu Apr  3 07:13:42 2014
@@ -26,6 +26,7 @@ import javax.xml.stream.XMLStreamExcepti
 import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.SCXMLExecutor;
+import org.apache.commons.scxml2.SCXMLIOProcessor;
 import org.apache.commons.scxml2.TriggerEvent;
 import org.apache.commons.scxml2.env.SimpleDispatcher;
 import org.apache.commons.scxml2.env.SimpleErrorReporter;
@@ -44,38 +45,35 @@ public class SimpleSCXMLInvoker implemen
     private static final long serialVersionUID = 1L;
     /** Parent state ID. */
     private String parentStateId;
-    /** Event prefix, all events sent to the parent executor must begin
-     *  with this prefix. */
-    private String eventPrefix;
-    /** Invoking document's SCXMLExecutor */
-    private SCXMLExecutor parentExecutor;
+    /** Invoking document's external I/O Processor */
+    private SCXMLIOProcessor parentIOProcessor;
+    /** The Evaluator provided by the parent executor */
+    private Evaluator evaluator;
     /** The invoked state machine executor. */
     private SCXMLExecutor executor;
     /** Cancellation status. */
     private boolean cancelled;
 
-    //// Constants
-    /** Prefix for all events sent to the parent state machine. */
-    private static String invokePrefix = ".invoke.";
-    /** Suffix for invoke done event. */
-    private static String invokeDone = "done";
-    /** Suffix for invoke cancel response event. */
-    private static String invokeCancelResponse = "cancel.response";
-
     /**
      * {@inheritDoc}.
      */
-    public void setParentStateId(final String parentStateId) {
-        this.parentStateId = parentStateId;
-        this.eventPrefix = this.parentStateId + invokePrefix;
+    public void setInvokeId(final String invokeId) {
+        this.parentStateId = invokeId;
         this.cancelled = false;
     }
 
     /**
      * {@inheritDoc}.
      */
-    public void setParentExecutor(final SCXMLExecutor parentExecutor) {
-        this.parentExecutor = parentExecutor;
+    public void setParentIOProcessor(SCXMLIOProcessor parentIOProcessor) {
+        this.parentIOProcessor = parentIOProcessor;
+    }
+
+    /**
+     * {@inheritDoc}.
+     */
+    public void setEvaluator(final Evaluator evaluator) {
+        this.evaluator = evaluator;
     }
 
     /**
@@ -83,7 +81,7 @@ public class SimpleSCXMLInvoker implemen
      */
     public void invoke(final String source, final Map<String, Object> params)
     throws InvokerException {
-        SCXML scxml = null;
+        SCXML scxml;
         try {
             scxml = SCXMLReader.read(new URL(source));
         } catch (ModelException me) {
@@ -93,15 +91,18 @@ public class SimpleSCXMLInvoker implemen
         } catch (XMLStreamException xse) {
             throw new InvokerException(xse.getMessage(), xse.getCause());
         }
-        Evaluator eval = parentExecutor.getEvaluator();
-        executor = new SCXMLExecutor(eval,
-            new SimpleDispatcher(), new SimpleErrorReporter());
-        Context rootCtx = eval.newContext(null);
+        executor = new SCXMLExecutor(evaluator, new SimpleDispatcher(), new SimpleErrorReporter());
+        Context rootCtx = evaluator.newContext(null);
         for (Map.Entry<String, Object> entry : params.entrySet()) {
             rootCtx.setLocal(entry.getKey(), entry.getValue());
         }
         executor.setRootContext(rootCtx);
-        executor.setStateMachine(scxml);
+        try {
+            executor.setStateMachine(scxml);
+        }
+        catch (ModelException me) {
+            throw new InvokerException(me);
+        }
         executor.addListener(scxml, new SimpleSCXMLListener());
         executor.registerInvokerClass("scxml", this.getClass());
         try {
@@ -110,30 +111,28 @@ public class SimpleSCXMLInvoker implemen
             throw new InvokerException(me.getMessage(), me.getCause());
         }
         if (executor.getCurrentStatus().isFinal()) {
-            TriggerEvent te = new TriggerEvent(eventPrefix + invokeDone,
-                TriggerEvent.SIGNAL_EVENT);
-            new AsyncTrigger(parentExecutor, te).start();
+            TriggerEvent te = new TriggerEvent("done.invoke."+parentStateId, TriggerEvent.SIGNAL_EVENT);
+            new AsyncTrigger(parentIOProcessor, te).start();
         }
     }
 
     /**
      * {@inheritDoc}.
      */
-    public void parentEvents(final TriggerEvent[] evts)
+    public void parentEvent(final TriggerEvent evt)
     throws InvokerException {
         if (cancelled) {
             return; // no further processing should take place
         }
         boolean doneBefore = executor.getCurrentStatus().isFinal();
         try {
-            executor.triggerEvents(evts);
+            executor.triggerEvent(evt);
         } catch (ModelException me) {
             throw new InvokerException(me.getMessage(), me.getCause());
         }
         if (!doneBefore && executor.getCurrentStatus().isFinal()) {
-            TriggerEvent te = new TriggerEvent(eventPrefix + invokeDone,
-                TriggerEvent.SIGNAL_EVENT);
-            new AsyncTrigger(parentExecutor, te).start();
+            TriggerEvent te = new TriggerEvent("done.invoke."+parentStateId,TriggerEvent.SIGNAL_EVENT);
+            new AsyncTrigger(parentIOProcessor, te).start();
         }
     }
 
@@ -143,9 +142,11 @@ public class SimpleSCXMLInvoker implemen
     public void cancel()
     throws InvokerException {
         cancelled = true;
-        TriggerEvent te = new TriggerEvent(eventPrefix
-            + invokeCancelResponse, TriggerEvent.SIGNAL_EVENT);
-        new AsyncTrigger(parentExecutor, te).start();
+        try {
+            executor.triggerEvent(new TriggerEvent("cancel.invoke."+parentStateId, TriggerEvent.CANCEL_EVENT));
+        } catch (ModelException me) {
+            throw new InvokerException(me.getMessage(), me.getCause());
+        }
     }
 
 }

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/ModelUpdater.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/ModelUpdater.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/ModelUpdater.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/ModelUpdater.java Thu Apr  3 07:13:42 2014
@@ -24,7 +24,6 @@ import java.util.Set;
 import java.util.StringTokenizer;
 
 import org.apache.commons.logging.LogFactory;
-import org.apache.commons.scxml2.SCXMLHelper;
 import org.apache.commons.scxml2.model.EnterableState;
 import org.apache.commons.scxml2.model.History;
 import org.apache.commons.scxml2.model.Initial;
@@ -170,7 +169,6 @@ final class ModelUpdater {
             // If 'initial' is not specified, the default initial state is
             // the first child state in document order.
             initialTransition.getTargets().add(scxml.getFirstChild());
-            initialTransition.getPaths(); // init paths
         }
 
         scxml.setInitialTransition(initialTransition);
@@ -261,7 +259,7 @@ final class ModelUpdater {
             }
             SimpleTransition initialTransition = ini.getTransition();
             updateTransition(initialTransition, targets);
-            List<TransitionTarget> initialStates = initialTransition.getTargets();
+            Set<TransitionTarget> initialStates = initialTransition.getTargets();
             // we have to allow for an indirect descendant initial (targets)
             //check that initialState is a descendant of s
             if (initialStates.size() == 0) {
@@ -269,7 +267,7 @@ final class ModelUpdater {
                         new Object[] {getName(state)});
             } else {
                 for (TransitionTarget initialState : initialStates) {
-                    if (!SCXMLHelper.isDescendant(initialState, state)) {
+                    if (!initialState.isDescendantOf(state)) {
                         logAndThrowModelError(ERR_STATE_BAD_INIT,
                                 new Object[] {getName(state)});
                     }
@@ -293,22 +291,14 @@ final class ModelUpdater {
         }
 
         for (Invoke inv : state.getInvokes()) {
-            String type = inv.getType();
-            if (SCXMLHelper.isStringEmpty(type)) {
-                logAndThrowModelError(ERR_INVOKE_NO_TYPE,
-                        new Object[] {getName(state)});
+            if (inv.getType() == null) {
+                logAndThrowModelError(ERR_INVOKE_NO_TYPE, new Object[] {getName(state)});
             }
-            String src = inv.getSrc();
-            boolean noSrc = SCXMLHelper.isStringEmpty(src);
-            String srcexpr = inv.getSrcexpr();
-            boolean noSrcexpr = SCXMLHelper.isStringEmpty(srcexpr);
-            if (noSrc && noSrcexpr) {
-                logAndThrowModelError(ERR_INVOKE_NO_SRC,
-                        new Object[] {getName(state)});
+            if (inv.getSrc() == null && inv.getSrcexpr() == null) {
+                logAndThrowModelError(ERR_INVOKE_NO_SRC, new Object[] {getName(state)});
             }
-            if (!noSrc && !noSrcexpr) {
-                logAndThrowModelError(ERR_INVOKE_AMBIGUOUS_SRC,
-                        new Object[] {getName(state)});
+            if (inv.getSrc() != null && inv.getSrcexpr() != null) {
+                logAndThrowModelError(ERR_INVOKE_AMBIGUOUS_SRC, new Object[] {getName(state)});
             }
         }
 
@@ -366,7 +356,7 @@ final class ModelUpdater {
         }
         else {
             updateTransition(transition, targets);
-            List<TransitionTarget> historyStates = transition.getTargets();
+            Set<TransitionTarget> historyStates = transition.getTargets();
             if (historyStates.size() == 0) {
                 logAndThrowModelError(ERR_STATE_NO_HIST,
                         new Object[] {getName(parent)});
@@ -380,7 +370,7 @@ final class ModelUpdater {
                     }
                 } else {
                     // Deep history
-                    if (!SCXMLHelper.isDescendant(historyState, parent)) {
+                    if (!historyState.isDescendantOf(parent)) {
                         logAndThrowModelError(ERR_STATE_BAD_DEEP_HIST,
                                 new Object[] {getName(parent)});
                     }
@@ -402,8 +392,8 @@ final class ModelUpdater {
         if (next == null) { // stay transition
             return;
         }
-        List<TransitionTarget> tts = transition.getTargets();
-        if (tts.size() == 0) {
+        Set<TransitionTarget> tts = transition.getTargets();
+        if (tts.isEmpty()) {
             // 'next' is a space separated list of transition target IDs
             StringTokenizer ids = new StringTokenizer(next);
             while (ids.hasMoreTokens()) {
@@ -423,7 +413,6 @@ final class ModelUpdater {
                 }
             }
         }
-        transition.getPaths(); // init paths
     }
 
     /**
@@ -455,16 +444,16 @@ final class ModelUpdater {
         String name = "anonymous transition target";
         if (tt instanceof State) {
             name = "anonymous state";
-            if (!SCXMLHelper.isStringEmpty(tt.getId())) {
+            if (tt.getId() != null) {
                 name = "state with ID \"" + tt.getId() + "\"";
             }
         } else if (tt instanceof Parallel) {
             name = "anonymous parallel";
-            if (!SCXMLHelper.isStringEmpty(tt.getId())) {
+            if (tt.getId() != null) {
                 name = "parallel with ID \"" + tt.getId() + "\"";
             }
         } else {
-            if (!SCXMLHelper.isStringEmpty(tt.getId())) {
+            if (tt.getId() != null) {
                 name = "transition target with ID \"" + tt.getId() + "\"";
             }
         }
@@ -473,37 +462,45 @@ final class ModelUpdater {
 
     /**
      * If a transition has multiple targets, then they satisfy the following
-     * criteria.
+     * criteria:
      * <ul>
-     *  <li>They must belong to the regions of the same parallel</li>
-     *  <li>All regions must be represented with exactly one target</li>
+     *  <li>No target is an ancestor of any other target on the list</li>
+     *  <li>A full legal state configuration results when all ancestors and default initial descendants have been added.
+     *  <br/>This means that they all must share the same least common parallel ancestor.
+     *  </li>
      * </ul>
      *
      * @param tts The transition targets
      * @return Whether this is a legal configuration
+     * @see <a href=http://www.w3.org/TR/2014/CR-scxml-20140313/#LegalStateConfigurations">
+     *     http://www.w3.org/TR/2014/CR-scxml-20140313/#LegalStateConfigurations</a>
      */
-    private static boolean verifyTransitionTargets(final List<TransitionTarget> tts) {
+    private static boolean verifyTransitionTargets(final Set<TransitionTarget> tts) {
         if (tts.size() <= 1) { // No contention
             return true;
         }
-        TransitionTarget lca = SCXMLHelper.getLCA(tts.get(0), tts.get(1));
-        if (lca == null || !(lca instanceof Parallel)) {
-            return false; // Must have a Parallel LCA
-        }
-        Parallel parallel = (Parallel) lca;
-        Set<TransitionTarget> regions = new HashSet<TransitionTarget>();
+
+        Set<EnterableState> parents = new HashSet<EnterableState>();
         for (TransitionTarget tt : tts) {
-            while (tt != null && tt.getParent() != parallel) {
-                tt = tt.getParent();
+            boolean hasParallelParent = false;
+            for (int i = tt.getNumberOfAncestors()-1; i > -1; i--) {
+                EnterableState parent = tt.getAncestor(i);
+                if (parent instanceof Parallel) {
+                    hasParallelParent = true;
+                    // keep on 'reading' as a parallel may have a parent parallel (and even intermediate states)
+                }
+                else {
+                    if (!parents.add(parent)) {
+                        // this TransitionTarget is an descendant of another, or shares the same Parallel region
+                        return false;
+                    }
+                }
             }
-            if (tt == null) {
-                // target outside lca
+            if (!hasParallelParent || !(tt.getAncestor(0) instanceof Parallel)) {
+                // multiple targets MUST all be children of a shared parallel
                 return false;
             }
-            if (!regions.add(tt)) {
-                return false; // One per region
-            }
         }
-        return regions.size() == parallel.getChildren().size();
-    }
+        return true;
+   }
 }
\ No newline at end of file

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java Thu Apr  3 07:13:42 2014
@@ -48,7 +48,6 @@ import javax.xml.validation.Validator;
 
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.scxml2.PathResolver;
-import org.apache.commons.scxml2.SCXMLHelper;
 import org.apache.commons.scxml2.env.SimpleErrorHandler;
 import org.apache.commons.scxml2.env.URLResolver;
 import org.apache.commons.scxml2.model.Action;
@@ -208,6 +207,15 @@ public final class SCXMLReader {
             +" required attribute \"{1}\" value at {2}";
 
     /**
+     * Error message when the target of the URI fragment in a &lt;state&gt;'s
+     * &quot;src&quot; attribute is not a &lt;state&gt; or &lt;final&gt; in
+     * the referenced document.
+     */
+    private static final String ERR_ATTRIBUTE_NOT_BOOLEAN = "Illegal value \"{0}\""
+            + "for attribute \"{1}\" in element <{2}> at {3}."
+            +" Only the value \"true\" or \"false\" is allowed.";
+
+    /**
      * Error message when the element (state|parallel|final|history) uses an id value
      * with the reserved prefix {@link SCXML#GENERATED_TT_ID_PREFIX}.
      */
@@ -260,6 +268,7 @@ public final class SCXMLReader {
 
     //---- ATTRIBUTE NAMES ----//
     private static final String ATTR_ARRAY = "array";
+    private static final String ATTR_AUTOFORWARD = "autoforward";
     private static final String ATTR_COND = "cond";
     private static final String ATTR_DELAY = "delay";
     private static final String ATTR_EVENT = "event";
@@ -813,6 +822,8 @@ public final class SCXMLReader {
                             parallel.addTransition(readTransition(reader, configuration));
                         } else if (ELEM_STATE.equals(name)) {
                             readState(reader, configuration, scxml, parallel);
+                        } else if (ELEM_PARALLEL.equals(name)) {
+                            readParallel(reader, configuration, scxml, parallel);
                         } else if (ELEM_ONENTRY.equals(name)) {
                             readOnEntry(reader, configuration, parallel);
                         } else if (ELEM_ONEXIT.equals(name)) {
@@ -971,8 +982,12 @@ public final class SCXMLReader {
             if (source instanceof State && ts instanceof State) {
                 State s = (State) ts;
                 State include = (State) source;
-                s.setOnEntry(include.getOnEntry());
-                s.setOnExit(include.getOnExit());
+                for (OnEntry onentry : include.getOnEntries()) {
+                    s.addOnEntry(onentry);
+                }
+                for (OnExit onexit : include.getOnExits()) {
+                    s.addOnExit(onexit);
+                }
                 s.setDatamodel(include.getDatamodel());
                 List<History> histories = include.getHistory();
                 for (History h : histories) {
@@ -1117,6 +1132,7 @@ public final class SCXMLReader {
         invoke.setSrc(readAV(reader, ATTR_SRC));
         invoke.setSrcexpr(readAV(reader, ATTR_SRCEXPR));
         invoke.setType(readAV(reader, ATTR_TYPE));
+        invoke.setAutoForward(readBooleanAV(reader, ELEM_INVOKE, ATTR_AUTOFORWARD));
         invoke.setPathResolver(configuration.pathResolver);
         readNamespaces(configuration, invoke);
 
@@ -1333,8 +1349,9 @@ public final class SCXMLReader {
             throws XMLStreamException, ModelException {
 
         OnEntry onentry = new OnEntry();
+        onentry.setRaiseEvent(readBooleanAV(reader, ELEM_ONENTRY, ATTR_EVENT));
         readExecutableContext(reader, configuration, onentry, null);
-        es.setOnEntry(onentry);
+        es.addOnEntry(onentry);
     }
 
     /**
@@ -1353,8 +1370,9 @@ public final class SCXMLReader {
             throws XMLStreamException, ModelException {
 
         OnExit onexit = new OnExit();
+        onexit.setRaiseEvent(readBooleanAV(reader, ELEM_ONEXIT, ATTR_EVENT));
         readExecutableContext(reader, configuration, onexit, null);
-        es.setOnExit(onexit);
+        es.addOnExit(onexit);
     }
 
     /**
@@ -2107,6 +2125,14 @@ public final class SCXMLReader {
     }
 
     /**
+     * @param input input string to check if null or empty after trim
+     * @return null if input is null or empty after trim()
+     */
+    private static String nullIfEmpty(String input) {
+        return input == null || input.trim().length()==0 ? null : input.trim();
+    }
+
+    /**
      * Get the attribute value at the current reader location.
      *
      * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
@@ -2115,7 +2141,30 @@ public final class SCXMLReader {
      * @return The value of the attribute.
      */
     private static String readAV(final XMLStreamReader reader, final String attrLocalName) {
-        return reader.getAttributeValue(XMLNS_DEFAULT, attrLocalName);
+        return nullIfEmpty(reader.getAttributeValue(XMLNS_DEFAULT, attrLocalName));
+    }
+
+    /**
+     * Get the Boolean attribute value at the current reader location.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param elementName The name of the element for which the attribute value is needed.
+     * @param attrLocalName The attribute name whose value is needed.
+     *
+     * @return The Boolean value of the attribute.
+     * @throws ModelException When the attribute value is not empty but neither "true" or "false".
+     */
+    private static Boolean readBooleanAV(final XMLStreamReader reader, final String elementName,
+                                         final String attrLocalName)
+            throws ModelException {
+        String value = nullIfEmpty(reader.getAttributeValue(XMLNS_DEFAULT, attrLocalName));
+        Boolean result = "true".equals(value) ? Boolean.TRUE : "false".equals(value) ? Boolean.FALSE : null;
+        if (result == null && value != null) {
+            MessageFormat msgFormat = new MessageFormat(ERR_ATTRIBUTE_NOT_BOOLEAN);
+            String errMsg = msgFormat.format(new Object[] {value, attrLocalName, elementName, reader.getLocation()});
+            throw new ModelException(errMsg);
+        }
+        return result;
     }
 
     /**
@@ -2130,8 +2179,8 @@ public final class SCXMLReader {
      */
     private static String readRequiredAV(final XMLStreamReader reader, final String elementName, final String attrLocalName)
             throws ModelException {
-        String value = reader.getAttributeValue(XMLNS_DEFAULT, attrLocalName);
-        if (SCXMLHelper.isStringEmpty(value)) {
+        String value = nullIfEmpty(reader.getAttributeValue(XMLNS_DEFAULT, attrLocalName));
+        if (value == null) {
             MessageFormat msgFormat = new MessageFormat(ERR_REQUIRED_ATTRIBUTE_MISSING);
             String errMsg = msgFormat.format(new Object[] {elementName, attrLocalName, reader.getLocation()});
             throw new ModelException(errMsg);
@@ -2143,7 +2192,7 @@ public final class SCXMLReader {
                                                             final String elementName)
             throws ModelException {
         String id = readAV(reader, ATTR_ID);
-        if (SCXMLHelper.isStringEmpty(id)) {
+        if (id == null) {
             id = scxml.generateTransitionTargetId();
         }
         else if (id.startsWith(SCXML.GENERATED_TT_ID_PREFIX)) {

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLWriter.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLWriter.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLWriter.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLWriter.java Thu Apr  3 07:13:42 2014
@@ -42,7 +42,6 @@ import javax.xml.transform.stream.Stream
 import javax.xml.transform.stream.StreamSource;
 
 import org.apache.commons.logging.LogFactory;
-import org.apache.commons.scxml2.SCXMLHelper;
 import org.apache.commons.scxml2.model.Action;
 import org.apache.commons.scxml2.model.Assign;
 import org.apache.commons.scxml2.model.Cancel;
@@ -156,6 +155,7 @@ public class SCXMLWriter {
 
     //---- ATTRIBUTE NAMES ----//
     private static final String ATTR_ARRAY = "array";
+    private static final String ATTR_AUTOFORWARD = "autoforward";
     private static final String ATTR_COND = "cond";
     private static final String ATTR_DELAY = "delay";
     private static final String ATTR_EVENT = "event";
@@ -347,6 +347,59 @@ public class SCXMLWriter {
     }
 
     //---------------------- PRIVATE UTILITY METHODS ----------------------//
+
+    /**
+     * Escape XML strings for serialization.
+     * The basic algorithm is taken from Commons Lang (see oacl.Entities.java)
+     *
+     * @param str A string to be escaped
+     * @return The escaped string
+     */
+    private static String escapeXML(final String str) {
+        if (str == null) {
+            return null;
+        }
+
+        // Make the writer an arbitrary bit larger than the source string
+        int len = str.length();
+        StringWriter stringWriter = new StringWriter(len + 8);
+
+        for (int i = 0; i < len; i++) {
+            char c = str.charAt(i);
+            String entityName = null; // Look for XML 1.0 predefined entities
+            switch (c) {
+                case '"':
+                    entityName = "quot";
+                    break;
+                case '&':
+                    entityName = "amp";
+                    break;
+                case '<':
+                    entityName = "lt";
+                    break;
+                case '>':
+                    entityName = "gt";
+                    break;
+                default:
+            }
+            if (entityName == null) {
+                if (c > 0x7F) {
+                    stringWriter.write("&#");
+                    stringWriter.write(Integer.toString(c));
+                    stringWriter.write(';');
+                } else {
+                    stringWriter.write(c);
+                }
+            } else {
+                stringWriter.write('&');
+                stringWriter.write(entityName);
+                stringWriter.write(';');
+            }
+        }
+
+        return stringWriter.toString();
+    }
+
     /**
      * Write out the Commons SCXML object model using the supplied {@link Configuration}.
      * Exactly one of the stream, writer or result parameters must be provided.
@@ -488,8 +541,8 @@ public class SCXMLWriter {
                 } else {
                     writer.writeStartElement(ELEM_DATA);
                     writeAV(writer, ATTR_ID, d.getId());
-                    writeAV(writer, ATTR_SRC, SCXMLHelper.escapeXML(d.getSrc()));
-                    writeAV(writer, ATTR_EXPR, SCXMLHelper.escapeXML(d.getExpr()));
+                    writeAV(writer, ATTR_SRC, escapeXML(d.getSrc()));
+                    writeAV(writer, ATTR_EXPR, escapeXML(d.getExpr()));
                     writer.writeEndElement();
                 }
             }
@@ -527,7 +580,9 @@ public class SCXMLWriter {
         writeInitial(writer, state.getInitial());
         writeDatamodel(writer, state.getDatamodel());
         writeHistory(writer, state.getHistory());
-        writeOnEntry(writer, state.getOnEntry());
+        for (OnEntry onentry : state.getOnEntries()) {
+            writeOnEntry(writer, onentry);
+        }
 
         for (Transition t : state.getTransitionsList()) {
             writeTransition(writer, t);
@@ -547,7 +602,9 @@ public class SCXMLWriter {
             }
         }
 
-        writeOnExit(writer, state.getOnExit());
+        for (OnExit onexit : state.getOnExits()) {
+            writeOnExit(writer, onexit);
+        }
         writer.writeEndElement();
     }
 
@@ -567,7 +624,9 @@ public class SCXMLWriter {
 
         writeDatamodel(writer, parallel.getDatamodel());
         writeHistory(writer, parallel.getHistory());
-        writeOnEntry(writer, parallel.getOnEntry());
+        for (OnEntry onentry : parallel.getOnEntries()) {
+            writeOnEntry(writer, onentry);
+        }
 
         for (Transition t : parallel.getTransitionsList()) {
             writeTransition(writer, t);
@@ -587,7 +646,9 @@ public class SCXMLWriter {
             }
         }
 
-        writeOnExit(writer, parallel.getOnExit());
+        for (OnExit onexit : parallel.getOnExits()) {
+            writeOnExit(writer, onexit);
+        }
         writer.writeEndElement();
     }
 
@@ -604,8 +665,12 @@ public class SCXMLWriter {
 
         writer.writeStartElement(ELEM_FINAL);
         writeTransitionTargetId(writer, end);
-        writeOnEntry(writer, end.getOnEntry());
-        writeOnExit(writer, end.getOnExit());
+        for (OnEntry onentry : end.getOnEntries()) {
+            writeOnEntry(writer, onentry);
+        }
+        for (OnExit onexit : end.getOnExits()) {
+            writeOnExit(writer, onexit);
+        }
         writer.writeEndElement();
     }
 
@@ -669,8 +734,9 @@ public class SCXMLWriter {
     private static void writeOnEntry(final XMLStreamWriter writer, final OnEntry onentry)
             throws XMLStreamException {
 
-        if (onentry != null && onentry.getActions().size() > 0) {
+        if (onentry != null && (onentry.isRaiseEvent() || onentry.getActions().size() > 0 )) {
             writer.writeStartElement(ELEM_ONENTRY);
+            writeAV(writer, ATTR_EVENT, onentry.getRaiseEvent());
             writeExecutableContent(writer, onentry.getActions());
             writer.writeEndElement();
         }
@@ -687,8 +753,9 @@ public class SCXMLWriter {
     private static void writeOnExit(final XMLStreamWriter writer, final OnExit onexit)
             throws XMLStreamException {
 
-        if (onexit != null && onexit.getActions().size() > 0) {
+        if (onexit != null && (onexit.isRaiseEvent() || onexit.getActions().size() > 0)) {
             writer.writeStartElement(ELEM_ONEXIT);
+            writeAV(writer, ATTR_EVENT, onexit.getRaiseEvent());
             writeExecutableContent(writer, onexit.getActions());
             writer.writeEndElement();
         }
@@ -708,7 +775,7 @@ public class SCXMLWriter {
         writer.writeStartElement(ELEM_TRANSITION);
         if (transition instanceof Transition) {
             writeAV(writer, ATTR_EVENT, ((Transition)transition).getEvent());
-            writeAV(writer, ATTR_COND, SCXMLHelper.escapeXML(((Transition)transition).getCond()));
+            writeAV(writer, ATTR_COND, escapeXML(((Transition)transition).getCond()));
         }
 
         writeAV(writer, ATTR_TARGET, transition.getNext());
@@ -735,11 +802,12 @@ public class SCXMLWriter {
         writeAV(writer, ATTR_SRC, invoke.getSrc());
         writeAV(writer, ATTR_SRCEXPR, invoke.getSrcexpr());
         writeAV(writer, ATTR_TYPE, invoke.getType());
+        writeAV(writer, ATTR_AUTOFORWARD, invoke.getAutoForward());
 
         for (Param p : invoke.params()) {
             writer.writeStartElement(ELEM_PARAM);
             writeAV(writer, ATTR_NAME, p.getName());
-            writeAV(writer, ATTR_EXPR, SCXMLHelper.escapeXML(p.getExpr()));
+            writeAV(writer, ATTR_EXPR, escapeXML(p.getExpr()));
             writer.writeEndElement();
         }
         writeFinalize(writer, invoke.getFinalize());
@@ -787,7 +855,7 @@ public class SCXMLWriter {
                 writeAV(writer, ATTR_LOCATION, asn.getLocation());
                 writeAV(writer, ATTR_NAME, asn.getName());
                 writeAV(writer, ATTR_SRC, asn.getSrc());
-                writeAV(writer, ATTR_EXPR, SCXMLHelper.escapeXML(asn.getExpr()));
+                writeAV(writer, ATTR_EXPR, escapeXML(asn.getExpr()));
                 writer.writeEndElement();
             } else if (a instanceof Send) {
                 writeSend(writer, (Send) a);
@@ -802,7 +870,7 @@ public class SCXMLWriter {
                 Log lg = (Log) a;
                 writer.writeStartElement(XMLNS_SCXML, ELEM_LOG);
                 writeAV(writer, ATTR_LABEL, lg.getLabel());
-                writeAV(writer, ATTR_EXPR, SCXMLHelper.escapeXML(lg.getExpr()));
+                writeAV(writer, ATTR_EXPR, escapeXML(lg.getExpr()));
                 writer.writeEndElement();
             } else if (a instanceof Raise) {
                 Raise e = (Raise) a;
@@ -821,13 +889,13 @@ public class SCXMLWriter {
             } else if (a instanceof ElseIf) {
                 ElseIf eif = (ElseIf) a;
                 writer.writeStartElement(XMLNS_SCXML, ELEM_ELSEIF);
-                writeAV(writer, ATTR_COND, SCXMLHelper.escapeXML(eif.getCond()));
+                writeAV(writer, ATTR_COND, escapeXML(eif.getCond()));
                 writer.writeEndElement();
             } else if (a instanceof Var) {
                 Var v = (Var) a;
                 writer.writeStartElement(XMLNS_COMMONS_SCXML, ELEM_VAR);
                 writeAV(writer, ATTR_NAME, v.getName());
-                writeAV(writer, ATTR_EXPR, SCXMLHelper.escapeXML(v.getExpr()));
+                writeAV(writer, ATTR_EXPR, escapeXML(v.getExpr()));
                 writer.writeEndElement();
             } else {
                 writer.writeComment("Custom action with class name '" + a.getClass().getName() + "' not serialized");
@@ -872,7 +940,7 @@ public class SCXMLWriter {
             throws XMLStreamException {
 
         writer.writeStartElement(ELEM_IF);
-        writeAV(writer, ATTR_COND, SCXMLHelper.escapeXML(iff.getCond()));
+        writeAV(writer, ATTR_COND, escapeXML(iff.getCond()));
         writeExecutableContent(writer, iff.getActions());
         writer.writeEndElement();
     }
@@ -891,7 +959,7 @@ public class SCXMLWriter {
         writer.writeStartElement(ELEM_FOREACH);
         writeAV(writer, ATTR_ITEM, foreach.getItem());
         writeAV(writer, ATTR_INDEX, foreach.getIndex());
-        writeAV(writer, ATTR_ARRAY, SCXMLHelper.escapeXML(foreach.getArray()));
+        writeAV(writer, ATTR_ARRAY, escapeXML(foreach.getArray()));
         writeExecutableContent(writer, foreach.getActions());
         writer.writeEndElement();
     }
@@ -960,6 +1028,22 @@ public class SCXMLWriter {
     }
 
     /**
+     * Write out this attribute, if the value is not <code>null</code>.
+     *
+     * @param writer The {@link XMLStreamWriter} in use for the serialization.
+     * @param localName The local name of the attribute.
+     * @param value The attribute value.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamWriter}.
+     */
+    private static void writeAV(final XMLStreamWriter writer, final String localName, final Boolean value)
+            throws XMLStreamException {
+        if (value != null) {
+            writer.writeAttribute(localName, value.toString());
+        }
+    }
+
+    /**
      * Write the serialized SCXML document while making attempts to make the serialization human readable. This
      * includes using new-lines and indentation as appropriate, where possible. Exactly one of the stream, writer
      * or result parameters must be provided.

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Action.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Action.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Action.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Action.java Thu Apr  3 07:13:42 2014
@@ -20,6 +20,7 @@ import java.io.Serializable;
 import java.util.Map;
 
 import org.apache.commons.scxml2.ActionExecutionContext;
+import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.SCXMLExpressionException;
 
 /**
@@ -42,12 +43,6 @@ public abstract class Action implements 
     private Map<String, String> namespaces;
 
     /**
-     * Current document namespaces are saved under this key in the parent
-     * state's context.
-     */
-    private static final String NAMESPACES_KEY = "_ALL_NAMESPACES";
-
-    /**
      * Constructor.
      */
     public Action() {
@@ -137,7 +132,7 @@ public abstract class Action implements 
      * @return The namespaces key
      */
     protected static String getNamespacesKey() {
-        return NAMESPACES_KEY;
+        return Context.NAMESPACES_KEY;
     }
 
 }

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Assign.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Assign.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Assign.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Assign.java Thu Apr  3 07:13:42 2014
@@ -28,11 +28,9 @@ import org.apache.commons.scxml2.Context
 import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.PathResolver;
 import org.apache.commons.scxml2.SCXMLExpressionException;
-import org.apache.commons.scxml2.SCXMLHelper;
 import org.apache.commons.scxml2.TriggerEvent;
 import org.apache.commons.scxml2.semantics.ErrorConstants;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
+import org.w3c.dom.*;
 import org.xml.sax.SAXException;
 
 /**
@@ -181,7 +179,7 @@ public class Assign extends Action imple
         Evaluator eval = exctx.getEvaluator();
         ctx.setLocal(getNamespacesKey(), getNamespaces());
         // "location" gets preference over "name"
-        if (!SCXMLHelper.isStringEmpty(location)) {
+        if (location != null) {
             Node oldNode = eval.evalLocation(ctx, location);
             if (oldNode != null) {
                 //// rvalue may be ...
@@ -213,7 +211,7 @@ public class Assign extends Action imple
                 } catch (SCXMLExpressionException see) {
                     // or something else, stuff toString() into lvalue
                     Object valueObject = eval.eval(ctx, expr);
-                    SCXMLHelper.setNodeValue(oldNode, valueObject.toString());
+                    setNodeValue(oldNode, valueObject.toString());
                 }
                 if (exctx.getAppLog().isDebugEnabled()) {
                     exctx.getAppLog().debug("<assign>: data node '" + oldNode.getNodeName()
@@ -253,6 +251,43 @@ public class Assign extends Action imple
     }
 
     /**
+     * Set node value, depending on its type, from a String.
+     *
+     * @param node A Node whose value is to be set
+     * @param value The new value
+     */
+    private void setNodeValue(final Node node, final String value) {
+        switch(node.getNodeType()) {
+            case Node.ATTRIBUTE_NODE:
+                node.setNodeValue(value);
+                break;
+            case Node.ELEMENT_NODE:
+                //remove all text children
+                if (node.hasChildNodes()) {
+                    Node child = node.getFirstChild();
+                    while (child != null) {
+                        if (child.getNodeType() == Node.TEXT_NODE) {
+                            node.removeChild(child);
+                        }
+                        child = child.getNextSibling();
+                    }
+                }
+                //create a new text node and append
+                Text txt = node.getOwnerDocument().createTextNode(value);
+                node.appendChild(txt);
+                break;
+            case Node.TEXT_NODE:
+            case Node.CDATA_SECTION_NODE:
+                ((CharacterData) node).setData(value);
+                break;
+            default:
+                String err = "Trying to set value of a strange Node type: "
+                        + node.getNodeType();
+                throw new IllegalArgumentException(err);
+        }
+    }
+
+    /**
      * Get the {@link Node} the "src" attribute points to.
      *
      * @return The node the "src" attribute points to.

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/CustomAction.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/CustomAction.java?rev=1584272&r1=1584271&r2=1584272&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/CustomAction.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/CustomAction.java Thu Apr  3 07:13:42 2014
@@ -17,7 +17,6 @@
 package org.apache.commons.scxml2.model;
 
 import org.apache.commons.logging.LogFactory;
-import org.apache.commons.scxml2.SCXMLHelper;
 
 import org.apache.commons.logging.Log;
 
@@ -92,7 +91,7 @@ public class CustomAction {
     public CustomAction(final String namespaceURI, final String localName,
             final Class<? extends Action> actionClass) {
         Log log = LogFactory.getLog(CustomAction.class);
-        if (SCXMLHelper.isStringEmpty(namespaceURI)) {
+        if (namespaceURI == null || namespaceURI.trim().length() == 0) {
             log.error(ERR_NO_NAMESPACE);
             throw new IllegalArgumentException(ERR_NO_NAMESPACE);
         }
@@ -100,12 +99,11 @@ public class CustomAction {
             log.error(ERR_RESERVED_NAMESPACE);
             throw new IllegalArgumentException(ERR_RESERVED_NAMESPACE);
         }
-        if (SCXMLHelper.isStringEmpty(localName)) {
+        if (localName == null || localName.trim().length() == 0) {
             log.error(ERR_NO_LOCAL_NAME);
             throw new IllegalArgumentException(ERR_NO_LOCAL_NAME);
         }
-        if (actionClass == null
-                || !Action.class.isAssignableFrom(actionClass)) {
+        if (actionClass == null || !Action.class.isAssignableFrom(actionClass)) {
             log.error(ERR_NOT_AN_ACTION);
             throw new IllegalArgumentException(ERR_NOT_AN_ACTION);
         }