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 2017/12/10 03:04:20 UTC

[1/2] commons-scxml git commit: SCXML-259 Complete implementation and handling of system variables _event and _ioprocessors

Repository: commons-scxml
Updated Branches:
  refs/heads/master a61c3c544 -> b4a10313c


http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/TriggerEventTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/TriggerEventTest.java b/src/test/java/org/apache/commons/scxml2/TriggerEventTest.java
index 0c31a34..24ba809 100644
--- a/src/test/java/org/apache/commons/scxml2/TriggerEventTest.java
+++ b/src/test/java/org/apache/commons/scxml2/TriggerEventTest.java
@@ -39,17 +39,17 @@ public class TriggerEventTest {
      */
     @Before
     public void setUp() {
-        payloadData = new HashMap<String, String>();
+        payloadData = new HashMap<>();
         payloadData.put("property1", "value1");
         payload1 = payloadData;
         payload2 = new Object();
-        te1 = new TriggerEvent("name1", TriggerEvent.CHANGE_EVENT, payload1);
-        te2 = new TriggerEvent("name1", TriggerEvent.CHANGE_EVENT, payload1);
-        te3 = new TriggerEvent("name2", TriggerEvent.CALL_EVENT, payload2);
-        te4 = new TriggerEvent("name2", TriggerEvent.CALL_EVENT, payload2);
-        te5 = new TriggerEvent("name3", TriggerEvent.SIGNAL_EVENT);
-        te6 = new TriggerEvent("name3", TriggerEvent.SIGNAL_EVENT);
-        te7 = new TriggerEvent("name3", TriggerEvent.TIME_EVENT);
+        te1 = new EventBuilder("name1", TriggerEvent.CHANGE_EVENT).data(payload1).build();
+        te2 = new EventBuilder("name1", TriggerEvent.CHANGE_EVENT).data(payload1).build();
+        te3 = new EventBuilder("name2", TriggerEvent.CALL_EVENT).data(payload2).build();
+        te4 = new EventBuilder("name2", TriggerEvent.CALL_EVENT).data(payload2).build();
+        te5 = new EventBuilder("name3", TriggerEvent.SIGNAL_EVENT).build();
+        te6 = new EventBuilder("name3", TriggerEvent.SIGNAL_EVENT).build();
+        te7 = new EventBuilder("name3", TriggerEvent.TIME_EVENT).build();
     }
 
     /**
@@ -70,7 +70,7 @@ public class TriggerEventTest {
     public void testTriggerEventGetters() {
         Assert.assertEquals("name1", te1.getName());
         Assert.assertEquals(2, te2.getType());
-        Assert.assertNull(te7.getPayload());
+        Assert.assertNull(te7.getData());
     }
 
     @Test
@@ -84,16 +84,16 @@ public class TriggerEventTest {
 
     @Test
     public void testTriggerEventToString() {
-        Assert.assertEquals("TriggerEvent{name=name3,type=4}", te7.toString());
-        Assert.assertEquals("TriggerEvent{name=name1,type=2,payload="
+        Assert.assertEquals("TriggerEvent{name=name3, type=4}", te7.toString());
+        Assert.assertEquals("TriggerEvent{name=name1, type=2, data="
             + "{property1=value1}}", te2.toString());
     }
 
     @Test
     public void testTriggerEventHashCode() {
-        Assert.assertEquals("TriggerEvent{name=name3,type=4}".hashCode(),
+        Assert.assertEquals("TriggerEvent{name=name3, type=4}".hashCode(),
             te7.hashCode());
-        Assert.assertEquals("TriggerEvent{name=name3,type=3}".hashCode(),
+        Assert.assertEquals("TriggerEvent{name=name3, type=3}".hashCode(),
             te5.hashCode());
     }
 }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/env/javascript/JSExampleTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/javascript/JSExampleTest.java b/src/test/java/org/apache/commons/scxml2/env/javascript/JSExampleTest.java
index 82799d5..bf33d61 100644
--- a/src/test/java/org/apache/commons/scxml2/env/javascript/JSExampleTest.java
+++ b/src/test/java/org/apache/commons/scxml2/env/javascript/JSExampleTest.java
@@ -25,6 +25,7 @@ import org.apache.commons.scxml2.SCXMLExecutor;
 import org.apache.commons.scxml2.SCXMLExpressionException;
 import org.apache.commons.scxml2.SCXMLTestHelper;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.EventBuilder;
 import org.apache.commons.scxml2.model.Action;
 import org.apache.commons.scxml2.ActionExecutionContext;
 import org.apache.commons.scxml2.model.CustomAction;
@@ -63,7 +64,8 @@ public class JSExampleTest {
 
         @Override
         public void execute(ActionExecutionContext exctx) throws ModelException, SCXMLExpressionException {
-            exctx.getInternalIOProcessor().addEvent(new TriggerEvent("ok",TriggerEvent.SIGNAL_EVENT,"and its ok with me to"));
+            exctx.getInternalIOProcessor()
+                    .addEvent(new EventBuilder("ok",TriggerEvent.SIGNAL_EVENT).data("and its ok with me to").build());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/invoke/InvokeParamNameTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/invoke/InvokeParamNameTest.java b/src/test/java/org/apache/commons/scxml2/invoke/InvokeParamNameTest.java
index a3809d2..1a198c1 100644
--- a/src/test/java/org/apache/commons/scxml2/invoke/InvokeParamNameTest.java
+++ b/src/test/java/org/apache/commons/scxml2/invoke/InvokeParamNameTest.java
@@ -22,6 +22,7 @@ import org.apache.commons.scxml2.SCXMLExecutor;
 import org.apache.commons.scxml2.SCXMLIOProcessor;
 import org.apache.commons.scxml2.SCXMLTestHelper;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.EventBuilder;
 import org.apache.commons.scxml2.model.ModelException;
 import org.junit.After;
 import org.junit.Assert;
@@ -51,8 +52,7 @@ public class InvokeParamNameTest {
     private void trigger() throws ModelException {
         lastParams = null;
         lastSource = null;
-        exec.triggerEvent(new TriggerEvent("test.trigger",
-            TriggerEvent.SIGNAL_EVENT)); 
+        exec.triggerEvent(new EventBuilder("test.trigger", TriggerEvent.SIGNAL_EVENT).build());
     }
     
     // Tests "param" element with "name" and "expr" attribute    

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/model/CancelTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/CancelTest.java b/src/test/java/org/apache/commons/scxml2/model/CancelTest.java
index 27409d5..0340c01 100644
--- a/src/test/java/org/apache/commons/scxml2/model/CancelTest.java
+++ b/src/test/java/org/apache/commons/scxml2/model/CancelTest.java
@@ -19,6 +19,7 @@ package org.apache.commons.scxml2.model;
 import org.apache.commons.scxml2.SCXMLExecutor;
 import org.apache.commons.scxml2.SCXMLTestHelper;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.EventBuilder;
 import org.apache.commons.scxml2.env.SimpleDispatcher;
 import org.junit.Test;
 
@@ -29,7 +30,7 @@ public class CancelTest {
         final SCXML scxml = SCXMLTestHelper.parse("org/apache/commons/scxml2/model/cancel-test-01.xml");
         final SCXMLExecutor exec = SCXMLTestHelper.getExecutor(scxml, null, new SimpleDispatcher());
         exec.go();
-        TriggerEvent te = new TriggerEvent("event.foo", TriggerEvent.SIGNAL_EVENT);
+        TriggerEvent te = new EventBuilder("event.foo", TriggerEvent.SIGNAL_EVENT).build();
         SCXMLTestHelper.fireEvent(exec, te);
         Thread.sleep(3000);
         exec.triggerEvents();
@@ -41,7 +42,7 @@ public class CancelTest {
         final SCXML scxml = SCXMLTestHelper.parse("org/apache/commons/scxml2/model/cancel-test-02.xml");
         final SCXMLExecutor exec = SCXMLTestHelper.getExecutor(scxml, null, new SimpleDispatcher());
         exec.go();
-        TriggerEvent te = new TriggerEvent("event.foo", TriggerEvent.SIGNAL_EVENT);
+        TriggerEvent te = new EventBuilder("event.foo", TriggerEvent.SIGNAL_EVENT).build();
         SCXMLTestHelper.fireEvent(exec, te);
         Thread.sleep(3000);
         exec.triggerEvents();

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/model/DatamodelTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/DatamodelTest.java b/src/test/java/org/apache/commons/scxml2/model/DatamodelTest.java
index 5d8b8f1..afb391f 100644
--- a/src/test/java/org/apache/commons/scxml2/model/DatamodelTest.java
+++ b/src/test/java/org/apache/commons/scxml2/model/DatamodelTest.java
@@ -16,13 +16,12 @@
  */
 package org.apache.commons.scxml2.model;
 
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Set;
 
 import org.apache.commons.scxml2.SCXMLExecutor;
 import org.apache.commons.scxml2.SCXMLTestHelper;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.EventBuilder;
 import org.junit.Assert;
 import org.junit.Test;
 /**
@@ -127,8 +126,7 @@ public class DatamodelTest {
     }
 
     private Set<EnterableState> fireEvent(String name, SCXMLExecutor exec) throws Exception {
-        TriggerEvent[] evts = {new TriggerEvent(name,
-                TriggerEvent.SIGNAL_EVENT, null)};
+        TriggerEvent[] evts = {new EventBuilder(name, TriggerEvent.SIGNAL_EVENT).build()};
         exec.triggerEvents(evts);
         return exec.getStatus().getStates();
     }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/model/Hello.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/Hello.java b/src/test/java/org/apache/commons/scxml2/model/Hello.java
index 2b17d4d..c01cbfc 100644
--- a/src/test/java/org/apache/commons/scxml2/model/Hello.java
+++ b/src/test/java/org/apache/commons/scxml2/model/Hello.java
@@ -19,6 +19,7 @@ package org.apache.commons.scxml2.model;
 import org.apache.commons.scxml2.ActionExecutionContext;
 import org.apache.commons.scxml2.SCXMLExpressionException;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.EventBuilder;
 
 /**
  * Our custom &quot;hello world&quot; action.
@@ -61,8 +62,7 @@ public class Hello extends Action {
             exctx.getAppLog().info("Hello " + name);
         }
         // For derived events payload testing
-        TriggerEvent event =
-            new TriggerEvent("helloevent", TriggerEvent.SIGNAL_EVENT, name);
+        TriggerEvent event = new EventBuilder("helloevent", TriggerEvent.SIGNAL_EVENT).data(name).build();
         exctx.getInternalIOProcessor().addEvent(event);
         callbacks++;
     }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/model/SendTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/SendTest.java b/src/test/java/org/apache/commons/scxml2/model/SendTest.java
index e5ca7a6..600df86 100644
--- a/src/test/java/org/apache/commons/scxml2/model/SendTest.java
+++ b/src/test/java/org/apache/commons/scxml2/model/SendTest.java
@@ -26,6 +26,7 @@ import org.apache.commons.scxml2.SCXMLExpressionException;
 import org.apache.commons.scxml2.SCXMLIOProcessor;
 import org.apache.commons.scxml2.SCXMLTestHelper;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.EventBuilder;
 import org.apache.commons.scxml2.env.SimpleDispatcher;
 import org.junit.Assert;
 import org.junit.Test;
@@ -33,7 +34,6 @@ import org.junit.Test;
 public class SendTest {
 
     @Test
-    @SuppressWarnings("unchecked")
     public void testNamelistOrderPreserved() throws Exception {
         final List<Object> payloads = new ArrayList<Object>();
         final SCXML scxml = SCXMLTestHelper.parse("org/apache/commons/scxml2/model/send-test-01.xml");
@@ -46,7 +46,7 @@ public class SendTest {
             }
         });
         exec.go();
-        TriggerEvent te = new TriggerEvent("event.foo", TriggerEvent.SIGNAL_EVENT, new Integer(3));
+        TriggerEvent te = new EventBuilder("event.foo", TriggerEvent.SIGNAL_EVENT).data(new Integer(3)).build();
         SCXMLTestHelper.fireEvent(exec, te);
 
         Assert.assertFalse("Payloads empty.", payloads.isEmpty());

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/model/StatelessModelTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/StatelessModelTest.java b/src/test/java/org/apache/commons/scxml2/model/StatelessModelTest.java
index e506481..3f6b529 100644
--- a/src/test/java/org/apache/commons/scxml2/model/StatelessModelTest.java
+++ b/src/test/java/org/apache/commons/scxml2/model/StatelessModelTest.java
@@ -22,6 +22,7 @@ import java.util.Set;
 import org.apache.commons.scxml2.SCXMLExecutor;
 import org.apache.commons.scxml2.SCXMLTestHelper;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.EventBuilder;
 import org.junit.Assert;
 import org.junit.Test;
 /**
@@ -183,7 +184,7 @@ public class StatelessModelTest {
     }
 
     private Set<EnterableState> fireEvent(String name, SCXMLExecutor exec) throws Exception {
-        TriggerEvent[] evts = {new TriggerEvent(name, TriggerEvent.SIGNAL_EVENT, null)};
+        TriggerEvent[] evts = {new EventBuilder(name, TriggerEvent.SIGNAL_EVENT).build()};
         exec.triggerEvents(evts);
         return exec.getStatus().getStates();
     }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/model/actions-initial-test.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/actions-initial-test.xml b/src/test/java/org/apache/commons/scxml2/model/actions-initial-test.xml
index 777925f..21ce85e 100644
--- a/src/test/java/org/apache/commons/scxml2/model/actions-initial-test.xml
+++ b/src/test/java/org/apache/commons/scxml2/model/actions-initial-test.xml
@@ -36,7 +36,7 @@
         </if>
         <cs:var name="drink" expr="'water'" />
         <cs:var name="eat" expr="'flies'" />
-        <send id="send12345" target="freddy" type="frog"
+        <send id="send12345"
          event="croak" namelist="drink eat" hints="'h2o bzz'"
          delayexpr="1000+500" />
         <cancel sendId="send12345"/>

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/model/actions-parallel-test.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/actions-parallel-test.xml b/src/test/java/org/apache/commons/scxml2/model/actions-parallel-test.xml
index de996f6..51706e4 100644
--- a/src/test/java/org/apache/commons/scxml2/model/actions-parallel-test.xml
+++ b/src/test/java/org/apache/commons/scxml2/model/actions-parallel-test.xml
@@ -35,7 +35,7 @@
       </if>
       <cs:var name="drink" expr="'water'" />
       <cs:var name="eat" expr="'flies'" />
-      <send id="send12345" target="freddy" type="frog"
+      <send id="send12345"
        event="croak" namelist="drink eat" hints="'h2o bzz'"
        delayexpr="1000+500" />
       <cancel sendId="send12345"/>

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/model/actions-state-test.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/actions-state-test.xml b/src/test/java/org/apache/commons/scxml2/model/actions-state-test.xml
index dd5036b..89bc038 100644
--- a/src/test/java/org/apache/commons/scxml2/model/actions-state-test.xml
+++ b/src/test/java/org/apache/commons/scxml2/model/actions-state-test.xml
@@ -35,7 +35,7 @@
       </if>
       <cs:var name="drink" expr="'water'" />
       <cs:var name="eat" expr="'flies'" />
-      <send id="send12345" target="freddy" type="frog"
+      <send id="send12345"
        event="croak" namelist="drink eat" hints="'h2o bzz'"
        delayexpr="1000+500" />
       <cancel sendId="send12345"/>

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/w3c/tests.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/w3c/tests.xml b/src/test/java/org/apache/commons/scxml2/w3c/tests.xml
index 035e998..ef02fd5 100644
--- a/src/test/java/org/apache/commons/scxml2/w3c/tests.xml
+++ b/src/test/java/org/apache/commons/scxml2/w3c/tests.xml
@@ -50,7 +50,7 @@
   <test id="156" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="525" mandatory="true"                    manual="false" jexl="true"  ecma="false"/>
   <test id="158" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
-  <test id="159" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
+  <test id="159" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="276" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="277" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="279" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
@@ -72,7 +72,7 @@
   <test id="302" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="303" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="304" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
-  <test id="307" mandatory="true"                    manual="true"  jexl="false" ecma="false" finalState="final"/>
+  <test id="307" mandatory="true"                    manual="true"  jexl="true"  ecma="false" finalState="final"/>
   <test id="309" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="310" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="311" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
@@ -90,8 +90,8 @@
   <test id="326" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="329" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="330" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
-  <test id="331" mandatory="true"                    manual="false" jexl="false" ecma="true" implemented="false"/>
-  <test id="332" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
+  <test id="331" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
+  <test id="332" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="333" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="335" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="336" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
@@ -112,17 +112,17 @@
   <test id="186" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="187" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
   <test id="194" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
-  <test id="198" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
+  <test id="198" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="199" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="200" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="205" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
-  <test id="521" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
+  <test id="521" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="553" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="207" mandatory="true"                    manual="false" jexl="false" ecma="false" implemented="false"/>
   <test id="208" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="210" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="215" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
-  <test id="216" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
+  <test id="216" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="220" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
   <test id="223" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
   <test id="224" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
@@ -167,7 +167,7 @@
   <test id="578" mandatory="false" profile="ecma"    manual="false"              ecma="false"/>
   <test id="561" mandatory="false" profile="ecma"    manual="false"              ecma="false"/>
   <test id="562" mandatory="false" profile="ecma"    manual="false"              ecma="false"/>
-  <test id="569" mandatory="false" profile="ecma"    manual="false"              ecma="false"/>
+  <test id="569" mandatory="false" profile="ecma"    manual="false"              ecma="true"/>
   <test id="457" mandatory="false" profile="ecma"    manual="false"              ecma="false"/>
   <test id="459" mandatory="false" profile="ecma"    manual="false"              ecma="true"/>
   <test id="460" mandatory="false" profile="ecma"    manual="false"              ecma="true"/>
@@ -180,13 +180,13 @@
   <test id="348" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="349" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="350" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
-  <test id="351" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
-  <test id="352" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
+  <test id="351" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
+  <test id="352" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="354" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
   <test id="495" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
-  <test id="496" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
-  <test id="500" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
-  <test id="501" mandatory="true"                    manual="false" jexl="false" ecma="false"/>
+  <test id="496" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
+  <test id="500" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
+  <test id="501" mandatory="true"                    manual="false" jexl="true"  ecma="true"/>
 
   <test id="201" mandatory="false" profile="http io" manual="false" implemented="false"/>
   <test id="509" mandatory="false" profile="http io" manual="false" implemented="false"/>


[2/2] commons-scxml git commit: SCXML-259 Complete implementation and handling of system variables _event and _ioprocessors

Posted by at...@apache.org.
SCXML-259 Complete implementation and handling of system variables _event and _ioprocessors


Project: http://git-wip-us.apache.org/repos/asf/commons-scxml/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-scxml/commit/b4a10313
Tree: http://git-wip-us.apache.org/repos/asf/commons-scxml/tree/b4a10313
Diff: http://git-wip-us.apache.org/repos/asf/commons-scxml/diff/b4a10313

Branch: refs/heads/master
Commit: b4a10313c5c7017aa0afadca7ce6bce93278a1e2
Parents: a61c3c5
Author: Ate Douma <at...@apache.org>
Authored: Sun Dec 10 04:04:13 2017 +0100
Committer: Ate Douma <at...@apache.org>
Committed: Sun Dec 10 04:04:13 2017 +0100

----------------------------------------------------------------------
 .../org/apache/commons/scxml2/EventBuilder.java |  90 ++++++++++++
 .../apache/commons/scxml2/EventDispatcher.java  |  12 ++
 .../scxml2/ExternalSCXMLIOProcessor.java        |  42 ++++++
 .../commons/scxml2/ParentSCXMLIOProcessor.java  |  47 ++++++
 .../org/apache/commons/scxml2/SCInstance.java   |   2 +-
 .../commons/scxml2/SCXMLExecutionContext.java   |  28 ++--
 .../apache/commons/scxml2/SCXMLExecutor.java    |  17 ++-
 .../apache/commons/scxml2/SCXMLIOProcessor.java |   2 +-
 .../org/apache/commons/scxml2/TriggerEvent.java | 119 ++++++++-------
 .../scxml2/env/AbstractStateMachine.java        |   4 +-
 .../commons/scxml2/env/SimpleDispatcher.java    |  99 +++++++------
 .../scxml2/env/javascript/init_global.js        |   4 +-
 .../commons/scxml2/invoke/AsyncTrigger.java     |  59 --------
 .../scxml2/invoke/SimpleSCXMLInvoker.java       |  35 ++---
 .../org/apache/commons/scxml2/model/Action.java |   4 +-
 .../scxml2/model/ActionExecutionError.java      |  57 ++++++++
 .../apache/commons/scxml2/model/Foreach.java    |   4 +-
 .../org/apache/commons/scxml2/model/If.java     |   3 +-
 .../org/apache/commons/scxml2/model/Invoke.java |  27 ++--
 .../org/apache/commons/scxml2/model/Raise.java  |   3 +-
 .../org/apache/commons/scxml2/model/Send.java   | 146 ++++++++++---------
 .../commons/scxml2/model/TransitionalState.java |   2 +-
 .../org/apache/commons/scxml2/model/Var.java    |   3 +-
 .../scxml2/semantics/SCXMLSemanticsImpl.java    |  68 +++++----
 .../commons/scxml2/system/EventVariable.java    |  20 +++
 .../commons/scxml2/test/StandaloneUtils.java    |   7 +-
 .../apache/commons/scxml2/EventDataTest.java    |  20 +--
 .../apache/commons/scxml2/SCXMLTestHelper.java  |  16 +-
 .../apache/commons/scxml2/TriggerEventTest.java |  26 ++--
 .../scxml2/env/javascript/JSExampleTest.java    |   4 +-
 .../scxml2/invoke/InvokeParamNameTest.java      |   4 +-
 .../apache/commons/scxml2/model/CancelTest.java |   5 +-
 .../commons/scxml2/model/DatamodelTest.java     |   6 +-
 .../org/apache/commons/scxml2/model/Hello.java  |   4 +-
 .../apache/commons/scxml2/model/SendTest.java   |   4 +-
 .../scxml2/model/StatelessModelTest.java        |   3 +-
 .../scxml2/model/actions-initial-test.xml       |   2 +-
 .../scxml2/model/actions-parallel-test.xml      |   2 +-
 .../commons/scxml2/model/actions-state-test.xml |   2 +-
 .../org/apache/commons/scxml2/w3c/tests.xml     |  26 ++--
 40 files changed, 640 insertions(+), 388 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/EventBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/EventBuilder.java b/src/main/java/org/apache/commons/scxml2/EventBuilder.java
new file mode 100644
index 0000000..d43ec49
--- /dev/null
+++ b/src/main/java/org/apache/commons/scxml2/EventBuilder.java
@@ -0,0 +1,90 @@
+/*
+ * 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;
+
+public class EventBuilder {
+
+    private final String name;
+    private final int type;
+    private String sendId;
+    private String origin;
+    private String originType;
+    private String invokeId;
+    private Object data;
+
+    public EventBuilder(final String name, final int type) {
+        this.name = name;
+        this.type = type;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getType() {
+        return type;
+    }
+
+    public String getSendId() {
+        return sendId;
+    }
+
+    public EventBuilder sendId(final String sendId) {
+        this.sendId = sendId;
+        return this;
+    }
+
+    public String getOrigin() {
+        return origin;
+    }
+
+    public EventBuilder origin(final String origin) {
+        this.origin = origin;
+        return this;
+    }
+
+    public String getOriginType() {
+        return originType;
+    }
+
+    public EventBuilder originType(final String originType) {
+        this.originType = originType;
+        return this;
+    }
+
+    public String getInvokeId() {
+        return invokeId;
+    }
+
+    public EventBuilder invokeId(final String invokeId) {
+        this.invokeId = invokeId;
+        return this;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public EventBuilder data(final Object data) {
+        this.data = data;
+        return this;
+    }
+
+    public TriggerEvent build() {
+        return new TriggerEvent(name, type, sendId, origin, originType, invokeId, data);
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/EventDispatcher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/EventDispatcher.java b/src/main/java/org/apache/commons/scxml2/EventDispatcher.java
index 6f0a8f1..b57b81f 100644
--- a/src/main/java/org/apache/commons/scxml2/EventDispatcher.java
+++ b/src/main/java/org/apache/commons/scxml2/EventDispatcher.java
@@ -18,6 +18,8 @@ package org.apache.commons.scxml2;
 
 import java.util.Map;
 
+import org.apache.commons.scxml2.invoke.Invoker;
+
 /**
  * The event controller interface used to send messages containing
  * events or other information directly to another SCXML Interpreter,
@@ -28,6 +30,16 @@ import java.util.Map;
 public interface EventDispatcher {
 
     /**
+     * A EventDispatcher keeps track of outstanding (pending) events to be send on behalf of the statemachine
+     * it is 'attached' to.
+     * To support easy setup and configuration of an invoked child statemachine (see {@link Invoker})
+     * the EventDispatcher provides this newInstnace method to allow creating a new instance without sharing its
+     * internal state..
+     * @return a new EventDispatcher instance for usage in an invoked child statemachine.
+     */
+    EventDispatcher newInstance();
+
+    /**
      * Cancel the specified send message.
      *
      * @param sendId The ID of the send message to cancel

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/ExternalSCXMLIOProcessor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/ExternalSCXMLIOProcessor.java b/src/main/java/org/apache/commons/scxml2/ExternalSCXMLIOProcessor.java
new file mode 100644
index 0000000..be14a3d
--- /dev/null
+++ b/src/main/java/org/apache/commons/scxml2/ExternalSCXMLIOProcessor.java
@@ -0,0 +1,42 @@
+/*
+ * 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 ExternalSCXMLIOProcessor is registered in the _ioprocessors system variable under the
+ * {@link #DEFAULT_EVENT_PROCESSOR} key <b>and</b> maintains a {@link #getLocation() location} field
+ * <pre>
+ *     <em>whose value holds an address that external entities can use to communicate with this SCXML session using the SCXML Event I/O Processor.</em></pre>
+ * @see <a href="https://www.w3.org/TR/scxml/#SCXMLEventProcessor">SCXML specification C.1.1 _ioprocessors Value</a>
+ */
+public class ExternalSCXMLIOProcessor implements SCXMLIOProcessor {
+
+    private SCXMLIOProcessor processor;
+
+    public ExternalSCXMLIOProcessor(final SCXMLIOProcessor processor) {
+        this.processor = processor;
+    }
+
+    @Override
+    public void addEvent(final TriggerEvent event) {
+        processor.addEvent(event);
+    }
+
+    public String getLocation() {
+        return SCXML_EVENT_PROCESSOR;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/ParentSCXMLIOProcessor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/ParentSCXMLIOProcessor.java b/src/main/java/org/apache/commons/scxml2/ParentSCXMLIOProcessor.java
new file mode 100644
index 0000000..f3cc08c
--- /dev/null
+++ b/src/main/java/org/apache/commons/scxml2/ParentSCXMLIOProcessor.java
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+public class ParentSCXMLIOProcessor implements SCXMLIOProcessor {
+
+    private SCXMLIOProcessor processor;
+    private final String invokeId;
+
+    public ParentSCXMLIOProcessor(final SCXMLIOProcessor processor, final String invokeId) {
+        this.processor = processor;
+        this.invokeId = invokeId;
+    }
+
+    @Override
+    public synchronized void addEvent(final TriggerEvent event) {
+        if (processor != null) {
+            processor.addEvent(event);
+        }
+    }
+
+    public String getInvokeId() {
+        return invokeId;
+    }
+
+    public synchronized void close() {
+        processor = null;
+    }
+
+    public synchronized boolean isClosed() {
+        return processor == null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/SCInstance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/SCInstance.java b/src/main/java/org/apache/commons/scxml2/SCInstance.java
index 299df9c..5fe715f 100644
--- a/src/main/java/org/apache/commons/scxml2/SCInstance.java
+++ b/src/main/java/org/apache/commons/scxml2/SCInstance.java
@@ -348,7 +348,7 @@ public class SCInstance implements Serializable {
                     setValue = true;
                 } catch (SCXMLExpressionException see) {
                     if (internalIOProcessor != null) {
-                        internalIOProcessor.addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
+                        internalIOProcessor.addEvent(new EventBuilder(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT).build());
                     }
                     errorReporter.onError(ErrorConstants.EXPRESSION_ERROR, see.getMessage(), datum);
                 } finally {

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/SCXMLExecutionContext.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/SCXMLExecutionContext.java b/src/main/java/org/apache/commons/scxml2/SCXMLExecutionContext.java
index 545feac..ec4dcea 100644
--- a/src/main/java/org/apache/commons/scxml2/SCXMLExecutionContext.java
+++ b/src/main/java/org/apache/commons/scxml2/SCXMLExecutionContext.java
@@ -149,11 +149,11 @@ public class SCXMLExecutionContext implements SCXMLIOProcessor {
         this.scInstance = new SCInstance(this, this.evaluator, this.errorReporter);
         this.actionExecutionContext = new ActionExecutionContext(this);
 
-        ioProcessors.put(SCXMLIOProcessor.DEFAULT_EVENT_PROCESSOR, getExternalIOProcessor());
-        ioProcessors.put(SCXMLIOProcessor.SCXML_EVENT_PROCESSOR, getExternalIOProcessor());
+        ioProcessors.put(SCXMLIOProcessor.SCXML_EVENT_PROCESSOR, new ExternalSCXMLIOProcessor(getExternalIOProcessor()));
+        ioProcessors.put(SCXMLIOProcessor.DEFAULT_EVENT_PROCESSOR, ioProcessors.get(SCXMLIOProcessor.SCXML_EVENT_PROCESSOR));
         ioProcessors.put(SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR, getInternalIOProcessor());
-        if (scxmlExecutor.getParentSCXMLExecutor() != null) {
-            ioProcessors.put(SCXMLIOProcessor.PARENT_EVENT_PROCESSOR, scxmlExecutor.getParentSCXMLExecutor());
+        if (scxmlExecutor.getParentSCXMLIOProcessor() != null) {
+            ioProcessors.put(SCXMLIOProcessor.PARENT_EVENT_PROCESSOR, scxmlExecutor.getParentSCXMLIOProcessor());
         }
         initializeIOProcessors();
         registerInvokerClass(SCXML_INVOKER_TYPE_URI, SimpleSCXMLInvoker.class);
@@ -414,13 +414,23 @@ public class SCXMLExecutionContext implements SCXMLIOProcessor {
     }
 
     /**
+     * Trivial utility method needed for SCXML IRP test 216 which (IMO incorrectly uses http://www.w3.org/TR/scxml
+     * (no trailing /) while the SCXML spec explicitly states http://www.w3.org/TR/scxml/ should be used (supported)
+     * @param uri
+     * @return
+     */
+    private final String stripTrailingSlash(final String uri) {
+        return uri.endsWith("/") ? uri.substring(0, uri.length()-1) : uri;
+    }
+
+    /**
      * Register an Invoker for this target type.
      *
      * @param type The target type (specified by "type" attribute of the invoke element).
      * @param invokerClass The Invoker class.
      */
     protected void registerInvokerClass(final String type, final Class<? extends Invoker> invokerClass) {
-        invokerClasses.put(type, invokerClass);
+        invokerClasses.put(stripTrailingSlash(type), invokerClass);
     }
 
     /**
@@ -429,7 +439,7 @@ public class SCXMLExecutionContext implements SCXMLIOProcessor {
      * @param type The target type (specified by "type" attribute of the invoke element).
      */
     protected void unregisterInvokerClass(final String type) {
-        invokerClasses.remove(type);
+        invokerClasses.remove(stripTrailingSlash(type));
     }
 
     /**
@@ -442,9 +452,9 @@ public class SCXMLExecutionContext implements SCXMLIOProcessor {
      * @throws InvokerException When a suitable {@link Invoker} cannot be instantiated.
      */
     public Invoker newInvoker(final String type) throws InvokerException {
-        Class<? extends Invoker> invokerClass = invokerClasses.get(type);
+        Class<? extends Invoker> invokerClass = invokerClasses.get(stripTrailingSlash(type));
         if (invokerClass == null) {
-            throw new InvokerException("No Invoker registered for type \"" + type + "\"");
+            throw new InvokerException("No Invoker registered for type \"" + stripTrailingSlash(type) + "\"");
         }
         try {
             return invokerClass.newInstance();
@@ -515,7 +525,7 @@ public class SCXMLExecutionContext implements SCXMLIOProcessor {
             try {
                 invokers.get(invokeId).cancel();
             } catch (InvokerException ie) {
-                TriggerEvent te = new TriggerEvent("failed.invoke.cancel."+invokeId, TriggerEvent.ERROR_EVENT);
+                TriggerEvent te = new EventBuilder("failed.invoke.cancel."+invokeId, TriggerEvent.ERROR_EVENT).build();
                 addEvent(te);
             }
             removeInvoker(invoke);

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/SCXMLExecutor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/SCXMLExecutor.java b/src/main/java/org/apache/commons/scxml2/SCXMLExecutor.java
index d22fe1d..a2b6bfd 100644
--- a/src/main/java/org/apache/commons/scxml2/SCXMLExecutor.java
+++ b/src/main/java/org/apache/commons/scxml2/SCXMLExecutor.java
@@ -54,9 +54,9 @@ public class SCXMLExecutor implements SCXMLIOProcessor {
     private Log log = LogFactory.getLog(SCXMLExecutor.class);
 
     /**
-     * Parent SCXMLExecutor
+     * Parent SCXMLIOProcessor
      */
-    private SCXMLExecutor parentSCXMLExecutor;
+    private ParentSCXMLIOProcessor parentSCXMLIOProcessor;
 
     /**
      *  Interpretation semantics.
@@ -112,20 +112,21 @@ public class SCXMLExecutor implements SCXMLIOProcessor {
      *
      * @param parentSCXMLExecutor the parent SCXMLExecutor
      */
-    public SCXMLExecutor(final SCXMLExecutor parentSCXMLExecutor) throws ModelException {
-        this.parentSCXMLExecutor = parentSCXMLExecutor;
+    public SCXMLExecutor(final SCXMLExecutor parentSCXMLExecutor, final String invokeId, final SCXML scxml) throws ModelException {
+        this.parentSCXMLIOProcessor = new ParentSCXMLIOProcessor(parentSCXMLExecutor, invokeId);
         this.semantics = parentSCXMLExecutor.semantics;
         this.exctx = new SCXMLExecutionContext(this, parentSCXMLExecutor.getEvaluator(),
-                parentSCXMLExecutor.getEventdispatcher(), parentSCXMLExecutor.getErrorReporter());
+                parentSCXMLExecutor.getEventdispatcher().newInstance(), parentSCXMLExecutor.getErrorReporter());
         getSCInstance().setSingleContext(parentSCXMLExecutor.isSingleContext());
         getSCInstance().setStrict(parentSCXMLExecutor.isStrict());
+        getSCInstance().setStateMachine(scxml);
     }
 
     /**
-     * @return the parent SCXMLExecutor (if any)
+     * @return the parent SCXMLIOProcessor (if any)
      */
-    protected SCXMLExecutor getParentSCXMLExecutor() {
-        return parentSCXMLExecutor;
+    public ParentSCXMLIOProcessor getParentSCXMLIOProcessor() {
+        return parentSCXMLIOProcessor;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/SCXMLIOProcessor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/SCXMLIOProcessor.java b/src/main/java/org/apache/commons/scxml2/SCXMLIOProcessor.java
index bafb86a..289b6d3 100644
--- a/src/main/java/org/apache/commons/scxml2/SCXMLIOProcessor.java
+++ b/src/main/java/org/apache/commons/scxml2/SCXMLIOProcessor.java
@@ -33,7 +33,7 @@ public interface SCXMLIOProcessor {
     String EVENT_PROCESSOR_ALIAS_PREFIX = "#_";
 
     /**
-     * Default SCXML I/O Event Processor alias
+     * Default external SCXML I/O Event Processor alias
      */
     String SCXML_EVENT_PROCESSOR = "scxml";
 

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/TriggerEvent.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/TriggerEvent.java b/src/main/java/org/apache/commons/scxml2/TriggerEvent.java
index fbf3328..438b8ab 100644
--- a/src/main/java/org/apache/commons/scxml2/TriggerEvent.java
+++ b/src/main/java/org/apache/commons/scxml2/TriggerEvent.java
@@ -23,7 +23,7 @@ import java.io.Serializable;
  * defined in reference to SCXML.
  *
  * <b>NOTE:</b> Instances are {@link Serializable} as long as the associated
- * payload, if any, is {@link Serializable}.
+ * data, if any, is {@link Serializable}.
  *
  */
 public class TriggerEvent implements Serializable {
@@ -36,24 +36,21 @@ public class TriggerEvent implements Serializable {
      *
      * @param name The event name
      * @param type The event type
-     * @param payload The event payload, must be {@link Serializable}
+     * @deprecated use {@link EventBuilder instead}
      */
-    public TriggerEvent(final String name, final int type,
-            final Object payload) {
-        super();
-        this.name = name != null ? name.trim() : "";
-        this.type = type;
-        this.payload = payload;
+    public TriggerEvent(final String name, final int type) {
+        this(name, type, null, null, null, null, null);
     }
 
-    /**
-     * Constructor.
-     *
-     * @param name The event name
-     * @param type The event type
-     */
-    public TriggerEvent(final String name, final int type) {
-        this(name, type, null);
+    TriggerEvent(final String name, final int type, final String sendId, final String origin,
+                        final String originType, final String invokeId, final Object data) {
+        this.name = name != null ? name.trim() : "";
+        this.type = type;
+        this.sendId = sendId;
+        this.origin = origin;
+        this.originType = originType;
+        this.invokeId = invokeId;
+        this.data = data;
     }
 
     /**
@@ -122,45 +119,46 @@ public class TriggerEvent implements Serializable {
      */
     public static final String ERROR_PLATFORM = "error.platform";
 
-    /**
-     * The event name.
-     *
-     */
-    private String name;
-
-    /**
-     * The event type.
-     *
-     */
-    private int type;
-
-    /**
-     * The event payload.
-     *
-     */
-    private Object payload;
+    private final String name;
+    private final int type;
+    private final String sendId;
+    private final String origin;
+    private final String originType;
+    private final String invokeId;
+    private final Object data;
 
-    /**
-     * @return Returns the name.
-     */
     public String getName() {
         return name;
     }
 
-    /**
-     * @return Returns the payload.
-     */
-    public Object getPayload() {
-        return payload;
-    }
-
-    /**
-     * @return Returns the type.
-     */
     public int getType() {
         return type;
     }
 
+    public String getSendId() {
+        return sendId;
+    }
+
+    public String getOrigin() {
+        return origin;
+    }
+
+    public String getOriginType() {
+        return originType;
+    }
+
+    public String getInvokeId() {
+        return invokeId;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    private static boolean equals(final Object a, final Object b) {
+        return (a == null && b == null) || (a != null && a.equals(b));
+    }
+
     /**
      * Define an equals operator for TriggerEvent.
      *
@@ -170,9 +168,12 @@ public class TriggerEvent implements Serializable {
     public boolean equals(final Object obj) {
         if (obj instanceof TriggerEvent) {
             TriggerEvent te2 = (TriggerEvent) obj;
-            if (type == te2.type && name.equals(te2.name)
-                && ((payload == null && te2.payload == null)
-                     || (payload != null && payload.equals(te2.payload)))) {
+            if (type == te2.type && name.equals(te2.name) &&
+                    equals(sendId, te2.sendId) &&
+                    equals(origin, te2.origin) &&
+                    equals(originType, te2.originType) &&
+                    equals(invokeId, te2.invokeId) &&
+                    equals(data, te2.data)) {
                 return true;
             }
         }
@@ -186,10 +187,22 @@ public class TriggerEvent implements Serializable {
      */
     @Override
     public String toString() {
-        StringBuffer buf = new StringBuffer("TriggerEvent{name=");
-        buf.append(name).append(",type=").append(type);
-        if (payload != null) {
-            buf.append(",payload=").append(payload.toString());
+        StringBuilder buf = new StringBuilder("TriggerEvent{name=");
+        buf.append(name).append(", type=").append(type);
+        if (sendId != null) {
+            buf.append(", sendid=").append(invokeId);
+        }
+        if (origin != null) {
+            buf.append(", origin=").append(invokeId);
+        }
+        if (originType != null) {
+            buf.append(", origintype=").append(invokeId);
+        }
+        if (invokeId != null) {
+            buf.append(", invokeid=").append(invokeId);
+        }
+        if (data != null) {
+            buf.append(", data=").append(data.toString());
         }
         buf.append("}");
         return String.valueOf(buf);

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/env/AbstractStateMachine.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/AbstractStateMachine.java b/src/main/java/org/apache/commons/scxml2/env/AbstractStateMachine.java
index 80b5d59..d72ec77 100644
--- a/src/main/java/org/apache/commons/scxml2/env/AbstractStateMachine.java
+++ b/src/main/java/org/apache/commons/scxml2/env/AbstractStateMachine.java
@@ -27,6 +27,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
+import org.apache.commons.scxml2.EventBuilder;
 import org.apache.commons.scxml2.SCXMLExecutor;
 import org.apache.commons.scxml2.SCXMLListener;
 import org.apache.commons.scxml2.TriggerEvent;
@@ -197,8 +198,7 @@ public abstract class AbstractStateMachine {
      *         configuration.
      */
     public boolean fireEvent(final String event) {
-        TriggerEvent[] evts = {new TriggerEvent(event,
-                TriggerEvent.SIGNAL_EVENT)};
+        TriggerEvent[] evts = {new EventBuilder(event, TriggerEvent.SIGNAL_EVENT).build()};
         try {
             engine.triggerEvents(evts);
         } catch (ModelException me) {

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/env/SimpleDispatcher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/SimpleDispatcher.java b/src/main/java/org/apache/commons/scxml2/env/SimpleDispatcher.java
index c3332c9..60ae51f 100644
--- a/src/main/java/org/apache/commons/scxml2/env/SimpleDispatcher.java
+++ b/src/main/java/org/apache/commons/scxml2/env/SimpleDispatcher.java
@@ -25,9 +25,12 @@ import java.util.TimerTask;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.commons.scxml2.EventBuilder;
 import org.apache.commons.scxml2.EventDispatcher;
+import org.apache.commons.scxml2.ParentSCXMLIOProcessor;
 import org.apache.commons.scxml2.SCXMLIOProcessor;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.model.ActionExecutionError;
 
 /**
  * <p>EventDispatcher implementation that can schedule <code>delay</code>ed
@@ -58,14 +61,9 @@ public class SimpleDispatcher implements EventDispatcher, Serializable {
         private String id;
 
         /**
-         * The event name.
+         * The event
          */
-        private String event;
-
-        /**
-         * The event payload, if any.
-         */
-        private Object payload;
+        private TriggerEvent event;
 
         /**
          * The target io processor
@@ -76,15 +74,13 @@ public class SimpleDispatcher implements EventDispatcher, Serializable {
          * Constructor for events with payload.
          *
          * @param id The ID of the send element.
-         * @param event The name of the event to be triggered.
-         * @param payload The event payload, if any.
+         * @param event The event to be triggered.
          * @param target The target io processor
          */
-        DelayedEventTask(final String id, final String event, final Object payload, SCXMLIOProcessor target) {
+        DelayedEventTask(final String id, final TriggerEvent event, SCXMLIOProcessor target) {
             super();
             this.id = id;
             this.event = event;
-            this.payload = payload;
             this.target = target;
         }
 
@@ -94,9 +90,9 @@ public class SimpleDispatcher implements EventDispatcher, Serializable {
         @Override
         public void run() {
             timers.remove(id);
-            target.addEvent(new TriggerEvent(event, TriggerEvent.SIGNAL_EVENT, payload));
+            target.addEvent(event);
             if (log.isDebugEnabled()) {
-                log.debug("Fired event '" + event + "' as scheduled by "
+                log.debug("Fired event '" + event.getName() + "' as scheduled by "
                         + "<send> with id '" + id + "'");
             }
         }
@@ -138,6 +134,12 @@ public class SimpleDispatcher implements EventDispatcher, Serializable {
         return timers;
     }
 
+
+    @Override
+    public SimpleDispatcher newInstance() {
+        return new SimpleDispatcher();
+    }
+
     /**
      * @see EventDispatcher#cancel(String)
      */
@@ -181,13 +183,15 @@ public class SimpleDispatcher implements EventDispatcher, Serializable {
 
         if (type == null || type.equalsIgnoreCase(SCXMLIOProcessor.SCXML_EVENT_PROCESSOR) ||
                 type.equals(SCXMLIOProcessor.DEFAULT_EVENT_PROCESSOR)) {
-
+            String originType = SCXMLIOProcessor.DEFAULT_EVENT_PROCESSOR;
             SCXMLIOProcessor ioProcessor;
 
             boolean internal = false;
 
+            String origin = target;
             if (target == null) {
                 ioProcessor = ioProcessors.get(SCXMLIOProcessor.SCXML_EVENT_PROCESSOR);
+                origin = SCXMLIOProcessor.SCXML_EVENT_PROCESSOR;
             }
             else if (ioProcessors.containsKey(target)) {
                 ioProcessor = ioProcessors.get(target);
@@ -198,44 +202,53 @@ public class SimpleDispatcher implements EventDispatcher, Serializable {
                 internal = true;
             }
             else {
-                // We know of no other target
-                if (log.isWarnEnabled()) {
-                    log.warn("<send>: Unavailable target - " + target);
+                if (target.startsWith(SCXMLIOProcessor.EVENT_PROCESSOR_ALIAS_PREFIX)) {
+                    ioProcessors.get(SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR).addEvent(
+                            new EventBuilder(TriggerEvent.ERROR_COMMUNICATION, TriggerEvent.ERROR_EVENT)
+                                    .sendId(id).build());
+                    throw new ActionExecutionError(true, "<send>: Unavailable target - " + target);
+                } else {
+                    ioProcessors.get(SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR).addEvent(
+                            new EventBuilder(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT)
+                                    .sendId(id).build());
+                    throw new ActionExecutionError(true, "<send>: Invalid or unsupported target - " + target);
                 }
-                ioProcessors.get(SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR).
-                        addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
-                return; // done
             }
 
             if (event == null) {
-                if (log.isWarnEnabled()) {
-                    log.warn("<send>: Cannot send without event name");
-                }
-                ioProcessors.get(SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR).
-                        addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
-            }
-
-            else if (!internal && delay > 0L) {
-                // Need to schedule this one
-                Timer timer = new Timer(true);
-                timer.schedule(new DelayedEventTask(id, event, data, ioProcessor), delay);
-                timers.put(id, timer);
-                if (log.isDebugEnabled()) {
-                    log.debug("Scheduled event '" + event + "' with delay "
-                            + delay + "ms, as specified by <send> with id '"
-                            + id + "'");
-                }
+                ioProcessors.get(SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR)
+                        .addEvent(new EventBuilder(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT).sendId(id).build());
+                throw new ActionExecutionError(true, "<send>: Cannot send without event name");
             }
             else {
-                ioProcessor.addEvent(new TriggerEvent(event, TriggerEvent.SIGNAL_EVENT, data));
+                EventBuilder eventBuilder = new EventBuilder(event, TriggerEvent.SIGNAL_EVENT)
+                        .sendId(id)
+                        .data(data);
+                if (!internal) {
+                    eventBuilder.origin(origin).originType(originType);
+                    if (SCXMLIOProcessor.PARENT_EVENT_PROCESSOR.equals(target)) {
+                        eventBuilder.invokeId(((ParentSCXMLIOProcessor)ioProcessor).getInvokeId());
+                    }
+                    if (delay > 0L) {
+                        // Need to schedule this one
+                        Timer timer = new Timer(true);
+                        timer.schedule(new DelayedEventTask(id, eventBuilder.build(), ioProcessor), delay);
+                        timers.put(id, timer);
+                        if (log.isDebugEnabled()) {
+                            log.debug("Scheduled event '" + event + "' with delay "
+                                    + delay + "ms, as specified by <send> with id '"
+                                    + id + "'");
+                        }
+                        return;
+                    }
+                }
+                ioProcessor.addEvent(eventBuilder.build());
             }
         }
         else {
-            if (log.isWarnEnabled()) {
-                log.warn("<send>: Unsupported type - " + type);
-            }
-            ioProcessors.get(SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR).
-                    addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
+            ioProcessors.get(SCXMLIOProcessor.INTERNAL_EVENT_PROCESSOR)
+                    .addEvent(new EventBuilder(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT).sendId(id).build());
+            throw new ActionExecutionError(true, "<send>: Unsupported type - " + type);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/env/javascript/init_global.js
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/javascript/init_global.js b/src/main/java/org/apache/commons/scxml2/env/javascript/init_global.js
index b4cb4fc..fccb6cb 100644
--- a/src/main/java/org/apache/commons/scxml2/env/javascript/init_global.js
+++ b/src/main/java/org/apache/commons/scxml2/env/javascript/init_global.js
@@ -79,13 +79,13 @@ Object.defineProperties(this, {
                 _scxmlProtected("_event.sendid")
             },
             get orgin() {
-                return _scxmlSystemContext._event.orgin||undefined
+                return _scxmlSystemContext._event.origin||undefined
             },
             set origin(val) {
                 _scxmlProtected("_event.origin")
             },
             get origintype() {
-                return _scxmlSystemContext._event.orgintype||undefined
+                return _scxmlSystemContext._event.origintype||undefined
             },
             set origintype(val) {
                 _scxmlProtected("_event.origintype")

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/invoke/AsyncTrigger.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/invoke/AsyncTrigger.java b/src/main/java/org/apache/commons/scxml2/invoke/AsyncTrigger.java
deleted file mode 100644
index afa9dd8..0000000
--- a/src/main/java/org/apache/commons/scxml2/invoke/AsyncTrigger.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.scxml2.invoke;
-
-import org.apache.commons.scxml2.SCXMLIOProcessor;
-import org.apache.commons.scxml2.TriggerEvent;
-
-/**
- * Trigger the given {@link TriggerEvent} on the given
- * state machine executor asynchronously, once.
- */
-class AsyncTrigger implements Runnable {
-
-    /** 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 ioProcessor The {@link org.apache.commons.scxml2.SCXMLIOProcessor} to trigger the event on.
-     * @param event The {@link TriggerEvent}.
-     */
-    AsyncTrigger(final SCXMLIOProcessor ioProcessor, final TriggerEvent event) {
-        this.ioProcessor = ioProcessor;
-        this.event = event;
-    }
-
-    /**
-     * Fire the trigger asynchronously.
-     */
-    public void start() {
-        new Thread(this).start();
-    }
-
-    /**
-     * Fire the event(s).
-     */
-    public void run() {
-        ioProcessor.addEvent(event);
-    }
-
-}
-

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/invoke/SimpleSCXMLInvoker.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/invoke/SimpleSCXMLInvoker.java b/src/main/java/org/apache/commons/scxml2/invoke/SimpleSCXMLInvoker.java
index 44084a3..ee7262f 100644
--- a/src/main/java/org/apache/commons/scxml2/invoke/SimpleSCXMLInvoker.java
+++ b/src/main/java/org/apache/commons/scxml2/invoke/SimpleSCXMLInvoker.java
@@ -24,6 +24,7 @@ import java.util.Map;
 import javax.xml.stream.XMLStreamException;
 
 import org.apache.commons.scxml2.Context;
+import org.apache.commons.scxml2.EventBuilder;
 import org.apache.commons.scxml2.SCXMLExecutor;
 import org.apache.commons.scxml2.SCXMLIOProcessor;
 import org.apache.commons.scxml2.TriggerEvent;
@@ -40,8 +41,8 @@ public class SimpleSCXMLInvoker implements Invoker, Serializable {
 
     /** Serial version UID. */
     private static final long serialVersionUID = 1L;
-    /** Parent state ID. */
-    private String parentStateId;
+    /** invokeId ID. */
+    private String invokeId;
     /** Invoking parent SCXMLExecutor */
     private SCXMLExecutor parentSCXMLExecutor;
     /** The invoked state machine executor. */
@@ -55,7 +56,7 @@ public class SimpleSCXMLInvoker implements Invoker, Serializable {
      */
     @Override
     public String getInvokeId() {
-        return parentStateId;
+        return invokeId;
     }
 
     /**
@@ -63,7 +64,7 @@ public class SimpleSCXMLInvoker implements Invoker, Serializable {
      */
     @Override
     public void setInvokeId(final String invokeId) {
-        this.parentStateId = invokeId;
+        this.invokeId = invokeId;
         this.cancelled = false;
     }
 
@@ -101,26 +102,17 @@ public class SimpleSCXMLInvoker implements Invoker, Serializable {
             throw new InvokerException(xse.getMessage(), xse.getCause());
         }
         try {
-            executor = new SCXMLExecutor(parentSCXMLExecutor);
-            executor.setStateMachine(scxml);
+            executor = new SCXMLExecutor(parentSCXMLExecutor, invokeId, scxml);
         }
         catch (ModelException me) {
             throw new InvokerException(me);
         }
-        Context rootCtx = executor.getRootContext();
-        for (Map.Entry<String, Object> entry : params.entrySet()) {
-            rootCtx.setLocal(entry.getKey(), entry.getValue());
-        }
         executor.addListener(scxml, new SimpleSCXMLListener());
         try {
-            executor.go();
+            executor.run(params);
         } catch (ModelException me) {
             throw new InvokerException(me.getMessage(), me.getCause());
         }
-        if (executor.getStatus().isFinal()) {
-            TriggerEvent te = new TriggerEvent("done.invoke."+parentStateId, TriggerEvent.SIGNAL_EVENT);
-            new AsyncTrigger(parentSCXMLExecutor, te).start();
-        }
     }
 
     /**
@@ -129,14 +121,8 @@ public class SimpleSCXMLInvoker implements Invoker, Serializable {
     @Override
     public void parentEvent(final TriggerEvent evt)
     throws InvokerException {
-        if (cancelled) {
-            return; // no further processing should take place
-        }
-        boolean doneBefore = executor.getStatus().isFinal();
-        executor.addEvent(evt);
-        if (!doneBefore && executor.getStatus().isFinal()) {
-            TriggerEvent te = new TriggerEvent("done.invoke."+parentStateId,TriggerEvent.SIGNAL_EVENT);
-            new AsyncTrigger(parentSCXMLExecutor, te).start();
+        if (!cancelled) {
+            executor.addEvent(evt);
         }
     }
 
@@ -147,7 +133,8 @@ public class SimpleSCXMLInvoker implements Invoker, Serializable {
     public void cancel()
     throws InvokerException {
         cancelled = true;
-        executor.addEvent(new TriggerEvent("cancel.invoke."+parentStateId, TriggerEvent.CANCEL_EVENT));
+        executor.getParentSCXMLIOProcessor().close();
+        executor.addEvent(new EventBuilder("cancel.invoke."+ invokeId, TriggerEvent.CANCEL_EVENT).build());
     }
 }
 

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/model/Action.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/model/Action.java b/src/main/java/org/apache/commons/scxml2/model/Action.java
index 550ddf0..0ad998b 100644
--- a/src/main/java/org/apache/commons/scxml2/model/Action.java
+++ b/src/main/java/org/apache/commons/scxml2/model/Action.java
@@ -126,8 +126,10 @@ public abstract class Action implements NamespacePrefixesHolder,
      *                        a non-deterministic state.
      * @throws SCXMLExpressionException If the execution involves trying
      *                        to evaluate an expression which is malformed.
+     * @throws ActionExecutionError to be thrown if the execution caused an error (event) to be raised,
+     * which then shall stop execution of (possible) following actions within the same executable content block
      */
-    public abstract void execute(ActionExecutionContext exctx) throws ModelException, SCXMLExpressionException;
+    public abstract void execute(ActionExecutionContext exctx) throws ModelException, SCXMLExpressionException, ActionExecutionError;
 
     /**
      * Return the key under which the current document namespaces are saved

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/model/ActionExecutionError.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/model/ActionExecutionError.java b/src/main/java/org/apache/commons/scxml2/model/ActionExecutionError.java
new file mode 100644
index 0000000..a71e7ea
--- /dev/null
+++ b/src/main/java/org/apache/commons/scxml2/model/ActionExecutionError.java
@@ -0,0 +1,57 @@
+/*
+ * 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.model;
+
+import org.apache.commons.scxml2.ActionExecutionContext;
+import org.apache.commons.scxml2.ErrorReporter;
+import org.apache.commons.scxml2.TriggerEvent;
+
+/**
+ * ActionExecutionError is a specific RuntimeException used for communicating the execution failure of an action.
+ * This exception when thrown from within {@link Action#execute(ActionExecutionContext)} will:
+ * <ul>
+ *     <li>stop further execution of (possible) following action within the same executable content block</li>
+ *     <li>if not yet {@link #isEventRaised()} raise the internal error event {@link TriggerEvent#ERROR_EXECUTION}</li>
+ *     <li>if a non-null error message is provided with the exception, report an error message with {@link ErrorReporter}</li>
+ * </ul>
+ * @see <a href="https://www.w3.org/TR/2015/REC-scxml-20150901/#EvaluationofExecutableContent">SCXML spec 4.9 Evaluation of Executable Content</a>
+ */
+public final class ActionExecutionError extends RuntimeException {
+
+    private final boolean eventRaised;
+
+    public ActionExecutionError() {
+        this(false, null);
+    }
+
+    public ActionExecutionError(final boolean eventRaised) {
+        this(eventRaised, null);
+    }
+
+    public ActionExecutionError(final String message) {
+        this(false, message);
+    }
+
+    public ActionExecutionError(final boolean eventRaised, final String message) {
+        super(message);
+        this.eventRaised = eventRaised;
+    }
+
+    public boolean isEventRaised() {
+        return eventRaised;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/model/Foreach.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/model/Foreach.java b/src/main/java/org/apache/commons/scxml2/model/Foreach.java
index 1325f79..6007b12 100644
--- a/src/main/java/org/apache/commons/scxml2/model/Foreach.java
+++ b/src/main/java/org/apache/commons/scxml2/model/Foreach.java
@@ -144,7 +144,9 @@ public class Foreach extends Action implements ActionsContainer {
                     }
                 }
             }
-            // else {} TODO: place the error 'error.execution' in the internal event queue. (section "3.12.2 Errors")
+            else {
+                throw new ActionExecutionError("<foreach> in state " + getParentEnterableState().getId()+": invalid array value '"+array+"'");
+            }
         }
         finally {
             ctx.setLocal(getNamespacesKey(), null);

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/model/If.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/model/If.java b/src/main/java/org/apache/commons/scxml2/model/If.java
index 7b93119..826afab 100644
--- a/src/main/java/org/apache/commons/scxml2/model/If.java
+++ b/src/main/java/org/apache/commons/scxml2/model/If.java
@@ -24,6 +24,7 @@ import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.SCXMLExpressionException;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.EventBuilder;
 import org.apache.commons.scxml2.semantics.ErrorConstants;
 
 /**
@@ -132,7 +133,7 @@ public class If extends Action implements ActionsContainer {
             }
         } catch (SCXMLExpressionException e) {
             rslt = Boolean.FALSE;
-            exctx.getInternalIOProcessor().addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
+            exctx.getInternalIOProcessor().addEvent(new EventBuilder(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT).build());
             exctx.getErrorReporter().onError(ErrorConstants.EXPRESSION_ERROR, "Treating as false due to error: "
                     + e.getMessage(), this);
         }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/model/Invoke.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/model/Invoke.java b/src/main/java/org/apache/commons/scxml2/model/Invoke.java
index 4885cc7..c14985c 100644
--- a/src/main/java/org/apache/commons/scxml2/model/Invoke.java
+++ b/src/main/java/org/apache/commons/scxml2/model/Invoke.java
@@ -27,6 +27,7 @@ import org.apache.commons.scxml2.SCXMLExecutionContext;
 import org.apache.commons.scxml2.SCXMLExpressionException;
 import org.apache.commons.scxml2.SCXMLSystemContext;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.EventBuilder;
 import org.apache.commons.scxml2.invoke.Invoker;
 import org.apache.commons.scxml2.invoke.InvokerException;
 import org.apache.commons.scxml2.semantics.ErrorConstants;
@@ -103,6 +104,11 @@ public class Invoke extends NamelistHolder implements PathResolverHolder, Conten
     private EnterableState parent;
 
     /**
+     * This invoke index in the parent (TransitionalState) defined invokers
+     */
+    private int invokeIndex;
+
+    /**
      * Get the identifier for this invoke (may be null).
      *
      * @return Returns the id.
@@ -322,14 +328,14 @@ public class Invoke extends NamelistHolder implements PathResolverHolder, Conten
      * Set the parent EnterableState.
      * @param parent The parent state to set
      */
-    public void setParentEnterableState(final EnterableState parent) {
+    public void setParentEnterableState(final EnterableState parent, final int invokeIndex) {
         if (parent == null) {
             throw new IllegalArgumentException("Parent parameter cannot be null");
         }
         this.parent = parent;
+        this.invokeIndex = invokeIndex;
     }
 
-    @SuppressWarnings("unchecked")
     @Override
     public void execute(final ActionExecutionContext axctx) throws ModelException {
         EnterableState parentState = getParentEnterableState();
@@ -357,7 +363,7 @@ public class Invoke extends NamelistHolder implements PathResolverHolder, Conten
 
             String invokeId = getId();
             if (invokeId == null) {
-                invokeId = parentState.getId() + "." + ctx.get(SCXMLSystemContext.SESSIONID_KEY);
+                invokeId = parentState.getId() + "." + ctx.get(SCXMLSystemContext.SESSIONID_KEY) + "." + invokeIndex;
             }
             if (getId() == null && getIdlocation() != null) {
                 eval.evalAssign(ctx, idlocation, invokeId);
@@ -390,7 +396,7 @@ public class Invoke extends NamelistHolder implements PathResolverHolder, Conten
                 }
             }
             if (src == null && srcNode == null) {
-                throw new SCXMLExpressionException("<invoke> for state "+parentState.getId() +
+                throw new ActionExecutionError("<invoke> for state "+parentState.getId() +
                         ": no src and no content defined");
             }
             Map<String, Object> payloadDataMap = new HashMap<>();
@@ -403,13 +409,12 @@ public class Invoke extends NamelistHolder implements PathResolverHolder, Conten
             // TODO: } else { invoker.invoke(srcNode, payloadDataMap); }
             exctx.registerInvoker(this, invoker);
         }
-        catch (InvokerException e) {
-            axctx.getErrorReporter().onError(ErrorConstants.EXECUTION_ERROR, e.getMessage(), this);
-            axctx.getInternalIOProcessor().addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
-        }
-        catch (SCXMLExpressionException e) {
-            axctx.getInternalIOProcessor().addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
-            axctx.getErrorReporter().onError(ErrorConstants.EXPRESSION_ERROR, e.getMessage(), this);
+        catch (InvokerException|ActionExecutionError|SCXMLExpressionException e) {
+            axctx.getInternalIOProcessor().addEvent(new EventBuilder(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT).build());
+            if (e.getMessage() != null) {
+                axctx.getErrorReporter().onError(e instanceof SCXMLExpressionException
+                        ? ErrorConstants.EXPRESSION_ERROR : ErrorConstants.EXECUTION_ERROR, e.getMessage(), this);
+            }
         }
         finally {
             ctx.setLocal(getNamespacesKey(), null);

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/model/Raise.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/model/Raise.java b/src/main/java/org/apache/commons/scxml2/model/Raise.java
index ab85606..9fa2aad 100644
--- a/src/main/java/org/apache/commons/scxml2/model/Raise.java
+++ b/src/main/java/org/apache/commons/scxml2/model/Raise.java
@@ -19,6 +19,7 @@ package org.apache.commons.scxml2.model;
 import org.apache.commons.scxml2.ActionExecutionContext;
 import org.apache.commons.scxml2.SCXMLExpressionException;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.EventBuilder;
 
 /**
  * The class in this SCXML object model that corresponds to the
@@ -72,7 +73,7 @@ public class Raise extends Action {
         if (exctx.getAppLog().isDebugEnabled()) {
             exctx.getAppLog().debug("<raise>: Adding event '" + event + "' to list of derived events.");
         }
-        TriggerEvent ev = new TriggerEvent(event, TriggerEvent.SIGNAL_EVENT);
+        TriggerEvent ev = new EventBuilder(event, TriggerEvent.SIGNAL_EVENT).build();
         exctx.getInternalIOProcessor().addEvent(ev);
 
     }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/model/Send.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/model/Send.java b/src/main/java/org/apache/commons/scxml2/model/Send.java
index 3352056..b7ed695 100644
--- a/src/main/java/org/apache/commons/scxml2/model/Send.java
+++ b/src/main/java/org/apache/commons/scxml2/model/Send.java
@@ -346,87 +346,91 @@ public class Send extends NamelistHolder implements ContentContainer {
         // Send attributes evaluation
         EnterableState parentState = getParentEnterableState();
         Context ctx = exctx.getContext(parentState);
-        ctx.setLocal(getNamespacesKey(), getNamespaces());
-        Evaluator eval = exctx.getEvaluator();
-        // Most attributes of <send> are expressions so need to be
-        // evaluated before the EventDispatcher callback
-        Object hintsValue = null;
-        if (hints != null) {
-            hintsValue = eval.eval(ctx, hints);
-        }
-        if (id == null) {
-            id = ctx.getSystemContext().generateSessionId();
+        try {
+            ctx.setLocal(getNamespacesKey(), getNamespaces());
+            Evaluator eval = exctx.getEvaluator();
+            // Most attributes of <send> are expressions so need to be
+            // evaluated before the EventDispatcher callback
+            Object hintsValue = null;
+            if (hints != null) {
+                hintsValue = eval.eval(ctx, hints);
+            }
             if (idlocation != null) {
+                if (id == null) {
+                    id = ctx.getSystemContext().generateSessionId();
+                }
                 eval.evalAssign(ctx, idlocation, id);
             }
-        }
-        String targetValue = target;
-        if (targetValue == null && targetexpr != null) {
-            targetValue = (String)eval.eval(ctx, targetexpr);
-            if ((targetValue == null || targetValue.trim().length() == 0)
-                    && exctx.getAppLog().isWarnEnabled()) {
-                exctx.getAppLog().warn("<send>: target expression \"" + targetexpr
-                        + "\" evaluated to null or empty String");
+            String targetValue = target;
+            if (targetValue == null && targetexpr != null) {
+                targetValue = (String)eval.eval(ctx, targetexpr);
+                if ((targetValue == null || targetValue.trim().length() == 0)
+                        && exctx.getAppLog().isWarnEnabled()) {
+                    exctx.getAppLog().warn("<send>: target expression \"" + targetexpr
+                            + "\" evaluated to null or empty String");
+                }
             }
-        }
-        String typeValue = type;
-        if (typeValue == null && typeexpr != null) {
-            typeValue = (String)eval.eval(ctx, typeexpr);
-            if ((typeValue == null || typeValue.trim().length() == 0)
-                    && exctx.getAppLog().isWarnEnabled()) {
-                exctx.getAppLog().warn("<send>: type expression \"" + typeexpr
-                        + "\" evaluated to null or empty String");
+            String typeValue = type;
+            if (typeValue == null && typeexpr != null) {
+                typeValue = (String)eval.eval(ctx, typeexpr);
+                if ((typeValue == null || typeValue.trim().length() == 0)
+                        && exctx.getAppLog().isWarnEnabled()) {
+                    exctx.getAppLog().warn("<send>: type expression \"" + typeexpr
+                            + "\" evaluated to null or empty String");
+                }
             }
-        }
-        if (typeValue == null) {
-            // must default to 'scxml' when unspecified
-            typeValue = SCXMLIOProcessor.DEFAULT_EVENT_PROCESSOR;
-        } else if (!SCXMLIOProcessor.DEFAULT_EVENT_PROCESSOR.equals(typeValue) && typeValue.trim().equalsIgnoreCase(SCXMLIOProcessor.SCXML_EVENT_PROCESSOR)) {
-            typeValue = SCXMLIOProcessor.DEFAULT_EVENT_PROCESSOR;
-        }
-        Object payload = null;
-        Map<String, Object> payloadDataMap = new LinkedHashMap<>();
-        addNamelistDataToPayload(exctx, payloadDataMap);
-        addParamsToPayload(exctx, payloadDataMap);
-        if (!payloadDataMap.isEmpty()) {
-            payload = payloadDataMap;
-        }
-        else if (content != null) {
-            if (content.getExpr() != null) {
-                payload = eval.cloneData(eval.eval(ctx, content.getExpr()));
-            } else {
-                payload = eval.cloneData(content.getBody());
+            if (typeValue == null) {
+                // must default to 'scxml' when unspecified
+                typeValue = SCXMLIOProcessor.DEFAULT_EVENT_PROCESSOR;
+            } else if (!SCXMLIOProcessor.DEFAULT_EVENT_PROCESSOR.equals(typeValue) && typeValue.trim().equalsIgnoreCase(SCXMLIOProcessor.SCXML_EVENT_PROCESSOR)) {
+                typeValue = SCXMLIOProcessor.DEFAULT_EVENT_PROCESSOR;
             }
-        }
-        long wait = 0L;
-        String delayString = delay;
-        if (delayString == null && delayexpr != null) {
-            Object delayValue = eval.eval(ctx, delayexpr);
-            if (delayValue != null) {
-                delayString = delayValue.toString();
+            Object payload = null;
+            Map<String, Object> payloadDataMap = new LinkedHashMap<>();
+            addNamelistDataToPayload(exctx, payloadDataMap);
+            addParamsToPayload(exctx, payloadDataMap);
+            if (!payloadDataMap.isEmpty()) {
+                payload = payloadDataMap;
             }
-        }
-        if (delayString != null) {
-            wait = parseDelay(delayString, delayexpr != null, delayexpr != null ? delayexpr : delay);
-        }
-        String eventValue = event;
-        if (eventValue == null && eventexpr != null) {
-            eventValue = (String)eval.eval(ctx, eventexpr);
-            if ((eventValue == null)) {
-                throw new SCXMLExpressionException("<send>: event expression \"" + eventexpr
-                        + "\" evaluated to null");
+            else if (content != null) {
+                if (content.getExpr() != null) {
+                    payload = eval.cloneData(eval.eval(ctx, content.getExpr()));
+                } else {
+                    payload = eval.cloneData(content.getBody());
+                }
+            }
+            long wait = 0L;
+            String delayString = delay;
+            if (delayString == null && delayexpr != null) {
+                Object delayValue = eval.eval(ctx, delayexpr);
+                if (delayValue != null) {
+                    delayString = delayValue.toString();
+                }
+            }
+            if (delayString != null) {
+                wait = parseDelay(delayString, delayexpr != null, delayexpr != null ? delayexpr : delay);
+            }
+            String eventValue = event;
+            if (eventValue == null && eventexpr != null) {
+                eventValue = (String)eval.eval(ctx, eventexpr);
+                if ((eventValue == null)) {
+                    throw new SCXMLExpressionException("<send>: event expression \"" + eventexpr
+                            + "\" evaluated to null");
+                }
+            }
+            Map<String, SCXMLIOProcessor> ioProcessors = (Map<String, SCXMLIOProcessor>) ctx.get(SCXMLSystemContext.IOPROCESSORS_KEY);
+            if (exctx.getAppLog().isDebugEnabled()) {
+                exctx.getAppLog().debug("<send>: Dispatching event '" + eventValue
+                        + "' to target '" + targetValue + "' of target type '"
+                        + typeValue + "' with suggested delay of " + wait
+                        + "ms");
             }
+            exctx.getEventDispatcher().send(ioProcessors, id, targetValue, typeValue, eventValue,
+                    payload, hintsValue, wait);
         }
-        Map<String, SCXMLIOProcessor> ioProcessors = (Map<String, SCXMLIOProcessor>) ctx.get(SCXMLSystemContext.IOPROCESSORS_KEY);
-        ctx.setLocal(getNamespacesKey(), null);
-        if (exctx.getAppLog().isDebugEnabled()) {
-            exctx.getAppLog().debug("<send>: Dispatching event '" + eventValue
-                    + "' to target '" + targetValue + "' of target type '"
-                    + typeValue + "' with suggested delay of " + wait
-                    + "ms");
+        finally {
+            ctx.setLocal(getNamespacesKey(), null);
         }
-        exctx.getEventDispatcher().send(ioProcessors, id, targetValue, typeValue, eventValue,
-                payload, hintsValue, wait);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/model/TransitionalState.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/model/TransitionalState.java b/src/main/java/org/apache/commons/scxml2/model/TransitionalState.java
index c2f4f0a..e7adfd0 100644
--- a/src/main/java/org/apache/commons/scxml2/model/TransitionalState.java
+++ b/src/main/java/org/apache/commons/scxml2/model/TransitionalState.java
@@ -216,8 +216,8 @@ public abstract class TransitionalState extends EnterableState {
      *            The invoke to set.
      */
     public final void addInvoke(final Invoke invoke) {
+        invoke.setParentEnterableState(this, this.invokes.size());
         this.invokes.add(invoke);
-        invoke.setParentEnterableState(this);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/model/Var.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/model/Var.java b/src/main/java/org/apache/commons/scxml2/model/Var.java
index a08c23e..71191d5 100644
--- a/src/main/java/org/apache/commons/scxml2/model/Var.java
+++ b/src/main/java/org/apache/commons/scxml2/model/Var.java
@@ -21,6 +21,7 @@ import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.SCXMLExpressionException;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.EventBuilder;
 
 /**
  * The class in this SCXML object model that corresponds to the
@@ -104,7 +105,7 @@ public class Var extends Action {
             exctx.getAppLog().debug("<var>: Defined variable '" + name
                 + "' with initial value '" + String.valueOf(varObj) + "'");
         }
-        TriggerEvent ev = new TriggerEvent(name + ".change", TriggerEvent.CHANGE_EVENT);
+        TriggerEvent ev = new EventBuilder(name + ".change", TriggerEvent.CHANGE_EVENT).build();
         exctx.getInternalIOProcessor().addEvent(ev);
     }
 }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/semantics/SCXMLSemanticsImpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/semantics/SCXMLSemanticsImpl.java b/src/main/java/org/apache/commons/scxml2/semantics/SCXMLSemanticsImpl.java
index 0278832..4e476c2 100644
--- a/src/main/java/org/apache/commons/scxml2/semantics/SCXMLSemanticsImpl.java
+++ b/src/main/java/org/apache/commons/scxml2/semantics/SCXMLSemanticsImpl.java
@@ -28,6 +28,7 @@ import java.util.Set;
 import org.apache.commons.scxml2.ActionExecutionContext;
 import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.ErrorReporter;
+import org.apache.commons.scxml2.ParentSCXMLIOProcessor;
 import org.apache.commons.scxml2.SCInstance;
 import org.apache.commons.scxml2.SCXMLExecutionContext;
 import org.apache.commons.scxml2.SCXMLExpressionException;
@@ -35,9 +36,10 @@ import org.apache.commons.scxml2.SCXMLSemantics;
 import org.apache.commons.scxml2.SCXMLSystemContext;
 import org.apache.commons.scxml2.StateConfiguration;
 import org.apache.commons.scxml2.TriggerEvent;
-import org.apache.commons.scxml2.invoke.Invoker;
+import org.apache.commons.scxml2.EventBuilder;
 import org.apache.commons.scxml2.invoke.InvokerException;
 import org.apache.commons.scxml2.model.Action;
+import org.apache.commons.scxml2.model.ActionExecutionError;
 import org.apache.commons.scxml2.model.DocumentOrder;
 import org.apache.commons.scxml2.model.EnterableState;
 import org.apache.commons.scxml2.model.Executable;
@@ -222,7 +224,18 @@ public class SCXMLSemanticsImpl implements SCXMLSemantics {
             }
             exctx.getNotificationRegistry().fireOnExit(es, es);
             exctx.getNotificationRegistry().fireOnExit(exctx.getStateMachine(), es);
-            if (!(es instanceof Final && es.getParent() == null)) {
+            if (es instanceof Final && es.getParent() == null) {
+                if (exctx.getSCXMLExecutor().getParentSCXMLIOProcessor() != null) {
+                    ParentSCXMLIOProcessor ioProcessor = exctx.getSCXMLExecutor().getParentSCXMLIOProcessor();
+                    if (!ioProcessor.isClosed()) {
+                        ioProcessor.addEvent(
+                                new EventBuilder("done.invoke."+ioProcessor.getInvokeId(), TriggerEvent.SIGNAL_EVENT)
+                                        .invokeId(ioProcessor.getInvokeId()).build());
+                        ioProcessor.close();
+                    }
+                }
+            }
+            else {
                 exctx.getScInstance().getStateConfiguration().exitState(es);
             }
             // else: keep final Final
@@ -707,7 +720,7 @@ public class SCXMLSemanticsImpl implements SCXMLSemantics {
                 }
             }
             catch (SCXMLExpressionException e) {
-                exctx.getInternalIOProcessor().addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
+                exctx.getInternalIOProcessor().addEvent(new EventBuilder(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT).build());
                 exctx.getErrorReporter().onError(ErrorConstants.EXPRESSION_ERROR, "Treating as false due to error: "
                         + e.getMessage(), transition);
             }
@@ -747,19 +760,6 @@ public class SCXMLSemanticsImpl implements SCXMLSemantics {
     }
 
     /**
-     * Checks if an external event was send (back) by an specific Invoker
-     *
-     * @param invokerId the invokerId
-     *
-     * @param event received external event
-     * @return true if this event was send by the specific Invoker
-     */
-    public boolean isInvokerEvent(final String invokerId, final TriggerEvent event) {
-        return event.getName().equals("done.invoke."+invokerId) ||
-                event.getName().startsWith("done.invoke."+invokerId+".");
-    }
-
-    /**
      * Check if an external event indicates the state machine execution must be cancelled.
      *
      * @param event received external event
@@ -854,9 +854,8 @@ public class SCXMLSemanticsImpl implements SCXMLSemantics {
             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(event.getName(), eventType, null, null, null, null, event.getPayload());
+            eventVar = new EventVariable(event.getName(), eventType, event.getSendId(), event.getOrigin(),
+                    event.getOriginType(), event.getInvokeId(), event.getData());
         }
         systemContext.setLocal(SCXMLSystemContext.EVENT_KEY, eventVar);
     }
@@ -873,7 +872,7 @@ public class SCXMLSemanticsImpl implements SCXMLSemantics {
             try {
                 globalScript.execute(exctx.getActionExecutionContext());
             } catch (SCXMLExpressionException e) {
-                exctx.getInternalIOProcessor().addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
+                exctx.getInternalIOProcessor().addEvent(new EventBuilder(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT).build());
                 exctx.getErrorReporter().onError(ErrorConstants.EXPRESSION_ERROR, e.getMessage(), exctx.getStateMachine());
             }
         }
@@ -912,7 +911,7 @@ public class SCXMLSemanticsImpl implements SCXMLSemantics {
                 executeContent(exctx, onexit);
                 if (!onexitEventRaised && onexit.isRaiseEvent()) {
                     onexitEventRaised = true;
-                    exctx.getInternalIOProcessor().addEvent(new TriggerEvent("exit.state."+es.getId(), TriggerEvent.CHANGE_EVENT));
+                    exctx.getInternalIOProcessor().addEvent(new EventBuilder("exit.state."+es.getId(), TriggerEvent.CHANGE_EVENT).build());
                 }
             }
             exctx.getNotificationRegistry().fireOnExit(es, es);
@@ -954,8 +953,15 @@ public class SCXMLSemanticsImpl implements SCXMLSemantics {
                 action.execute(exctx.getActionExecutionContext());
             }
         } catch (SCXMLExpressionException e) {
-            exctx.getInternalIOProcessor().addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
+            exctx.getInternalIOProcessor().addEvent(new EventBuilder(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT).build());
             exctx.getErrorReporter().onError(ErrorConstants.EXPRESSION_ERROR, e.getMessage(), exec);
+        } catch (ActionExecutionError e) {
+            if (!e.isEventRaised()) {
+                exctx.getInternalIOProcessor().addEvent(new EventBuilder(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT).build());
+            }
+            if (e.getMessage() != null) {
+                exctx.getErrorReporter().onError(ErrorConstants.EXECUTION_ERROR, e.getMessage(), exec);
+            }
         }
         if (exec instanceof Transition) {
             Transition t = (Transition)exec;
@@ -1016,7 +1022,7 @@ public class SCXMLSemanticsImpl implements SCXMLSemantics {
                 executeContent(exctx, onentry);
                 if (!onentryEventRaised && onentry.isRaiseEvent()) {
                     onentryEventRaised = true;
-                    exctx.getInternalIOProcessor().addEvent(new TriggerEvent("entry.state."+es.getId(), TriggerEvent.CHANGE_EVENT));
+                    exctx.getInternalIOProcessor().addEvent(new EventBuilder("entry.state."+es.getId(), TriggerEvent.CHANGE_EVENT).build());
                 }
             }
             exctx.getNotificationRegistry().fireOnEntry(es, es);
@@ -1038,11 +1044,11 @@ public class SCXMLSemanticsImpl implements SCXMLSemantics {
                     exctx.stop();
                 }
                 else {
-                    exctx.getInternalIOProcessor().addEvent(new TriggerEvent("done.state."+parent.getId(),TriggerEvent.CHANGE_EVENT));
+                    exctx.getInternalIOProcessor().addEvent(new EventBuilder("done.state."+parent.getId(),TriggerEvent.CHANGE_EVENT).build());
                     if (parent.isRegion()) {
                         if (isInFinalState(parent.getParent(), exctx.getScInstance().getStateConfiguration().getActiveStates())) {
-                            exctx.getInternalIOProcessor().addEvent(new TriggerEvent("done.state."+parent.getParent().getId()
-                                    , TriggerEvent.CHANGE_EVENT));
+                            exctx.getInternalIOProcessor().addEvent(new EventBuilder("done.state."+parent.getParent().getId()
+                                    , TriggerEvent.CHANGE_EVENT).build());
                         }
                     }
                 }
@@ -1081,11 +1087,13 @@ public class SCXMLSemanticsImpl implements SCXMLSemantics {
      */
     public void processInvokes(final SCXMLExecutionContext exctx, final TriggerEvent event) throws ModelException {
         for (Map.Entry<Invoke, String> entry : exctx.getInvokeIds().entrySet()) {
-            if (!isInvokerEvent(entry.getValue(), event)) {
-                if (entry.getKey().isAutoForward()) {
-                    Invoker inv = exctx.getInvoker(entry.getKey());
+            if (entry.getValue().equals(event.getInvokeId())) {
+                Invoke invoke = entry.getKey();
+                if (entry.getKey().isAutoForward() &&
+                        !(event.getName().equals("done.invoke."+entry.getValue()) ||
+                                event.getName().startsWith("done.invoke."+entry.getValue()+"."))) {
                     try {
-                        inv.parentEvent(event);
+                        exctx.getInvoker(entry.getKey()).parentEvent(event);
                     } catch (InvokerException ie) {
                         exctx.getAppLog().error(ie.getMessage(), ie);
                         throw new ModelException(ie.getMessage(), ie.getCause());

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/system/EventVariable.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/system/EventVariable.java b/src/main/java/org/apache/commons/scxml2/system/EventVariable.java
index edaa1c3..13800aa 100644
--- a/src/main/java/org/apache/commons/scxml2/system/EventVariable.java
+++ b/src/main/java/org/apache/commons/scxml2/system/EventVariable.java
@@ -104,5 +104,25 @@ public class EventVariable implements Serializable {
     public Object getData() {
         return data;
     }
+
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("_event(");
+        sb.append("name: ").append(name);
+        sb.append(", type: ").append(type);
+        if (sendid != null) {
+            sb.append(", sendid: ").append(sendid);
+        }
+        if (origin != null) {
+            sb.append(", origin: ").append(origin);
+        }
+        if (origintype != null) {
+            sb.append(", origintype: ").append(origintype);
+        }
+        if (invokeid != null) {
+            sb.append(", invokeid: ").append(invokeid);
+        }
+        sb.append(")");
+        return sb.toString();
+    }
 }
 

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/main/java/org/apache/commons/scxml2/test/StandaloneUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/test/StandaloneUtils.java b/src/main/java/org/apache/commons/scxml2/test/StandaloneUtils.java
index 91db521..12c860e 100644
--- a/src/main/java/org/apache/commons/scxml2/test/StandaloneUtils.java
+++ b/src/main/java/org/apache/commons/scxml2/test/StandaloneUtils.java
@@ -29,6 +29,7 @@ import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.SCXMLExecutor;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.EventBuilder;
 import org.apache.commons.scxml2.env.Tracer;
 import org.apache.commons.scxml2.invoke.SimpleSCXMLInvoker;
 import org.apache.commons.scxml2.io.SCXMLReader;
@@ -111,8 +112,7 @@ public final class StandaloneUtils {
                         + value);
                 } else if (event.trim().length() == 0
                            || event.equalsIgnoreCase("null")) {
-                    TriggerEvent[] evts = {new TriggerEvent(null,
-                        TriggerEvent.SIGNAL_EVENT, null)};
+                    TriggerEvent[] evts = {new EventBuilder(null,TriggerEvent.SIGNAL_EVENT).build()};
                     exec.triggerEvents(evts);
                     if (exec.getStatus().isFinal()) {
                         System.out.println("A final configuration reached.");
@@ -122,8 +122,7 @@ public final class StandaloneUtils {
                     int tkns = st.countTokens();
                     TriggerEvent[] evts = new TriggerEvent[tkns];
                     for (int i = 0; i < tkns; i++) {
-                        evts[i] = new TriggerEvent(st.nextToken(),
-                                TriggerEvent.SIGNAL_EVENT, null);
+                        evts[i] = new EventBuilder(st.nextToken(), TriggerEvent.SIGNAL_EVENT).build();
                     }
                     exec.triggerEvents(evts);
                     if (exec.getStatus().isFinal()) {

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/EventDataTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/EventDataTest.java b/src/test/java/org/apache/commons/scxml2/EventDataTest.java
index fe92acc..885c182 100644
--- a/src/test/java/org/apache/commons/scxml2/EventDataTest.java
+++ b/src/test/java/org/apache/commons/scxml2/EventDataTest.java
@@ -39,19 +39,16 @@ public class EventDataTest {
         Set<EnterableState> currentStates = exec.getStatus().getStates();
         Assert.assertEquals(1, currentStates.size());
         Assert.assertEquals("state1", currentStates.iterator().next().getId());
-        TriggerEvent te = new TriggerEvent("event.foo",
-            TriggerEvent.SIGNAL_EVENT, new Integer(3));
+        TriggerEvent te = new EventBuilder("event.foo", TriggerEvent.SIGNAL_EVENT).data(new Integer(3)).build();
         currentStates = SCXMLTestHelper.fireEvent(exec, te);
         Assert.assertEquals(1, currentStates.size());
         Assert.assertEquals("state3", currentStates.iterator().next().getId());
         TriggerEvent[] evts = new TriggerEvent[] { te,
-            new TriggerEvent("event.bar", TriggerEvent.SIGNAL_EVENT,
-            new Integer(6))};
+            new EventBuilder("event.bar", TriggerEvent.SIGNAL_EVENT).data(new Integer(6)).build()};
         currentStates = SCXMLTestHelper.fireEvents(exec, evts);
         Assert.assertEquals(1, currentStates.size());
         Assert.assertEquals("state6", currentStates.iterator().next().getId());
-        te = new TriggerEvent("event.baz",
-            TriggerEvent.SIGNAL_EVENT, new Integer(7));
+        te = new EventBuilder("event.baz", TriggerEvent.SIGNAL_EVENT).data(new Integer(7)).build();
         currentStates = SCXMLTestHelper.fireEvent(exec, te);
         Assert.assertEquals(1, currentStates.size());
         Assert.assertEquals("state7", currentStates.iterator().next().getId());
@@ -64,14 +61,12 @@ public class EventDataTest {
         Set<EnterableState> currentStates = exec.getStatus().getStates();
         Assert.assertEquals(1, currentStates.size());
         Assert.assertEquals("state0", currentStates.iterator().next().getId());
-        TriggerEvent te1 = new TriggerEvent("connection.alerting",
-            TriggerEvent.SIGNAL_EVENT, "line2");
+        TriggerEvent te1 = new EventBuilder("connection.alerting", TriggerEvent.SIGNAL_EVENT).data("line2").build();
         currentStates = SCXMLTestHelper.fireEvent(exec, te1);
         Assert.assertEquals(1, currentStates.size());
         Assert.assertEquals("state2", currentStates.iterator().next().getId());
-        TriggerEvent te2 = new TriggerEvent("connection.alerting",
-            TriggerEvent.SIGNAL_EVENT,
-            new ConnectionAlertingPayload(4));
+        TriggerEvent te2 = new EventBuilder("connection.alerting", TriggerEvent.SIGNAL_EVENT)
+                .data(new ConnectionAlertingPayload(4)).build();
         currentStates = SCXMLTestHelper.fireEvent(exec, te2);
         Assert.assertEquals(1, currentStates.size());
         Assert.assertEquals("state4", currentStates.iterator().next().getId());
@@ -84,8 +79,7 @@ public class EventDataTest {
         Set<EnterableState> currentStates = exec.getStatus().getStates();
         Assert.assertEquals(1, currentStates.size());
         Assert.assertEquals("ten", currentStates.iterator().next().getId());
-        TriggerEvent te = new TriggerEvent("event.foo",
-            TriggerEvent.SIGNAL_EVENT);
+        TriggerEvent te = new EventBuilder("event.foo", TriggerEvent.SIGNAL_EVENT).build();
         currentStates = SCXMLTestHelper.fireEvent(exec, te);
         Assert.assertEquals(1, currentStates.size());
         Assert.assertEquals("thirty", currentStates.iterator().next().getId());

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/b4a10313/src/test/java/org/apache/commons/scxml2/SCXMLTestHelper.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/SCXMLTestHelper.java b/src/test/java/org/apache/commons/scxml2/SCXMLTestHelper.java
index 983bc7c..fef7a9d 100644
--- a/src/test/java/org/apache/commons/scxml2/SCXMLTestHelper.java
+++ b/src/test/java/org/apache/commons/scxml2/SCXMLTestHelper.java
@@ -148,8 +148,8 @@ public class SCXMLTestHelper {
         return fireEvent(exec, name, null);
     }
 
-    public static Set<EnterableState> fireEvent(SCXMLExecutor exec, String name, Object payload) throws Exception {
-        TriggerEvent[] evts = {new TriggerEvent(name, TriggerEvent.SIGNAL_EVENT, payload)};
+    public static Set<EnterableState> fireEvent(SCXMLExecutor exec, String name, Object data) throws Exception {
+        TriggerEvent[] evts = {new EventBuilder(name, TriggerEvent.SIGNAL_EVENT).data(data).build()};
         exec.triggerEvents(evts);
         return exec.getStatus().getStates();
     }
@@ -170,9 +170,9 @@ public class SCXMLTestHelper {
     }
 
     public static void assertPostTriggerState(SCXMLExecutor exec,
-            String triggerEventName, Object payload, String expectedStateId) throws Exception {
-        assertPostTriggerState(exec, new TriggerEvent(triggerEventName,
-                TriggerEvent.SIGNAL_EVENT, payload), expectedStateId);
+            String triggerEventName, Object data, String expectedStateId) throws Exception {
+        assertPostTriggerState(exec, new EventBuilder(triggerEventName, TriggerEvent.SIGNAL_EVENT)
+                .data(data).build(), expectedStateId);
     }
 
     public static void assertPostTriggerStates(SCXMLExecutor exec,
@@ -181,9 +181,9 @@ public class SCXMLTestHelper {
     }
 
     public static void assertPostTriggerStates(SCXMLExecutor exec,
-            String triggerEventName, Object payload, String[] expectedStateIds) throws Exception {
-        assertPostTriggerStates(exec, new TriggerEvent(triggerEventName,
-                TriggerEvent.SIGNAL_EVENT, payload), expectedStateIds);
+            String triggerEventName, Object data, String[] expectedStateIds) throws Exception {
+        assertPostTriggerStates(exec, new EventBuilder(triggerEventName, TriggerEvent.SIGNAL_EVENT)
+                .data(data).build(), expectedStateIds);
     }
 
     public static void assertPostTriggerState(SCXMLExecutor exec,