diff options
author | Stefan Radomski <github@mintwerk.de> | 2014-07-01 22:52:51 (GMT) |
---|---|---|
committer | Stefan Radomski <github@mintwerk.de> | 2014-07-01 22:52:51 (GMT) |
commit | f9e8883a9ae3574c99a7a830ec5d82e07d0f36f0 (patch) | |
tree | c43e4a7db898026bc62cc20af5061d07736f847e | |
parent | d48cefb17820d5dc4b6f05ee4a78a12c897997cd (diff) | |
parent | 945160d0539ad119ffc986fac712db76c7203e84 (diff) | |
download | uscxml-f9e8883a9ae3574c99a7a830ec5d82e07d0f36f0.zip uscxml-f9e8883a9ae3574c99a7a830ec5d82e07d0f36f0.tar.gz uscxml-f9e8883a9ae3574c99a7a830ec5d82e07d0f36f0.tar.bz2 |
Merge pull request #45 from sradomski/master
More polishing for bindings C# and Java
98 files changed, 1426 insertions, 700 deletions
@@ -21,3 +21,7 @@ package/windows* /package/* contrib/prebuilt/include/* + +/embedding/csharp/uSCXMLEmbedding/bin/ + +/embedding/csharp/uSCXMLEmbedding/obj/ diff --git a/embedding/csharp/uSCXMLEmbedding.suo b/embedding/csharp/uSCXMLEmbedding.suo Binary files differnew file mode 100644 index 0000000..b08325e --- /dev/null +++ b/embedding/csharp/uSCXMLEmbedding.suo diff --git a/embedding/csharp/uSCXMLEmbedding/Examples.csproj b/embedding/csharp/uSCXMLEmbedding/Examples.csproj index b1579bf..b312b5f 100644 --- a/embedding/csharp/uSCXMLEmbedding/Examples.csproj +++ b/embedding/csharp/uSCXMLEmbedding/Examples.csproj @@ -41,18 +41,19 @@ <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
- <Reference Include="uscxmlCSharp">
+ <Reference Include="uscxmlCSharp, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
<HintPath>C:\Users\sradomski\Desktop\build\uscxml\lib\uscxmlCSharp.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="Extensions\SampleDataModel.cs" />
- <Compile Include="Extensions\SampleExecutableContent.cs" />
- <Compile Include="Extensions\SampleInterpreterMonitor.cs" />
- <Compile Include="Extensions\SampleInvoker.cs" />
- <Compile Include="Extensions\SampleIOProc.cs" />
+ <Compile Include="Extensions\CustomDataModel.cs" />
+ <Compile Include="Extensions\CustomExecutableContent.cs" />
+ <Compile Include="Extensions\CustomInterpreterMonitor.cs" />
+ <Compile Include="Extensions\CustomInvoker.cs" />
+ <Compile Include="Extensions\CustomIOProc.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
diff --git a/embedding/csharp/uSCXMLEmbedding/Extensions/SampleDataModel.cs b/embedding/csharp/uSCXMLEmbedding/Extensions/CustomDataModel.cs index 4d70594..b2ee1de 100644 --- a/embedding/csharp/uSCXMLEmbedding/Extensions/SampleDataModel.cs +++ b/embedding/csharp/uSCXMLEmbedding/Extensions/CustomDataModel.cs @@ -4,13 +4,13 @@ using System.Linq; using System.Text;
using org.uscxml;
-namespace EmbeddedDataModel
+namespace embedding
{
- class SampleDataModel : DataModel
+ class CustomDataModel : DataModel
{
public override DataModel create(Interpreter interpreter)
{
- return new SampleDataModel();
+ return new CustomDataModel();
}
public override void eval(string scriptElem, string expr)
@@ -54,10 +54,9 @@ namespace EmbeddedDataModel return names;
}
- public override DataNative getStringAsData(string content)
+ public override Data getStringAsData(string content)
{
- // DataNative ought to be wrapped by a Data.cs class - used to carry JSONesque structures
- DataNative data = new DataNative();
+ Data data = new Data();
return data;
}
diff --git a/embedding/csharp/uSCXMLEmbedding/Extensions/SampleExecutableContent.cs b/embedding/csharp/uSCXMLEmbedding/Extensions/CustomExecutableContent.cs index a86776f..4789020 100644 --- a/embedding/csharp/uSCXMLEmbedding/Extensions/SampleExecutableContent.cs +++ b/embedding/csharp/uSCXMLEmbedding/Extensions/CustomExecutableContent.cs @@ -6,7 +6,7 @@ using org.uscxml; namespace embedding
{
- class SampleExecutableContent : ExecutableContent
+ class CustomExecutableContent : ExecutableContent
{
public override string getLocalName()
{
@@ -25,7 +25,7 @@ namespace embedding public override ExecutableContent create(Interpreter interpreter)
{
- return new SampleExecutableContent();
+ return new CustomExecutableContent();
}
diff --git a/embedding/csharp/uSCXMLEmbedding/Extensions/SampleIOProc.cs b/embedding/csharp/uSCXMLEmbedding/Extensions/CustomIOProc.cs index 5abbf37..0480a34 100644 --- a/embedding/csharp/uSCXMLEmbedding/Extensions/SampleIOProc.cs +++ b/embedding/csharp/uSCXMLEmbedding/Extensions/CustomIOProc.cs @@ -6,16 +6,16 @@ using org.uscxml; namespace embedding
{
- class SampleIOProc : IOProcessor
+ class CustomIOProc : IOProcessor
{
public override IOProcessor create(Interpreter interpreter)
{
- return new SampleIOProc();
+ return new CustomIOProc();
}
- public override DataNative getDataModelVariables()
+ public override Data getDataModelVariables()
{
- DataNative data = new DataNative();
+ Data data = new Data();
return data;
}
diff --git a/embedding/csharp/uSCXMLEmbedding/Extensions/SampleInterpreterMonitor.cs b/embedding/csharp/uSCXMLEmbedding/Extensions/CustomInterpreterMonitor.cs index 2a2f561..8009aa0 100644 --- a/embedding/csharp/uSCXMLEmbedding/Extensions/SampleInterpreterMonitor.cs +++ b/embedding/csharp/uSCXMLEmbedding/Extensions/CustomInterpreterMonitor.cs @@ -6,7 +6,7 @@ using org.uscxml; namespace embedding
{
- class SampleInterpreterMonitor : InterpreterMonitor
+ class CustomInterpreterMonitor : InterpreterMonitor
{
public override void afterCompletion(Interpreter interpreter) { }
public override void afterMicroStep(Interpreter interpreter) { }
diff --git a/embedding/csharp/uSCXMLEmbedding/Extensions/SampleInvoker.cs b/embedding/csharp/uSCXMLEmbedding/Extensions/CustomInvoker.cs index f5fb363..3fd01ce 100644 --- a/embedding/csharp/uSCXMLEmbedding/Extensions/SampleInvoker.cs +++ b/embedding/csharp/uSCXMLEmbedding/Extensions/CustomInvoker.cs @@ -4,18 +4,18 @@ using System.Linq; using System.Text;
using org.uscxml;
-namespace EmbeddedInvoker
+namespace embedding
{
- class SampleInvoker : Invoker
+ class CustomInvoker : Invoker
{
public override Invoker create(Interpreter interpreter)
{
- return new SampleInvoker();
+ return new CustomInvoker();
}
- public override DataNative getDataModelVariables()
+ public override Data getDataModelVariables()
{
- DataNative data = new DataNative();
+ Data data = new Data();
return data;
}
diff --git a/embedding/csharp/uSCXMLEmbedding/Program.cs b/embedding/csharp/uSCXMLEmbedding/Program.cs index 559d28f..0c76cb4 100644 --- a/embedding/csharp/uSCXMLEmbedding/Program.cs +++ b/embedding/csharp/uSCXMLEmbedding/Program.cs @@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
+using System.Diagnostics;
using System.Runtime.InteropServices;
namespace embedding
@@ -13,6 +14,34 @@ namespace embedding [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern void SetDllDirectory(string lpPathName);
+ static bool testLifecycle() {
+ // try to instantiate an interpreter with a parse error
+ try
+ {
+ Interpreter interpreter = Interpreter.fromXML("<invalid");
+ Debug.Assert(false);
+ }
+ catch (InterpreterException e) {
+ Console.Write(e.Message);
+ }
+
+ // try to instantiate an interpreter with invalid XML (no scxml element)
+ try
+ {
+ Interpreter interpreter = Interpreter.fromXML("<invalid />");
+ Debug.Assert(interpreter.getState() == InterpreterState.USCXML_INSTANTIATED);
+ InterpreterState state = interpreter.step();
+
+ Debug.Assert(false);
+ }
+ catch (InterpreterException e)
+ {
+ Console.Write(e.Message);
+ }
+
+ return true;
+ }
+
static void Main(string[] args)
{
@@ -28,9 +57,8 @@ namespace embedding SetDllDirectory("C:\\Users\\sradomski\\Desktop\\build\\uscxml\\lib\\csharp");
}
- Interpreter interpreter = Interpreter.fromXML("<scxml><state id=\"f oo\" final=\"true\" /></scxml>");
- interpreter.addMonitor(new SampleInterpreterMonitor());
- interpreter.interpret();
+ testLifecycle();
+ Console.ReadKey();
}
}
}
diff --git a/embedding/java/src/org/uscxml/datamodel/ecmascript/ECMAData.java b/embedding/java/src/org/uscxml/datamodel/ecmascript/ECMAData.java index 56d7090..035da61 100644 --- a/embedding/java/src/org/uscxml/datamodel/ecmascript/ECMAData.java +++ b/embedding/java/src/org/uscxml/datamodel/ecmascript/ECMAData.java @@ -19,8 +19,8 @@ public class ECMAData implements Scriptable { } public Object unwrap(Data data) { - if (data.atom.length() > 0) { - return data.atom; + if (data.getAtom().length() > 0) { + return data.getAtom(); } return new ECMAData(data); @@ -28,26 +28,26 @@ public class ECMAData implements Scriptable { @Override public Object get(String name, Scriptable start) { - if (data.compound.containsKey(name)) - return unwrap(data.compound.get(name)); + if (data.hasKey(name)) + return unwrap(data.at(name)); return NOT_FOUND; } @Override public Object get(int index, Scriptable start) { - if (data.array.size() > index) - return unwrap(data.array.get(index)); + if (data.getArray().size() > index) + return unwrap(data.item(index)); return NOT_FOUND; } @Override public boolean has(String name, Scriptable start) { - return data.compound.containsKey(name); + return data.hasKey(name); } @Override public boolean has(int index, Scriptable start) { - return data.array.size() > index; + return data.getArray().size() > index; } @Override @@ -88,7 +88,7 @@ public class ECMAData implements Scriptable { @Override public Object[] getIds() { - return data.compound.keySet().toArray(); + return data.getCompound().keySet().toArray(); } @Override diff --git a/embedding/java/src/org/uscxml/datamodel/ecmascript/ECMAEvent.java b/embedding/java/src/org/uscxml/datamodel/ecmascript/ECMAEvent.java index 58fff72..45d93b8 100644 --- a/embedding/java/src/org/uscxml/datamodel/ecmascript/ECMAEvent.java +++ b/embedding/java/src/org/uscxml/datamodel/ecmascript/ECMAEvent.java @@ -1,13 +1,12 @@ package org.uscxml.datamodel.ecmascript; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.mozilla.javascript.Scriptable; import org.uscxml.Data; import org.uscxml.Event; -import org.uscxml.ParamPair; -import org.uscxml.ParamPairVector; public class ECMAEvent implements Scriptable { @@ -19,17 +18,17 @@ public class ECMAEvent implements Scriptable { public ECMAEvent(Event event) { this.event = event; - - Data data = new Data(event.getData()); - - // insert params into event.data - ParamPairVector ppv = event.getParamPairs(); - for (int i = 0; i < ppv.size(); i++) { - ParamPair pp = ppv.get(i); - data.compound.put(pp.getFirst(), new Data(pp.getSecond())); + + // copy event params to data + Data data = event.getData(); + Map<String, List<Data>> params = event.getParams(); + for (String key : params.keySet()) { + for (Data param : params.get(key)) { + data.put(key, param); + } } - members.put("type", event.getEventType().toString()); + members.put("type", event.getEventType()); members.put("data", new ECMAData(data)); members.put("sendid", event.getSendId()); members.put("origin", event.getOrigin()); diff --git a/embedding/java/src/org/uscxml/datamodel/ecmascript/ECMAScriptDataModel.java b/embedding/java/src/org/uscxml/datamodel/ecmascript/ECMAScriptDataModel.java index 152f5e3..0b2b576 100644 --- a/embedding/java/src/org/uscxml/datamodel/ecmascript/ECMAScriptDataModel.java +++ b/embedding/java/src/org/uscxml/datamodel/ecmascript/ECMAScriptDataModel.java @@ -12,7 +12,6 @@ import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.Undefined; import org.uscxml.Data; import org.uscxml.DataModel; -import org.uscxml.DataNative; import org.uscxml.Event; import org.uscxml.Interpreter; import org.uscxml.StringList; @@ -45,20 +44,20 @@ public class ECMAScriptDataModel extends DataModel { ScriptableObject obj = (ScriptableObject) Context.toObject(s, scope); for (Object key : obj.getIds()) { - data.compound.put(Context.toString(key), + data.put(Context.toString(key), getScriptableAsData(obj.get(key))); } } } catch (ClassCastException e) { if (object instanceof Boolean) { - data.atom = (Context.toBoolean(object) ? "true" : "false"); - data.type = Data.Type.INTERPRETED; + data.setAtom(Context.toBoolean(object) ? "true" : "false"); + data.setType(Data.Type.INTERPRETED); } else if (object instanceof String) { - data.atom = (String) object; - data.type = Data.Type.VERBATIM; + data.setAtom((String) object); + data.setType(Data.Type.VERBATIM); } else if (object instanceof Integer) { - data.atom = ((Integer) object).toString(); - data.type = Data.Type.INTERPRETED; + data.setAtom(((Integer) object).toString()); + data.setType(Data.Type.INTERPRETED); } else { throw new RuntimeException("Unhandled ECMA type " + object.getClass().getName()); @@ -102,9 +101,9 @@ public class ECMAScriptDataModel extends DataModel { Data ioProcs = new Data(); StringVector keys = interpreter.getIOProcessorKeys(); for (int i = 0; i < keys.size(); i++) { - ioProcs.compound.put(keys.get(i), new Data(interpreter + ioProcs.put(keys.get(i), interpreter .getIOProcessors().get(keys.get(i)) - .getDataModelVariables())); + .getDataModelVariables()); } newDM.scope .put("_ioprocessors", newDM.scope, new ECMAData(ioProcs)); @@ -115,9 +114,9 @@ public class ECMAScriptDataModel extends DataModel { Data invokers = new Data(); StringVector keys = interpreter.getInvokerKeys(); for (int i = 0; i < keys.size(); i++) { - invokers.compound.put(keys.get(i), new Data(interpreter + invokers.put(keys.get(i), interpreter .getInvokers().get(keys.get(i)) - .getDataModelVariables())); + .getDataModelVariables()); } newDM.scope .put("_ioprocessors", newDM.scope, new ECMAData(invokers)); @@ -176,7 +175,7 @@ public class ECMAScriptDataModel extends DataModel { } @Override - public DataNative getStringAsData(String content) { + public Data getStringAsData(String content) { if (debug) { System.out.println(interpreter.getName() + " getStringAsData"); } @@ -186,7 +185,7 @@ public class ECMAScriptDataModel extends DataModel { * JSON-like Data structure */ if (content.length() == 0) { - return Data.toNative(new Data()); + return new Data(); } // is it a json expression? @@ -194,7 +193,7 @@ public class ECMAScriptDataModel extends DataModel { Object json = NativeJSON.parse(ctx, scope, content, new NullCallable()); if (json != NativeJSON.NOT_FOUND) { - return Data.toNative(getScriptableAsData(json)); + return getScriptableAsData(json); } } catch (org.mozilla.javascript.EcmaError e) { System.err.println(e); @@ -207,7 +206,7 @@ public class ECMAScriptDataModel extends DataModel { x = ctx.evaluateString(scope, '"' + content + '"', "uscxml", 0, null); } - return Data.toNative(getScriptableAsData(x)); + return getScriptableAsData(x); } @Override diff --git a/embedding/java/src/org/uscxml/tests/TestData.java b/embedding/java/src/org/uscxml/tests/TestData.java index 44f1ce0..d1ebf20 100644 --- a/embedding/java/src/org/uscxml/tests/TestData.java +++ b/embedding/java/src/org/uscxml/tests/TestData.java @@ -1,7 +1,7 @@ package org.uscxml.tests; import org.uscxml.Data; -import org.uscxml.DataNative; +import org.uscxml.Event; public class TestData { @@ -9,15 +9,12 @@ public class TestData { System.load("/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava64.jnilib"); { Data data = Data.fromJSON("[1,2,3,4,5]"); - DataNative nData2 = Data.toNative(data); - Data data2 = new Data(nData2); - System.out.println(data2); + System.out.println(data); } { Data data = Data.fromJSON("{ \"foo\": \"bar\", \"faz\": 12 }"); - DataNative nData2 = Data.toNative(data); - Data data2 = new Data(nData2); - System.out.println(data2); + System.out.println(data); } + } } diff --git a/embedding/java/src/org/uscxml/tests/TestLifecycle.java b/embedding/java/src/org/uscxml/tests/TestLifecycle.java new file mode 100644 index 0000000..9278cbe --- /dev/null +++ b/embedding/java/src/org/uscxml/tests/TestLifecycle.java @@ -0,0 +1,124 @@ +package org.uscxml.tests; + +import org.uscxml.Interpreter; +import org.uscxml.InterpreterException; +import org.uscxml.InterpreterState; + +public class TestLifecycle { + public static void main(String[] args) { + System.load("/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava64.jnilib"); + + // syntactic xml parse error -> throws + try { + String xml = "<invalid"; + Interpreter interpreter = Interpreter.fromXML(xml); + throw new RuntimeException(""); + } catch (InterpreterException e) { + System.err.println(e); + } + + // semantic xml parse error -> throws + try { + String xml = "<invalid />"; + Interpreter interpreter = Interpreter.fromXML(xml); + if (interpreter.getState() != InterpreterState.USCXML_INSTANTIATED) throw new RuntimeException(""); + interpreter.step(); + throw new RuntimeException(""); + } catch (InterpreterException e) { + System.err.println(e); + } + + // request unknown datamodel -> throws + try { + String xml = + "<scxml datamodel=\"invalid\">" + + " <state id=\"start\">" + + " <transition target=\"done\" />" + + " </state>" + + " <final id=\"done\" />" + + "</scxml>"; + Interpreter interpreter = Interpreter.fromXML(xml); + if (interpreter.getState() != InterpreterState.USCXML_INSTANTIATED) throw new RuntimeException(""); + interpreter.step(); + throw new RuntimeException(""); + + } catch (InterpreterException e) { + System.err.println(e); + } + + try { + // two microsteps + String xml = + "<scxml>" + + " <state id=\"start\">" + + " <transition target=\"s2\" />" + + " </state>" + + " <state id=\"s2\">" + + " <transition target=\"done\" />" + + " </state>" + + " <final id=\"done\" />" + + "</scxml>"; + + Interpreter interpreter = Interpreter.fromXML(xml); + + if (interpreter.getState() != InterpreterState.USCXML_INSTANTIATED) throw new RuntimeException(""); + if (interpreter.step() != InterpreterState.USCXML_MICROSTEPPED) throw new RuntimeException(""); + if (interpreter.step() != InterpreterState.USCXML_MICROSTEPPED) throw new RuntimeException(""); + if (interpreter.step() != InterpreterState.USCXML_FINISHED) throw new RuntimeException(""); + + } catch (InterpreterException e) { + System.err.println(e); + } + + try { + // single macrostep, multiple runs + String xml = + "<scxml>" + + " <state id=\"start\">" + + " <transition target=\"done\" />" + + " </state>" + + " <final id=\"done\" />" + + "</scxml>"; + + Interpreter interpreter = Interpreter.fromXML(xml); + if (interpreter.getState() != InterpreterState.USCXML_INSTANTIATED) throw new RuntimeException(""); + if (interpreter.step() != InterpreterState.USCXML_MICROSTEPPED) throw new RuntimeException(""); + if (interpreter.step() != InterpreterState.USCXML_FINISHED) throw new RuntimeException(""); + interpreter.reset(); + + if (interpreter.getState() != InterpreterState.USCXML_INSTANTIATED) throw new RuntimeException(""); + if (interpreter.step() != InterpreterState.USCXML_MICROSTEPPED) throw new RuntimeException(""); + if (interpreter.step() != InterpreterState.USCXML_FINISHED) throw new RuntimeException(""); + + } catch (InterpreterException e) { + System.err.println(e); + } + + try { + // macrostep in between + String xml = + "<scxml>" + + " <state id=\"start\">" + + " <onentry>" + + " <send event=\"continue\" delay=\"2s\"/>" + + " </onentry>" + + " <transition target=\"s2\" event=\"continue\" />" + + " </state>" + + " <state id=\"s2\">" + + " <transition target=\"done\" />" + + " </state>" + + " <final id=\"done\" />" + + "</scxml>"; + + Interpreter interpreter = Interpreter.fromXML(xml); + if (interpreter.getState() != InterpreterState.USCXML_INSTANTIATED) throw new RuntimeException(""); + if (interpreter.step() != InterpreterState.USCXML_IDLE) throw new RuntimeException(""); + if (interpreter.step(true) != InterpreterState.USCXML_MACROSTEPPED) throw new RuntimeException(""); + if (interpreter.step() != InterpreterState.USCXML_MICROSTEPPED) throw new RuntimeException(""); + if (interpreter.step() != InterpreterState.USCXML_FINISHED) throw new RuntimeException(""); + + } catch (InterpreterException e) { + System.err.println(e); + } + } +} diff --git a/embedding/java/src/org/uscxml/tests/execContent/TestCustomExecContent.java b/embedding/java/src/org/uscxml/tests/execContent/TestCustomExecContent.java index 92d7ed3..7a97ab4 100644 --- a/embedding/java/src/org/uscxml/tests/execContent/TestCustomExecContent.java +++ b/embedding/java/src/org/uscxml/tests/execContent/TestCustomExecContent.java @@ -1,11 +1,9 @@ package org.uscxml.tests.execContent; -import org.uscxml.Data; -import org.uscxml.Event; +import org.uscxml.ExecutableContent; import org.uscxml.Factory; import org.uscxml.Interpreter; import org.uscxml.InterpreterException; -import org.uscxml.ExecutableContent; public class TestCustomExecContent extends ExecutableContent { diff --git a/embedding/java/src/org/uscxml/tests/invoker/TestCustomInvoker.java b/embedding/java/src/org/uscxml/tests/invoker/TestCustomInvoker.java index b17b52e..25420ed 100644 --- a/embedding/java/src/org/uscxml/tests/invoker/TestCustomInvoker.java +++ b/embedding/java/src/org/uscxml/tests/invoker/TestCustomInvoker.java @@ -1,7 +1,6 @@ package org.uscxml.tests.invoker; import org.uscxml.Data; -import org.uscxml.DataNative; import org.uscxml.Event; import org.uscxml.Factory; import org.uscxml.Interpreter; @@ -21,27 +20,29 @@ public class TestCustomInvoker extends Invoker { } @Override - public DataNative getDataModelVariables() { + public Data getDataModelVariables() { Data data = new Data(); - data.array.add(new Data("foo", Data.Type.VERBATIM)); - return Data.toNative(data); + return data; } @Override public void send(SendRequest req) { - System.out.println("send"); + System.out.println(req); + if ("foo".equals(req.getName())) + returnEvent(new Event("received2"), true); // enqueue an external event } @Override public void invoke(InvokeRequest req) { - System.out.println("invoke"); - - System.out.println(req.getData()); - System.out.println(req.getXML()); + System.out.println(req); + if ("Some string content".equals(req.getContent())) { + returnEvent(new Event("received1"), true); // enqueue an external event + } + } - Event ev = new Event(); - ev.setName("foo"); - returnEvent(ev); + @Override + public void uninvoke() { + System.out.println("uninvoke"); } @Override @@ -54,15 +55,35 @@ public class TestCustomInvoker extends Invoker { * @throws InterpreterException */ public static void main(String[] args) throws InterpreterException { - System.load("/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava64_d.jnilib"); + System.load("/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava64.jnilib"); TestCustomInvoker invoker = new TestCustomInvoker(); + // just register prototype at global factory Factory.getInstance().registerInvoker(invoker); - Interpreter interpreter = Interpreter - .fromURI("/Users/sradomski/Documents/TK/Code/uscxml/test/samples/uscxml/test-java-invoker.scxml"); - while (true) - interpreter.interpret(); + String xml = + "<scxml>" + + " <state id=\"s1\">" + + " <invoke type=\"java\" id=\"javainvoker1\">" + + " <content>Some string content</content>" + + " </invoke>" + + " <invoke type=\"java\" id=\"javainvoker2\" />" + + " <state id=\"s11\">" + + " <transition event=\"received1\" target=\"s12\" />" + + " </state>" + + " <state id=\"s12\">" + + " <onentry>" + + " <send target=\"#_javainvoker2\" event=\"foo\" />" + + " </onentry>" + + " <transition event=\"received2\" target=\"done\" />" + + " </state>" + + " </state>" + + " <final id=\"done\" />" + + "</scxml>"; + + // parse and interpret + Interpreter interpreter = Interpreter.fromXML(xml); + interpreter.interpret(); } } diff --git a/embedding/java/src/org/uscxml/tests/ioprocessor/TestCustomIOProc.java b/embedding/java/src/org/uscxml/tests/ioprocessor/TestCustomIOProc.java index cc4d332..277c505 100644 --- a/embedding/java/src/org/uscxml/tests/ioprocessor/TestCustomIOProc.java +++ b/embedding/java/src/org/uscxml/tests/ioprocessor/TestCustomIOProc.java @@ -1,16 +1,30 @@ package org.uscxml.tests.ioprocessor; +import java.io.IOException; +import java.io.StringReader; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + import org.uscxml.Data; -import org.uscxml.DataNative; +import org.uscxml.Event; import org.uscxml.Factory; import org.uscxml.IOProcessor; import org.uscxml.Interpreter; import org.uscxml.InterpreterException; import org.uscxml.SendRequest; import org.uscxml.StringList; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; public class TestCustomIOProc extends IOProcessor { + public Interpreter interpreter; + + /** + * The types we will handle on a <send> element + */ @Override public StringList getNames() { StringList ss = new StringList(); @@ -18,38 +32,111 @@ public class TestCustomIOProc extends IOProcessor { return ss; } + /** + * Optional data we want to make available at + * _ioprocessors[this.getNames.front()] in the datamodel + */ @Override - public DataNative getDataModelVariables() { - Data data = new Data(); - data.array.add(new Data("foo", Data.Type.VERBATIM)); - return Data.toNative(data); + public Data getDataModelVariables() { + return new Data(); } + /** + * Send from the SCXML interpreter to this ioprocessor + */ @Override public void send(SendRequest req) { - System.out.println("send"); + System.out.println(req); + // send in s1.onentry + if ("This is some content!".equals(req.getContent())) { + returnEvent(new Event("received1")); + return; + } + // send in s2.onentry + if (req.getParams().containsKey("foo") + && "bar".equals(req.getParams().get("foo").get(0).getAtom())) { + returnEvent(new Event("received2")); + return; + } + // send in s3 + if (req.getXML().length() > 0) { + try { + DocumentBuilderFactory factory = DocumentBuilderFactory + .newInstance(); + Document doc = factory.newDocumentBuilder().parse( + new InputSource(new StringReader(req.getXML()))); + System.out.println("Root element :" + + doc.getDocumentElement().getNodeName()); + if ("this".equals(doc.getDocumentElement().getNodeName())) { + returnEvent(new Event("received3")); + return; + } + } catch (ParserConfigurationException e) { + e.printStackTrace(); + } catch (SAXException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + /** + * Create a new instance of this + */ @Override public IOProcessor create(Interpreter interpreter) { - return new TestCustomIOProc(); + TestCustomIOProc ioProc = new TestCustomIOProc(); + ioProc.interpreter = interpreter; + return ioProc; } /** * @param args - * @throws InterpreterException + * @throws InterpreterException */ public static void main(String[] args) throws InterpreterException { - System.load("/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava64_d.jnilib"); + System.load("/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava64.jnilib"); TestCustomIOProc ioproc = new TestCustomIOProc(); + // just register prototype at global factory Factory.getInstance().registerIOProcessor(ioproc); - Interpreter interpreter = Interpreter - .fromURI("/Users/sradomski/Documents/TK/Code/uscxml/test/samples/uscxml/test-java-invoker.scxml"); - - while (true) - interpreter.interpret(); + String xml = + "<scxml>" + + " <state id=\"s1\">" + + " <onentry>" + + " <send type=\"java\">" + + " <content>This is some content!</content>" + + " </send>" + + " </onentry>" + + " <transition event=\"received1\" target=\"s2\" />" + + " </state>" + + " <state id=\"s2\">" + + " <onentry>" + + " <send type=\"java\">" + + " <param name=\"foo\" expr=\"bar\" />" + + " </send>" + + " </onentry>" + + " <transition event=\"received2\" target=\"s3\" />" + + " </state>" + + " <state id=\"s3\">" + + " <onentry>" + + " <send type=\"java\">" + + " <content>" + + " <this><is><xml/></is></this>" + + " </content>" + + " </send>" + + " </onentry>" + + " <transition event=\"received3\" target=\"done\" />" + + " </state>" + + " <final id=\"done\" />" + + "</scxml>"; + + // parse and interpret + Interpreter interpreter = Interpreter.fromXML(xml); + interpreter.interpret(); } } diff --git a/src/bindings/swig/csharp/org/uscxml/InterpreterException.cs b/src/bindings/swig/csharp/org/uscxml/InterpreterException.cs index f86dc0e..38430d8 100644 --- a/src/bindings/swig/csharp/org/uscxml/InterpreterException.cs +++ b/src/bindings/swig/csharp/org/uscxml/InterpreterException.cs @@ -1,5 +1,5 @@ namespace org.uscxml { - class InterpreterException : System.ApplicationException { + public class InterpreterException : System.ApplicationException { public InterpreterException(string message) : base(message) { } diff --git a/src/bindings/swig/csharp/uscxml.i b/src/bindings/swig/csharp/uscxml.i index 988c541..8e9a297 100644 --- a/src/bindings/swig/csharp/uscxml.i +++ b/src/bindings/swig/csharp/uscxml.i @@ -12,10 +12,19 @@ %include <boost_shared_ptr.i> +// these are needed at least for the templates to work typedef uscxml::Data Data; typedef uscxml::Event Event; typedef uscxml::InvokeRequest InvokeRequest; typedef uscxml::SendRequest SendRequest; +typedef uscxml::Invoker Invoker; +typedef uscxml::IOProcessor IOProcessor; +typedef uscxml::DataModel DataModel; +typedef uscxml::ExecutableContent ExecutableContent; +typedef uscxml::InvokerImpl InvokerImpl; +typedef uscxml::IOProcessorImpl IOProcessorImpl; +typedef uscxml::DataModelImpl DataModelImpl; +typedef uscxml::ExecutableContentImpl ExecutableContentImpl; %feature("director") uscxml::WrappedInvoker; %feature("director") uscxml::WrappedDataModel; @@ -54,6 +63,7 @@ typedef uscxml::SendRequest SendRequest; using namespace uscxml; using namespace Arabica::DOM; +// the wrapped* C++ classes get rid of DOM nodes and provide more easily wrapped base classes #include "../wrapped/WrappedInvoker.cpp" #include "../wrapped/WrappedDataModel.cpp" #include "../wrapped/WrappedExecutableContent.cpp" @@ -125,11 +135,139 @@ WRAP_THROW_EXCEPTION(uscxml::Interpreter::interpret); %include "../uscxml_ignores.i" -%rename Data DataNative; +//*********************************************** +// Beautify important classes +//*********************************************** %include "../uscxml_beautify.i" +%rename(getCompoundNative) uscxml::Data::getCompound(); +%rename(getArrayNative) uscxml::Data::getArray(); +%rename(setCompoundNative) uscxml::Data::setCompound(const std::map<std::string, Data>&); +%rename(setArrayNative) uscxml::Data::setArray(const std::list<Data>&); +%csmethodmodifiers uscxml::Data::getCompound() "private"; +%csmethodmodifiers uscxml::Data::getArray() "private"; +%csmethodmodifiers uscxml::Data::setCompound(const std::map<std::string, Data>&) "private"; +%csmethodmodifiers uscxml::Data::setArray(const std::list<Data>&) "private"; +%csmethodmodifiers uscxml::Data::getCompoundKeys() "private"; + +%typemap(csimports) uscxml::Data %{ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +%} + +%typemap(cscode) uscxml::Data %{ + public Data(List<Data> arr) : this() { + setArray(arr); + } + + public Data(Dictionary<string, Data> compound) : this() { + setCompound(compound); + } + + public Dictionary<string, Data> getCompound() { + Dictionary<string, Data> compound = new Dictionary<string, Data>(); + DataMap dataMap = getCompoundNative(); + StringVector dataMapKeys = getCompoundKeys(); + for (int i = 0; i < dataMapKeys.Count; i++) { + compound[dataMapKeys[i]] = dataMap[dataMapKeys[i]]; + } + return compound; + } + + public void setCompound(Dictionary<string, Data> compound) { + DataMap dataMap = new DataMap(); + foreach(KeyValuePair<string, Data> entry in compound) { + dataMap.Add(entry); + } + setCompoundNative(dataMap); + } + + public List<Data> getArray() { + List<Data> arr = new List<Data>(); + DataList dataList = getArrayNative(); + for (int i = 0; i < dataList.size(); i++) { + arr.Add(dataList.get(i)); + } + return arr; + } + + public void setArray(List<Data> arr) { + DataList dataList = new DataList(); + foreach (Data data in arr) { + dataList.add(data); + } + setArrayNative(dataList); + } + +%} + +%rename(getNameListNative) uscxml::Event::getNameList(); +%rename(getParamsNative) uscxml::Event::getParams(); +%rename(setNameListNative) uscxml::Event::setNameList(const std::map<std::string, Data>&); +%rename(setParamsNative) uscxml::Event::setParams(const std::multimap<std::string, Data>&); +%csmethodmodifiers uscxml::Event::getNameList() "private"; +%csmethodmodifiers uscxml::Event::getNameListKeys() "private"; +%csmethodmodifiers uscxml::Event::getParams() "private"; +%csmethodmodifiers uscxml::Event::setNameList(const std::map<std::string, Data>&) "private"; +%csmethodmodifiers uscxml::Event::setParams(const std::multimap<std::string, Data>&) "private"; + +%typemap(csimports) uscxml::Event %{ + using System; + using System.Collections.Generic; + using System.Runtime.InteropServices; +%} + +%typemap(cscode) uscxml::Event %{ + public Dictionary<string, List<Data> > getParams() { + Dictionary<string, List<Data>> parameters = new Dictionary<string, List<Data>>(); + ParamMap paramMap = getParamMap(); + + foreach (KeyValuePair<string, DataList> entry in paramMap) { + DataList dataList = entry.Value; + List<Data> paramList = new List<Data>(); + for (int i = 0; i < dataList.size(); i++) { + Data data = dataList.get(i); + paramList.Add(data); + } + parameters.Add(entry.Key, paramList); + } + return parameters; + } + + public void setParams(Dictionary<string, List<Data>> parameters) { + ParamMap paramMap = new ParamMap(); + foreach(KeyValuePair<string, List<Data>> entry in parameters) { + DataList dataList = new DataList(); + foreach (Data data in entry.Value) { + dataList.add(data); + } + paramMap.Add(entry.Key, dataList); + } + setParamMap(paramMap); + } + + public Dictionary<string, Data> getNameList() { + Dictionary<string, Data> nameList = new Dictionary<string, Data>(); + DataMap nameListMap = getNameListNative(); + StringVector nameListMapKeys = getNameListKeys(); + for (int i = 0; i < nameListMapKeys.Count; i++) { + nameList[nameListMapKeys[i]] = nameListMap[nameListMapKeys[i]]; + } + return nameList; + } + + public void setNameList(Dictionary<string, Data> nameList) { + DataMap dataMap = new DataMap(); + foreach (KeyValuePair<string, Data> entry in nameList) { + dataMap.Add(entry); + } + setNameListNative(dataMap); + } +%} + //*********************************************** // Parse the header file to generate wrappers //*********************************************** @@ -164,8 +302,7 @@ WRAP_THROW_EXCEPTION(uscxml::Interpreter::interpret); %template(StringSet) std::set<std::string>; %template(StringVector) std::vector<std::string>; %template(StringList) std::list<std::string>; -%template(ParamPair) std::pair<std::string, uscxml::Data>; -%template(ParamPairVector) std::vector<std::pair<std::string, uscxml::Data> >; -%template(IOProcMap) std::map<std::string, uscxml::IOProcessor>; -%template(InvokerMap) std::map<std::string, uscxml::Invoker>; +%template(ParamMap) std::map<std::string, std::list<uscxml::Data> >; +%template(IOProcMap) std::map<std::string, IOProcessor>; +%template(InvokerMap) std::map<std::string, Invoker>; %template(ParentQueue) uscxml::concurrency::BlockingQueue<uscxml::SendRequest>; diff --git a/src/bindings/swig/java/org/uscxml/Data.java b/src/bindings/swig/java/org/uscxml/Data.java deleted file mode 100644 index 7781f47..0000000 --- a/src/bindings/swig/java/org/uscxml/Data.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.uscxml; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public class Data { - public Map<String, Data> compound = new HashMap<String, Data>(); - public List<Data> array = new LinkedList<Data>(); - public String atom; - public Type type = Type.INTERPRETED; - - public enum Type { - VERBATIM, INTERPRETED - } - - public static Data fromJSON(String jsonString) { - return new Data(DataNative.fromJSON(jsonString)); - } - - public Data() { - } - - public Data(String atom, Data.Type type) { - this.atom = atom; - this.type = type; - } - - public Data(DataNative nativeData) { - if (!nativeData.getCompound().empty()) { - // data is a key value compound - StringVector keys = nativeData.getCompundKeys(); - for(int i = 0; i < keys.size(); i++) { - this.compound.put(keys.get(i), new Data(nativeData.getCompound().get(keys.get(i)))); - } - } else if (!nativeData.getArray().isEmpty()) { - // data is an array - for (int i = 0; i < nativeData.getArray().size(); i++) { - this.array.add(new Data(nativeData.getArray().get(i))); - } - } else { - // data is a single atom - this.atom = nativeData.getAtom(); - if (nativeData.getType() == DataNative.Type.INTERPRETED) { - this.type = Type.INTERPRETED; - } else { - this.type = Type.VERBATIM; - } - } - } - - @Override - public String toString() { - return toJSON(); - } - - public String toJSON() { - DataNative nativeData = toNative(this); - return DataNative.toJSON(nativeData); - } - - public static DataNative toNative(Data data) { - DataNative nativeData = new DataNative(); - //nativeData.swigCMemOwn = false; - if (data.compound != null && !data.compound.isEmpty()) { - DataMap nativeDataMap = new DataMap(); - for (String key : data.compound.keySet()) { - nativeDataMap.set(key, toNative(data.compound.get(key))); - } - nativeData.setCompound(nativeDataMap); - } else if (data.array != null && !data.array.isEmpty()) { - DataList nativeDataList = new DataList(); - for (Data item : data.array) { - nativeDataList.add(toNative(item)); - } - nativeData.setArray(nativeDataList); - } else if (data.atom != null) { - nativeData.setAtom(data.atom); - if (data.type == Type.INTERPRETED) { - nativeData.setType(DataNative.Type.INTERPRETED); - } else { - nativeData.setType(DataNative.Type.VERBATIM); - } - } - return nativeData; - } - -} diff --git a/src/bindings/swig/java/uscxml.i b/src/bindings/swig/java/uscxml.i index 880b02d..cb760e4 100644 --- a/src/bindings/swig/java/uscxml.i +++ b/src/bindings/swig/java/uscxml.i @@ -12,10 +12,19 @@ %include <boost_shared_ptr.i> +// these are needed at least for the templates to work typedef uscxml::Data Data; typedef uscxml::Event Event; typedef uscxml::InvokeRequest InvokeRequest; typedef uscxml::SendRequest SendRequest; +typedef uscxml::Invoker Invoker; +typedef uscxml::IOProcessor IOProcessor; +typedef uscxml::DataModel DataModel; +typedef uscxml::ExecutableContent ExecutableContent; +typedef uscxml::InvokerImpl InvokerImpl; +typedef uscxml::IOProcessorImpl IOProcessorImpl; +typedef uscxml::DataModelImpl DataModelImpl; +typedef uscxml::ExecutableContentImpl ExecutableContentImpl; %feature("director") uscxml::WrappedInvoker; %feature("director") uscxml::WrappedDataModel; @@ -33,7 +42,6 @@ typedef uscxml::SendRequest SendRequest; %rename(equals) operator==; %rename(isValid) operator bool; - //************************************************** // This ends up in the generated wrapper code //************************************************** @@ -54,6 +62,7 @@ typedef uscxml::SendRequest SendRequest; using namespace uscxml; using namespace Arabica::DOM; +// the wrapped* C++ classes get rid of DOM nodes and provide more easily wrapped base classes #include "../wrapped/WrappedInvoker.cpp" #include "../wrapped/WrappedDataModel.cpp" #include "../wrapped/WrappedExecutableContent.cpp" @@ -86,11 +95,202 @@ WRAP_THROW_EXCEPTION(uscxml::Interpreter::interpret); %include "../uscxml_ignores.i" -%rename Data DataNative; +// see http://swig.org/Doc2.0/Java.html#Java_date_marshalling +%define BEAUTIFY_NATIVE( MATCH, WRAPPER, NATIVE ) + +%rename WRAPPER NATIVE; + +%typemap(jstype) const MATCH & "WRAPPER" +%typemap(jstype) MATCH "WRAPPER" + +%typemap(javain, + pre=" NATIVE temp$javainput = $javainput.toNative();", + pgcppname="temp$javainput") const MATCH & + "$javaclassname.getCPtr(temp$javainput)" + + %typemap(javain, + pre=" NATIVE temp$javainput = $javainput.toNative();", + pgcppname="temp$javainput") MATCH + "$javaclassname.getCPtr(temp$javainput)" + +%typemap(javaout) const MATCH & { + NATIVE nativeData = new NATIVE($jnicall, $owner); + return new WRAPPER(nativeData); +} + +%typemap(javaout) MATCH { + NATIVE nativeData = new NATIVE($jnicall, $owner); + return new WRAPPER(nativeData); +} + +%typemap(javadirectorout) MATCH "NATIVE.getCPtr($javacall.toNative())" + +%typemap(javadirectorin) MATCH "WRAPPER.fromNative(new NATIVE($jniinput, false))"; +%typemap(javadirectorin) const MATCH & "WRAPPER.fromNative(new NATIVE($jniinput, false))"; + +%typemap(directorin,descriptor="L/org/uscxml/"##"WRAPPER;") const MATCH & "*(MATCH **)&$input = (MATCH *) &$1;" + +%typemap(directorout) MATCH ($&1_type argp) +%{ argp = *($&1_ltype*)&$input; + if (!argp) { + SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "Unexpected null return for type $1_type"); + return $null; + } + $result = *argp; %} + +%enddef + +/* +// not used as it will not work for directors :( +BEAUTIFY_NATIVE(uscxml::Data, Data, DataNative); +BEAUTIFY_NATIVE(uscxml::Event, Event, EventNative); +BEAUTIFY_NATIVE(uscxml::SendRequest, SendRequest, SendRequestNative); +BEAUTIFY_NATIVE(uscxml::InvokeRequest, InvokeRequest, InvokeRequestNative); +*/ + + +//*********************************************** +// Beautify important classes +//*********************************************** %include "../uscxml_beautify.i" +%rename(getCompoundNative) uscxml::Data::getCompound(); +%rename(getArrayNative) uscxml::Data::getArray(); +%rename(setCompoundNative) uscxml::Data::setCompound(const std::map<std::string, Data>&); +%rename(setArrayNative) uscxml::Data::setArray(const std::list<Data>&); +%javamethodmodifiers uscxml::Data::getCompound() "private"; +%javamethodmodifiers uscxml::Data::getArray() "private"; +%javamethodmodifiers uscxml::Data::setCompound(const std::map<std::string, Data>&) "private"; +%javamethodmodifiers uscxml::Data::setArray(const std::list<Data>&) "private"; +%javamethodmodifiers uscxml::Data::getCompoundKeys() "private"; + +%typemap(javaimports) uscxml::Data %{ +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.LinkedList; +%} + +%typemap(javacode) uscxml::Data %{ + public Data(Map<String, Data> compound) { + this(uscxmlNativeJavaJNI.new_Data__SWIG_0(), true); + setCompound(compound); + } + + public Data(List<Data> array) { + this(uscxmlNativeJavaJNI.new_Data__SWIG_0(), true); + setArray(array); + } + + public Map<String, Data> getCompound() { + Map<String, Data> compound = new HashMap<String, Data>(); + DataMap dataMap = getCompoundNative(); + StringVector dataMapKeys = getCompoundKeys(); + for (int i = 0; i < dataMapKeys.size(); i++) { + compound.put(dataMapKeys.get(i), dataMap.get(dataMapKeys.get(i))); + } + return compound; + } + + public void setCompound(Map<String, Data> compound) { + DataMap dataMap = new DataMap(); + for (String key : compound.keySet()) { + dataMap.set(key, compound.get(key)); + } + setCompoundNative(dataMap); + } + + public List<Data> getArray() { + List<Data> array = new LinkedList<Data>(); + DataList dataList = getArrayNative(); + for (int i = 0; i < dataList.size(); i++) { + array.add(dataList.get(i)); + } + return array; + } + + public void setArray(List<Data> array) { + DataList dataList = new DataList(); + for (Data data : array) { + dataList.add(data); + } + setArrayNative(dataList); + } + +%} + +%rename(getNameListNative) uscxml::Event::getNameList(); +%rename(getParamstNative) uscxml::Event::getParams(); +%rename(setNameListNative) uscxml::Event::setNameList(const std::map<std::string, Data>&); +%rename(setParamsNative) uscxml::Event::setParams(const std::multimap<std::string, Data>&); +%javamethodmodifiers uscxml::Event::getNameList() "private"; +%javamethodmodifiers uscxml::Event::getNameListKeys() "private"; +%javamethodmodifiers uscxml::Event::getParams() "private"; +%javamethodmodifiers uscxml::Event::setNameList(const std::map<std::string, Data>&) "private"; +%javamethodmodifiers uscxml::Event::setParams(const std::multimap<std::string, Data>&) "private"; + +%typemap(javaimports) uscxml::Event %{ +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.LinkedList; +%} + +%typemap(javacode) uscxml::Event %{ + public Map<String, List<Data>> getParams() { + Map<String, List<Data>> params = new HashMap<String, List<Data>>(); + ParamMap paramMap = getParamMap(); + StringVector paramMapKeys = getParamMapKeys(); + + for (int i = 0; i < paramMapKeys.size(); i++) { + String key = paramMapKeys.get(i); + DataList dataList = paramMap.get(key); + + for (int j = 0; j < dataList.size(); j++) { + Data data = dataList.get(j); + if (!params.containsKey(key)) + params.put(key, new LinkedList<Data>()); + params.get(key).add(data); + } + } + return params; + } + + public void setParams(Map<String, List<Data>> params) { + ParamMap paramMap = new ParamMap(); + for (String key : params.keySet()) { + DataList datalist = new DataList(); + for (Data data : params.get(key)) { + datalist.add(data); + } + paramMap.set(key, datalist); + } + setParamMap(paramMap); + } + + public Map<String, Data> getNameList() { + Map<String, Data> namelist = new HashMap<String, Data>(); + StringVector nameMapKeys = getNameListKeys(); + DataMap nameMap = getNameListNative(); + + for (int i = 0; i < nameMapKeys.size(); i++) { + namelist.put(nameMapKeys.get(i), nameMap.get(nameMapKeys.get(i))); + } + return namelist; + } + + public void setNameList(Map<String, Data> namelist) { + DataMap nameListMap = new DataMap(); + for (String key : namelist.keySet()) { + nameListMap.set(key, namelist.get(key)); + } + setNameListNative(nameListMap); + } +%} + + //*********************************************** // Parse the header file to generate wrappers //*********************************************** @@ -125,8 +325,7 @@ WRAP_THROW_EXCEPTION(uscxml::Interpreter::interpret); %template(StringSet) std::set<std::string>; %template(StringVector) std::vector<std::string>; %template(StringList) std::list<std::string>; -%template(ParamPair) std::pair<std::string, uscxml::Data>; -%template(ParamPairVector) std::vector<std::pair<std::string, uscxml::Data> >; -%template(IOProcMap) std::map<std::string, uscxml::IOProcessor>; -%template(InvokerMap) std::map<std::string, uscxml::Invoker>; +%template(ParamMap) std::map<std::string, std::list<uscxml::Data> >; +%template(IOProcMap) std::map<std::string, IOProcessor>; +%template(InvokerMap) std::map<std::string, Invoker>; %template(ParentQueue) uscxml::concurrency::BlockingQueue<uscxml::SendRequest>; diff --git a/src/bindings/swig/uscxml_beautify.i b/src/bindings/swig/uscxml_beautify.i index 8a53fbb..ac3ed44 100644 --- a/src/bindings/swig/uscxml_beautify.i +++ b/src/bindings/swig/uscxml_beautify.i @@ -9,15 +9,76 @@ %rename(NativeInterpreterMonitor) InterpreterMonitor; %rename(InterpreterMonitor) WrappedInterpreterMonitor; -%extend uscxml::Event { - std::vector<std::pair<std::string, Data> > getParamPairs() { - std::vector<std::pair<std::string, Data> > pairs; - std::multimap<std::string, Data>::iterator paramPairIter = self->getParams().begin(); +%extend uscxml::Event { +/* std::vector<std::pair<std::string, uscxml::Data> > getParamPairs() { + std::vector<std::pair<std::string, Data> > pairs; + std::multimap<std::string, Data>::iterator paramPairIter = self->getParams().begin(); + while(paramPairIter != self->getParams().end()) { + pairs.push_back(*paramPairIter); + paramPairIter++; + } + return pairs; + } + + void setParamPairs(const std::vector<std::pair<std::string, uscxml::Data> >& pairs) { + std::multimap<std::string, Data> params; + std::vector<std::pair<std::string, Data> >::const_iterator pairIter = pairs.begin(); + while(pairIter != pairs.end()) { + params.insert(std::make_pair(pairIter->first, pairIter->second)); + pairIter++; + } + self->setParams(params); + } +*/ + + std::string toString() { + std::stringstream ss; + ss << *self; + return ss.str(); + } + + std::map<std::string, std::list<uscxml::Data> > getParamMap() { + std::map<std::string, std::list<uscxml::Data> > paramMap; + std::multimap<std::string, Data>::const_iterator paramPairIter = self->getParams().begin(); while(paramPairIter != self->getParams().end()) { - pairs.push_back(*paramPairIter); + paramMap[paramPairIter->first].push_back(paramPairIter->second); paramPairIter++; } - return pairs; + return paramMap; + } + + std::vector<std::string> getParamMapKeys() { + std::vector<std::string> keys; + for(std::multimap<std::string, Data>::const_iterator iter = self->getParams().begin(); + iter != self->getParams().end(); + iter = self->getParams().upper_bound(iter->first)) { + keys.push_back(iter->first); + } + return keys; + } + + void setParamMap(const std::map<std::string, std::list<uscxml::Data> >& paramMap) { + std::multimap<std::string, Data> params; + std::map<std::string, std::list<uscxml::Data> >::const_iterator mapIter = paramMap.begin(); + while(mapIter != paramMap.end()) { + std::list<uscxml::Data>::const_iterator dataIter = mapIter->second.begin(); + while(dataIter != mapIter->second.end()) { + params.insert(std::make_pair(mapIter->first, *dataIter)); + dataIter++; + } + mapIter++; + } + self->setParams(params); + } + + std::vector<std::string> getNameListKeys() { + std::vector<std::string> keys; + std::map<std::string, Data>::const_iterator iter = self->getNameList().begin(); + while(iter != self->getNameList().end()) { + keys.push_back(iter->first); + iter++; + } + return keys; } }; @@ -66,7 +127,13 @@ }; %extend uscxml::Data { - std::vector<std::string> getCompundKeys() { + std::string toString() { + std::stringstream ss; + ss << *self; + return ss.str(); + } + + std::vector<std::string> getCompoundKeys() { std::vector<std::string> keys; std::map<std::string, Data>::const_iterator iter = self->compound.begin(); while(iter != self->compound.end()) { @@ -76,3 +143,19 @@ return keys; } }; + +%extend uscxml::SendRequest { + std::string toString() { + std::stringstream ss; + ss << *self; + return ss.str(); + } +}; + +%extend uscxml::InvokeRequest { + std::string toString() { + std::stringstream ss; + ss << *self; + return ss.str(); + } +};
\ No newline at end of file diff --git a/src/bindings/swig/uscxml_ignores.i b/src/bindings/swig/uscxml_ignores.i index c5bf88b..d54dae2 100644 --- a/src/bindings/swig/uscxml_ignores.i +++ b/src/bindings/swig/uscxml_ignores.i @@ -21,7 +21,6 @@ %ignore uscxml::EventHandler::getElement; %ignore uscxml::EventHandler::runOnMainThread; - %ignore uscxml::NameSpaceInfo::NameSpaceInfo(const std::map<std::string, std::string>&); %ignore uscxml::NameSpaceInfo::NameSpaceInfo(const NameSpaceInfo&); %ignore uscxml::NameSpaceInfo::setPrefix(Arabica::DOM::Element<std::string>); @@ -180,6 +179,11 @@ %ignore uscxml::Event::toDocument(); %ignore uscxml::Event::getParams(); %ignore uscxml::Event::getParam; +%ignore uscxml::Event::setParams; + +%ignore uscxml::SendRequest::fromXML; +%ignore uscxml::InvokeRequest::fromXML; + // Data diff --git a/src/bindings/swig/wrapped/WrappedDataModel.h b/src/bindings/swig/wrapped/WrappedDataModel.h index 013f22c..e1b29af 100644 --- a/src/bindings/swig/wrapped/WrappedDataModel.h +++ b/src/bindings/swig/wrapped/WrappedDataModel.h @@ -46,6 +46,7 @@ public: _interpreter = interpreter->shared_from_this(); return boost::shared_ptr<DataModelImpl>(create(_interpreter)); } + virtual std::list<std::string> getNames() { return std::list<std::string>(); }; diff --git a/src/bindings/swig/wrapped/WrappedExecutableContent.h b/src/bindings/swig/wrapped/WrappedExecutableContent.h index e00704a..b1ce4f9 100644 --- a/src/bindings/swig/wrapped/WrappedExecutableContent.h +++ b/src/bindings/swig/wrapped/WrappedExecutableContent.h @@ -72,11 +72,9 @@ public: } virtual void enterElement(const std::string& node) { - } virtual void exitElement(const std::string& node) { - } private: diff --git a/src/bindings/swig/wrapped/WrappedIOProcessor.h b/src/bindings/swig/wrapped/WrappedIOProcessor.h index 1d134dc..b4e4938 100644 --- a/src/bindings/swig/wrapped/WrappedIOProcessor.h +++ b/src/bindings/swig/wrapped/WrappedIOProcessor.h @@ -47,6 +47,7 @@ public: _interpreter = interpreter->shared_from_this(); return boost::shared_ptr<IOProcessorImpl>(create(_interpreter)); } + virtual std::list<std::string> getNames() { return std::list<std::string>(); }; diff --git a/src/bindings/swig/wrapped/WrappedInvoker.h b/src/bindings/swig/wrapped/WrappedInvoker.h index b3ff200..6251c6e 100644 --- a/src/bindings/swig/wrapped/WrappedInvoker.h +++ b/src/bindings/swig/wrapped/WrappedInvoker.h @@ -50,6 +50,7 @@ public: virtual void send(const SendRequest& req) {} virtual void invoke(const InvokeRequest& req) {} + virtual void uninvoke() {} virtual WrappedInvoker* create(Interpreter interpreter) { return new WrappedInvoker(); diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp index 3556aba..22482e6 100644 --- a/src/uscxml/Factory.cpp +++ b/src/uscxml/Factory.cpp @@ -516,7 +516,7 @@ boost::shared_ptr<InvokerImpl> Factory::createInvoker(const std::string& type, I if (_parentFactory) { return _parentFactory->createInvoker(type, interpreter); } else { - LOG(ERROR) << "No " << type << " Invoker known"; + ERROR_EXECUTION_THROW("No Invoker named '" + type + "' known"); } return boost::shared_ptr<InvokerImpl>(); @@ -538,7 +538,7 @@ boost::shared_ptr<DataModelImpl> Factory::createDataModel(const std::string& typ if (_parentFactory) { return _parentFactory->createDataModel(type, interpreter); } else { - LOG(ERROR) << "No " << type << " Datamodel known"; + ERROR_EXECUTION_THROW("No Datamodel name '" + type + "' known"); } return boost::shared_ptr<DataModelImpl>(); @@ -559,7 +559,7 @@ boost::shared_ptr<IOProcessorImpl> Factory::createIOProcessor(const std::string& if (_parentFactory) { return _parentFactory->createIOProcessor(type, interpreter); } else { - LOG(ERROR) << "No " << type << " IOProcessor known"; + ERROR_EXECUTION_THROW("No IOProcessor named '" + type + "' known"); } return boost::shared_ptr<IOProcessorImpl>(); @@ -578,7 +578,7 @@ boost::shared_ptr<ExecutableContentImpl> Factory::createExecutableContent(const if (_parentFactory) { return _parentFactory->createExecutableContent(localName, nameSpace, interpreter); } else { - LOG(ERROR) << "Executable content " << localName << " in " << actualNameSpace << " not available in factory"; + ERROR_EXECUTION_THROW("No Executable content name '" + localName + "' in namespace '" + actualNameSpace + "' known"); } return boost::shared_ptr<ExecutableContentImpl>(); @@ -654,51 +654,32 @@ Factory* Factory::getInstance() { } void EventHandlerImpl::returnErrorExecution(const std::string& cause) { - Event exceptionEvent; - exceptionEvent.data.compound["exception"] = Data(cause, Data::VERBATIM); - exceptionEvent.name = "error.execution"; - exceptionEvent.eventType = Event::PLATFORM; - returnEvent(exceptionEvent); + ERROR_EXECUTION(exc, cause); + returnEvent(exc); } -void EventHandlerImpl::returnErrorPlatform(const std::string& cause) { - Event exceptionEvent; - exceptionEvent.data.compound["exception"] = Data(cause, Data::VERBATIM); - exceptionEvent.name = "error.platform"; - exceptionEvent.eventType = Event::PLATFORM; - returnEvent(exceptionEvent); +void EventHandlerImpl::returnErrorCommunication(const std::string& cause) { + ERROR_COMMUNICATION(exc, cause); + returnEvent(exc); } -void EventHandlerImpl::returnEvent(Event& event) { +void EventHandlerImpl::returnEvent(Event& event, bool external) { if (event.invokeid.length() == 0) event.invokeid = _invokeId; if (event.eventType == 0) - event.eventType = Event::EXTERNAL; + event.eventType = (external ? Event::EXTERNAL : Event::INTERNAL); if (event.origin.length() == 0) event.origin = "#_" + _invokeId; if (event.origintype.length() == 0) event.origintype = _type; - - _interpreter->receive(event); -} - -void DataModelImpl::throwErrorExecution(const std::string& cause) { - uscxml::Event exc; - exc.data.compound["cause"] = uscxml::Data(cause, uscxml::Data::VERBATIM); - exc.name = "error.execution"; - exc.eventType = uscxml::Event::PLATFORM; - throw exc; -} - -void DataModelImpl::throwErrorPlatform(const std::string& cause) { - uscxml::Event exc; - exc.data.compound["cause"] = uscxml::Data(cause, uscxml::Data::VERBATIM); - exc.name = "error.platform"; - exc.eventType = uscxml::Event::PLATFORM; - throw exc; + + if (external) { + _interpreter->receive(event); + } else { + _interpreter->receiveInternal(event); + } } - Factory* Factory::_instance = NULL; std::string Factory::_defaultPluginPath; }
\ No newline at end of file diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 22fb79e..47a6182 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -83,6 +83,7 @@ #define VALID_FROM_MACROSTEPPED(newState) ( \ newState == USCXML_DESTROYED || \ newState == USCXML_MICROSTEPPED || \ + newState == USCXML_MACROSTEPPED || \ newState == USCXML_IDLE || \ newState == USCXML_FINISHED \ ) @@ -96,14 +97,7 @@ #define VALID_FROM_FINISHED(newState) ( \ newState == USCXML_DESTROYED || \ newState == USCXML_INSTANTIATED \ -) - -#define THROW_ERROR_PLATFORM(msg) \ - Event e; \ - e.name = "error.platform"; \ - e.data.compound["cause"] = Data(msg, Data::VERBATIM); \ - throw e; \ - +) /// macro to catch exceptions in executeContent #define CATCH_AND_DISTRIBUTE(msg) \ @@ -113,6 +107,7 @@ catch (Event e) {\ throw(e);\ } else {\ e.name = "error.execution";\ + e.data.compound["cause"] = uscxml::Data(msg, uscxml::Data::VERBATIM); \ e.eventType = Event::PLATFORM;\ receiveInternal(e);\ }\ @@ -120,11 +115,14 @@ catch (Event e) {\ #define CATCH_AND_DISTRIBUTE2(msg, node) \ catch (Event e) {\ - LOG(ERROR) << msg << " " << DOMUtils::xPathForNode(node) << ":" << std::endl << e << std::endl;\ + std::string xpathPos = DOMUtils::xPathForNode(node); \ + LOG(ERROR) << msg << " " << xpathPos << ":" << std::endl << e << std::endl;\ if (rethrow) {\ throw(e);\ } else {\ e.name = "error.execution";\ + e.data.compound["cause"] = uscxml::Data(msg, uscxml::Data::VERBATIM); \ + e.data.compound["xpath"] = uscxml::Data(xpathPos, uscxml::Data::VERBATIM); \ e.eventType = Event::PLATFORM;\ e.dom = node;\ receiveInternal(e);\ @@ -394,7 +392,7 @@ Interpreter Interpreter::fromURI(const std::string& uri) { URL absUrl(uri); if (!absUrl.isAbsolute()) { if (!absUrl.toAbsoluteCwd()) { - THROW_ERROR_PLATFORM("Given URL is not absolute or does not have file schema"); + ERROR_COMMUNICATION_THROW("URL is not absolute or does not have file schema"); } } @@ -416,7 +414,7 @@ Interpreter Interpreter::fromURI(const std::string& uri) { std::stringstream ss; ss << absUrl; if (absUrl.downloadFailed()) { - THROW_ERROR_PLATFORM("Downloading SCXML document from " + absUrl.asString() + " failed"); + ERROR_COMMUNICATION_THROW("Downloading SCXML document from '" + absUrl.asString() + "' failed"); } interpreter = fromXML(ss.str()); } @@ -426,7 +424,7 @@ Interpreter Interpreter::fromURI(const std::string& uri) { interpreter._impl->_baseURI = URL::asBaseURL(absUrl); interpreter._impl->_sourceURI = absUrl; } else { - THROW_ERROR_PLATFORM("Cannot create interpreter from URI " + absUrl.asString() + "'"); + ERROR_PLATFORM_THROW("Cannot create interpreter from URI '" + absUrl.asString() + "'"); } return interpreter; } @@ -454,9 +452,9 @@ Interpreter Interpreter::fromInputSource(Arabica::SAX::InputSource<std::string>& interpreterImpl->_document = parser.getDocument(); } else { if (parser.errorsReported()) { - THROW_ERROR_PLATFORM(parser.errors()) + ERROR_PLATFORM_THROW(parser.errors()) } else { - THROW_ERROR_PLATFORM("Failed to create interpreter"); + ERROR_PLATFORM_THROW("Failed to create interpreter"); // interpreterImpl->setInterpreterState(USCXML_FAULTED, parser.errors()); } } @@ -680,11 +678,13 @@ void InterpreterImpl::reset() { _internalQueue.clear(); _historyValue.clear(); + _currEvent = Event(); _alreadyEntered = NodeSet<std::string>(); _configuration = NodeSet<std::string>(); _topLevelFinalReached = false; _isInitialized = false; - + _stable = false; + setInterpreterState(USCXML_INSTANTIATED); } @@ -693,9 +693,7 @@ void InterpreterImpl::setupAndNormalizeDOM() { return; if (!_document) { - Event error("error.platform"); - error.data.compound["cause"] = Data("Interpreter has no DOM", Data::VERBATIM); - throw error; + ERROR_PLATFORM_THROW("Interpreter has no DOM"); } // find scxml element @@ -707,9 +705,7 @@ void InterpreterImpl::setupAndNormalizeDOM() { } if (scxmls.getLength() == 0) { - Event error("error.platform"); - error.data.compound["cause"] = Data("Cannot find SCXML element in DOM", Data::VERBATIM); - throw error; + ERROR_PLATFORM_THROW("Cannot find SCXML element in DOM"); } _scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0); @@ -777,12 +773,8 @@ void InterpreterImpl::init() { // instantiate datamodel if (HAS_ATTR(_scxml, "datamodel")) { + // might throw _dataModel = _factory->createDataModel(ATTR(_scxml, "datamodel"), this); - if (!_dataModel) { - Event e; - e.data.compound["cause"] = Data("Cannot instantiate datamodel", Data::VERBATIM); - throw e; - } } else { _dataModel = _factory->createDataModel("null", this); } @@ -1264,9 +1256,8 @@ void InterpreterImpl::delayedSend(void* userdata, std::string eventName) { * If the SCXML Processor does not support the type that is specified, it * must place the event error.execution on the internal event queue. */ - Event exceptionEvent("error.execution", Event::PLATFORM); -// exceptionEvent.sendid = sendReq.sendid; - INSTANCE->receiveInternal(exceptionEvent); + ERROR_EXECUTION(exc, "Unsupported type '" + sendReq.type + "' with send element"); + INSTANCE->receiveInternal(exc); } assert(INSTANCE->_sendIds.find(sendReq.sendid) != INSTANCE->_sendIds.end()); @@ -1372,7 +1363,12 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node<std::string>& element) { if (invokeReq.type.size() == 0) invokeReq.type = "http://www.w3.org/TR/scxml/"; - Invoker invoker(_factory->createInvoker(invokeReq.type, this)); + Invoker invoker; + try { + invoker = _factory->createInvoker(invokeReq.type, this); + } catch (Event e) { + receiveInternal(e); + } if (invoker) { tthread::lock_guard<tthread::recursive_mutex> lock(_pluginMutex); try { @@ -1439,7 +1435,7 @@ void InterpreterImpl::cancelInvoke(const Arabica::DOM::Node<std::string>& elemen } USCXML_MONITOR_CALLBACK3(beforeUninvoking, Element<std::string>(element), invokeId) - + _invokers[invokeId].uninvoke(); _invokers.erase(invokeId); USCXML_MONITOR_CALLBACK3(beforeUninvoking, Element<std::string>(element), invokeId) @@ -1689,8 +1685,7 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node<std::string>& cont try { if (!_dataModel.isDeclared(ATTR(content, "location"))) { // test 286, 331 - LOG(ERROR) << "Assigning to undeclared location '" << ATTR(content, "location") << "' not allowed." << std::endl; - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Assigning to undeclared location '" + ATTR(content, "location") + "' not allowed."); } else { Node<std::string> dom; std::string text; @@ -1745,7 +1740,7 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node<std::string>& cont try { _dataModel.eval((Element<std::string>)content, srcContent.str()); } - CATCH_AND_DISTRIBUTE("Syntax error while executing script element from '" << ATTR(content, "src") << "':") + CATCH_AND_DISTRIBUTE("Syntax error while executing script element from '" + ATTR(content, "src") + "':") } else { if (content.hasChildNodes()) { // search for the text node with the actual script @@ -1791,16 +1786,9 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node<std::string>& cont // --- Custom Executable Content ExecutableContent execContent; if (_executableContent.find(content) == _executableContent.end()) { - execContent = _factory->createExecutableContent(content.getLocalName(), content.getNamespaceURI(), this); - if (!execContent) { - LOG(ERROR) << "No custom executable content known for element '" - << content.getLocalName() << "' in namespace '" << content.getNamespaceURI() << "'"; - return; - } - _executableContent[content] = execContent; - } else { - execContent = _executableContent[content]; + _executableContent[content] = _factory->createExecutableContent(content.getLocalName(), content.getNamespaceURI(), this); } + execContent = _executableContent[content]; execContent.enterElement(content); if (execContent.processChildren()) { @@ -2005,13 +1993,8 @@ Arabica::DOM::Node<std::string> InterpreterImpl::getState(const std::string& sta if (target.size() > 0) goto FOUND; - LOG(ERROR) << "No state with id " << stateId << " found!"; { - Event ev; - ev.name = "error.execution"; - ev.eventType = Event::PLATFORM; - ev.data.compound["cause"] = Data("No state with id " + stateId + " found", Data::VERBATIM); - throw ev; + ERROR_EXECUTION_THROW("No state with id '" + stateId + "' found"); } FOUND: if (target.size() > 0) { @@ -2403,6 +2386,7 @@ void InterpreterImpl::setupIOProcessors() { continue; } + // this might throw error.execution _ioProcessors[ioProcIter->first] = _factory->createIOProcessor(ioProcIter->first, this); _ioProcessors[ioProcIter->first].setType(ioProcIter->first); _ioProcessors[ioProcIter->first].setInterpreter(this); diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index a07d9af..cf281b5 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -46,6 +46,11 @@ #include "uscxml/plugins/Invoker.h" #include "uscxml/plugins/ExecutableContent.h" +#define ERROR_PLATFORM_THROW(msg) \ + Event e; \ + e.name = "error.platform"; \ + e.data.compound["cause"] = Data(msg, Data::VERBATIM); \ + throw e; \ #define USCXML_MONITOR_CATCH(callback) \ diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp index aaf4cde..08135fd 100644 --- a/src/uscxml/URL.cpp +++ b/src/uscxml/URL.cpp @@ -364,19 +364,19 @@ const void URLImpl::download(bool blocking) { _condVar.wait(_mutex); // wait for notification } if (_hasFailed) { - Event exception; - exception.name = "error.communication"; - exception.data = URL(shared_from_this()); + ERROR_COMMUNICATION(exc, _error); + exc.data = URL(shared_from_this()); if (_error.length() > 0) - exception.data.compound["reason"] = Data(_error, Data::VERBATIM); - throw exception; + exc.data.compound["cause"] = Data(_error, Data::VERBATIM); + throw exc; } if (iequals(scheme(), "http")) { if (_statusCode.size() > 0 && boost::lexical_cast<int>(_statusCode) > 400) { - Event exception; - exception.name = "error.communication"; - exception.data = URL(shared_from_this()); - throw exception; + ERROR_COMMUNICATION(exc, _error); + exc.data = URL(shared_from_this()); + if (_error.length() > 0) + exc.data.compound["cause"] = Data(_error, Data::VERBATIM); + throw exc; } } } diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index dd23a87..048adf9 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -135,21 +135,23 @@ InterpreterState InterpreterDraft6::step(int waitForMS = 0) { NodeSet<std::string> initialTransitions = getDocumentInitialTransitions(); assert(initialTransitions.size() > 0); enterStates(initialTransitions); + setInterpreterState(USCXML_MICROSTEPPED); } - _stable = false; - // are there spontaneous transitions? - enabledTransitions = selectEventlessTransitions(); - if (!enabledTransitions.empty()) { - // test 403b - enabledTransitions.to_document_order(); - microstep(enabledTransitions); + if (!_stable) { + enabledTransitions = selectEventlessTransitions(); + if (!enabledTransitions.empty()) { + // test 403b + enabledTransitions.to_document_order(); + microstep(enabledTransitions); - setInterpreterState(USCXML_MICROSTEPPED); - return _state; + setInterpreterState(USCXML_MICROSTEPPED); + return _state; + } + _stable = true; } - + // test415 if (_topLevelFinalReached) goto EXIT_INTERPRETER; @@ -158,6 +160,7 @@ InterpreterState InterpreterDraft6::step(int waitForMS = 0) { if (!_internalQueue.empty()) { _currEvent = _internalQueue.front(); _internalQueue.pop_front(); + _stable = false; USCXML_MONITOR_CALLBACK2(beforeProcessingEvent, _currEvent) @@ -178,14 +181,15 @@ InterpreterState InterpreterDraft6::step(int waitForMS = 0) { } else { _stable = true; } - // even if we did nothing - count as microstep - setInterpreterState(USCXML_MICROSTEPPED); + + if (_state != USCXML_MACROSTEPPED && _state != USCXML_IDLE) + USCXML_MONITOR_CALLBACK(onStableConfiguration) + + setInterpreterState(USCXML_MACROSTEPPED); if (_topLevelFinalReached) goto EXIT_INTERPRETER; - setInterpreterState(USCXML_MACROSTEPPED); - USCXML_MONITOR_CALLBACK(onStableConfiguration) // when we reach a stable configuration, invoke for (unsigned int i = 0; i < _statesToInvoke.size(); i++) { @@ -227,7 +231,8 @@ InterpreterState InterpreterDraft6::step(int waitForMS = 0) { _currEvent = _externalQueue.pop(); _currEvent.eventType = Event::EXTERNAL; // make sure it is set to external - + _stable = false; + if (_topLevelFinalReached) goto EXIT_INTERPRETER; @@ -350,149 +355,6 @@ void InterpreterDraft6::stabilize() { } -#if 0 -void InterpreterDraft6::mainEventLoop() { - - while(_running) { - NodeSet<std::string> enabledTransitions; - _stable = false; - - // Here we handle eventless transitions and transitions - // triggered by internal events until machine is stable - while(_running && !_stable) { -#if VERBOSE - std::cout << "Configuration: "; - for (int i = 0; i < _configuration.size(); i++) { - std::cout << ATTR(_configuration[i], "id") << ", "; - } - std::cout << std::endl; -#endif - - enabledTransitions = selectEventlessTransitions(); - if (enabledTransitions.size() == 0) { - if (_internalQueue.size() == 0) { - _stable = true; - } else { - _currEvent = _internalQueue.front(); - _internalQueue.pop_front(); -#if VERBOSE - std::cout << "Received internal event " << _currEvent.name << std::endl; -#endif - - USCXML_MONITOR_CALLBACK(beforeProcessingEvent) - - if (_dataModel) - _dataModel.setEvent(_currEvent); - enabledTransitions = selectTransitions(_currEvent.name); - } - } - if (!enabledTransitions.empty()) { - // test 403b - enabledTransitions.to_document_order(); - microstep(enabledTransitions); - } - } - - for (unsigned int i = 0; i < _statesToInvoke.size(); i++) { - NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]); - for (unsigned int j = 0; j < invokes.size(); j++) { - if (!HAS_ATTR(invokes[j], "persist") || !DOMUtils::attributeIsTrue(ATTR(invokes[j], "persist"))) { - invoke(invokes[j]); - } - } - } - _statesToInvoke = NodeSet<std::string>(); - - if (!_internalQueue.empty()) - continue; - - // assume that we have a legal configuration as soon as the internal queue is empty - assert(hasLegalConfiguration()); - - USCXML_MONITOR_CALLBACK(onStableConfiguration) - - _mutex.unlock(); - - // whenever we have a stable configuration, run the mainThread hooks with 200fps - while(_externalQueue.isEmpty() && _thread == NULL) { - runOnMainThread(200); - } - _mutex.lock(); - - while(_externalQueue.isEmpty()) { - _condVar.wait(_mutex); - } - _currEvent = _externalQueue.pop(); -#if VERBOSE - std::cout << "Received externalEvent event " << _currEvent.name << std::endl; - if (_running && _currEvent.name == "unblock.and.die") { - std::cout << "Still running " << this << std::endl; - } else { - std::cout << "Aborting " << this << std::endl; - } -#endif - _currEvent.eventType = Event::EXTERNAL; // make sure it is set to external - if (!_running) - goto EXIT_INTERPRETER; - - USCXML_MONITOR_CALLBACK(beforeProcessingEvent) - - if (_dataModel && iequals(_currEvent.name, "cancel.invoke." + _sessionId)) - break; - - if (_dataModel) { - try { - _dataModel.setEvent(_currEvent); - } catch (Event e) { - LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl << _currEvent; - } - } - for (std::map<std::string, Invoker>::iterator invokeIter = _invokers.begin(); - invokeIter != _invokers.end(); - invokeIter++) { - if (iequals(invokeIter->first, _currEvent.invokeid)) { - Arabica::XPath::NodeSet<std::string> finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", invokeIter->second.getElement()); - for (int k = 0; k < finalizes.size(); k++) { - Element<std::string> finalizeElem = Element<std::string>(finalizes[k]); - executeContent(finalizeElem); - } - } - if (HAS_ATTR(invokeIter->second.getElement(), "autoforward") && DOMUtils::attributeIsTrue(ATTR(invokeIter->second.getElement(), "autoforward"))) { - try { - // do not autoforward to invokers that send to #_parent from the SCXML IO Processor! - // Yes do so, see test229! - // if (!boost::equals(_currEvent.getOriginType(), "http://www.w3.org/TR/scxml/#SCXMLEventProcessor")) - invokeIter->second.send(_currEvent); - } catch(...) { - LOG(ERROR) << "Exception caught while sending event to invoker " << invokeIter->first; - } - } - } - enabledTransitions = selectTransitions(_currEvent.name); - if (!enabledTransitions.empty()) { - // test 403b - enabledTransitions.to_document_order(); - microstep(enabledTransitions); - } - } - -EXIT_INTERPRETER: - USCXML_MONITOR_CALLBACK(beforeCompletion) - - exitInterpreter(); - if (_sendQueue) { - std::map<std::string, std::pair<InterpreterImpl*, SendRequest> >::iterator sendIter = _sendIds.begin(); - while(sendIter != _sendIds.end()) { - _sendQueue->cancelEvent(sendIter->first); - sendIter++; - } - } - - USCXML_MONITOR_CALLBACK(afterCompletion) - -} -#endif - Arabica::XPath::NodeSet<std::string> InterpreterDraft6::selectTransitions(const std::string& event) { Arabica::XPath::NodeSet<std::string> enabledTransitions; diff --git a/src/uscxml/messages/Data.h b/src/uscxml/messages/Data.h index bf13409..9b5bea7 100644 --- a/src/uscxml/messages/Data.h +++ b/src/uscxml/messages/Data.h @@ -141,6 +141,14 @@ public: return data; } + void put(std::string key, const Data& data) { + compound[key] = data; + } + + void put(size_t index, const Data& data) { + this[index] = data; + } + bool operator==(const Data &other) const { if (other.atom.size() != atom.size()) return false; diff --git a/src/uscxml/messages/Event.cpp b/src/uscxml/messages/Event.cpp index a3e6a20..f8a880f 100644 --- a/src/uscxml/messages/Event.cpp +++ b/src/uscxml/messages/Event.cpp @@ -155,6 +155,8 @@ std::ostream& operator<< (std::ostream& os, const Event& event) { os << indent << " origin: " << event.origin << std::endl; if (event.origintype.size() > 0) os << indent << " origintype: " << event.origintype << std::endl; + if (event.content.size() > 0) + os << indent << " content: '" << event.content << "'" << std::endl; if (event.params.size() > 0) { std::multimap<std::string, Data>::const_iterator paramIter = event.params.begin(); os << indent << " params:" << std::endl; diff --git a/src/uscxml/messages/Event.h b/src/uscxml/messages/Event.h index 1acfce7..6697bb9 100644 --- a/src/uscxml/messages/Event.h +++ b/src/uscxml/messages/Event.h @@ -22,6 +22,56 @@ #include "uscxml/messages/Data.h" +#define ERROR_EXECUTION(identifier, cause) \ + uscxml::Event identifier; \ + identifier.data.compound["cause"] = uscxml::Data(cause, uscxml::Data::VERBATIM); \ + identifier.name = "error.execution"; \ + identifier.eventType = uscxml::Event::PLATFORM; + +#define ERROR_EXECUTION2(identifier, cause, node) \ + uscxml::Event identifier; \ + identifier.data.compound["cause"] = uscxml::Data(cause, uscxml::Data::VERBATIM); \ + identifier.name = "error.execution"; \ + identifier.data.compound["xpath"] = uscxml::Data(DOMUtils::xPathForNode(node), uscxml::Data::VERBATIM); \ + identifier.eventType = uscxml::Event::PLATFORM; + +#define ERROR_COMMUNICATION(identifier, cause) \ + uscxml::Event identifier; \ + identifier.data.compound["cause"] = uscxml::Data(cause, uscxml::Data::VERBATIM); \ + identifier.name = "error.communication"; \ + identifier.eventType = uscxml::Event::PLATFORM; + +#define ERROR_COMMUNICATION2(identifier, cause, node) \ + uscxml::Event identifier; \ + identifier.data.compound["cause"] = uscxml::Data(cause, uscxml::Data::VERBATIM); \ + identifier.name = "error.communication"; \ + identifier.data.compound["xpath"] = uscxml::Data(DOMUtils::xPathForNode(node), uscxml::Data::VERBATIM); \ + identifier.eventType = uscxml::Event::PLATFORM; + +#define ERROR_EXECUTION_THROW(cause) \ +{\ + ERROR_EXECUTION(exc, cause); \ + throw exc;\ +} + +#define ERROR_EXECUTION_THROW2(cause, node) \ +{\ + ERROR_EXECUTION2(exc, cause, node); \ + throw exc;\ +} + +#define ERROR_COMMUNICATION_THROW(cause) \ +{\ + ERROR_COMMUNICATION(exc, cause); \ + throw exc;\ +} + +#define ERROR_COMMUNICATION_THROW2(cause, node) \ +{\ + ERROR_COMMUNICATION(exc, cause, node); \ + throw exc;\ +} + namespace uscxml { class USCXML_API Event { @@ -145,6 +195,13 @@ public: return params; } + void setNameList(const std::map<std::string, Data>& nameList) { + this->namelist = nameList; + } + void setParams(const std::multimap<std::string, Data>& params) { + this->params = params; + } + typedef std::multimap<std::string, Data> params_t; typedef std::map<std::string, Data> namelist_t; diff --git a/src/uscxml/messages/InvokeRequest.cpp b/src/uscxml/messages/InvokeRequest.cpp index a39c8c6..26d40ce 100644 --- a/src/uscxml/messages/InvokeRequest.cpp +++ b/src/uscxml/messages/InvokeRequest.cpp @@ -60,6 +60,7 @@ std::ostream& operator<< (std::ostream& os, const InvokeRequest& invokeReq) { if (invokeReq.src.size() > 0) os<< indent << " src: " << invokeReq.src << std::endl; +#if 0 if (invokeReq.namelist.size() > 0) { os << indent << " namelist: " << std::endl; InvokeRequest::namelist_t::const_iterator namelistIter = invokeReq.namelist.begin(); @@ -80,6 +81,7 @@ std::ostream& operator<< (std::ostream& os, const InvokeRequest& invokeReq) { if (invokeReq.content.size() > 0) os << indent << " content: " << invokeReq.content << std::endl; +#endif _dataIndentation++; os << (Event)invokeReq; diff --git a/src/uscxml/messages/SendRequest.cpp b/src/uscxml/messages/SendRequest.cpp index a8fbe13..497182c 100644 --- a/src/uscxml/messages/SendRequest.cpp +++ b/src/uscxml/messages/SendRequest.cpp @@ -103,7 +103,7 @@ std::ostream& operator<< (std::ostream& os, const SendRequest& sendReq) { if (sendReq.delayMs > 0) os<< indent << " delay: " << sendReq.delayMs << std::endl; - +#if 0 if (sendReq.namelist.size() > 0) { os << indent << " namelist: " << std::endl; SendRequest::namelist_t::const_iterator namelistIter = sendReq.namelist.begin(); @@ -124,7 +124,7 @@ std::ostream& operator<< (std::ostream& os, const SendRequest& sendReq) { if (sendReq.content.size() > 0) os << indent << " content: " << sendReq.content << std::endl; - +#endif _dataIndentation++; os << (Event)sendReq; _dataIndentation--; diff --git a/src/uscxml/plugins/DataModel.h b/src/uscxml/plugins/DataModel.h index 57d4b14..f142a60 100644 --- a/src/uscxml/plugins/DataModel.h +++ b/src/uscxml/plugins/DataModel.h @@ -86,10 +86,6 @@ public: return ""; } - static void throwErrorExecution(const std::string& cause); - static void throwErrorPlatform(const std::string& cause); - - // we need it public for various static functions protected: InterpreterImpl* _interpreter; }; diff --git a/src/uscxml/plugins/EventHandler.h b/src/uscxml/plugins/EventHandler.h index d30feb9..7b38575 100644 --- a/src/uscxml/plugins/EventHandler.h +++ b/src/uscxml/plugins/EventHandler.h @@ -62,9 +62,9 @@ public: virtual void send(const SendRequest& req) = 0; virtual void runOnMainThread() {}; - void returnEvent(Event& event); + void returnEvent(Event& event, bool external = false); void returnErrorExecution(const std::string&); - void returnErrorPlatform(const std::string&); + void returnErrorCommunication(const std::string&); protected: InterpreterImpl* _interpreter; diff --git a/src/uscxml/plugins/Invoker.h b/src/uscxml/plugins/Invoker.h index c967331..4a142e4 100644 --- a/src/uscxml/plugins/Invoker.h +++ b/src/uscxml/plugins/Invoker.h @@ -33,6 +33,7 @@ class USCXML_API InvokerImpl : public EventHandlerImpl { public: virtual ~InvokerImpl() {} virtual void invoke(const InvokeRequest& req) = 0; + virtual void uninvoke() {} virtual boost::shared_ptr<InvokerImpl> create(InterpreterImpl* interpreter) = 0; }; @@ -65,6 +66,10 @@ public: _impl->invoke(req); } + virtual void uninvoke() { + _impl->uninvoke(); + } + protected: boost::shared_ptr<InvokerImpl> _impl; }; diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp index b2fce62..6dc8c26 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp @@ -452,12 +452,7 @@ uint32_t JSCDataModel::getLength(const std::string& expr) { result = evalAsValue("(" + expr + ").length"); JSType type = JSValueGetType(_ctx, result); if (type == kJSTypeNull || type == kJSTypeUndefined) { - Event exceptionEvent; - exceptionEvent.data.compound["exception"] = Data("'" + expr + "' does not evaluate to an array.", Data::VERBATIM); - exceptionEvent.name = "error.execution"; - exceptionEvent.eventType = Event::PLATFORM; - - throw(exceptionEvent); + ERROR_EXECUTION_THROW("'" + expr + "' does not evaluate to an array."); } JSValueRef exception = NULL; @@ -549,20 +544,20 @@ void JSCDataModel::assign(const Element<std::string>& assignElem, } else if (HAS_ATTR(assignElem, "location")) { key = ATTR(assignElem, "location"); } - if (key.length() == 0) - throw Event("error.execution", Event::PLATFORM); - + if (key.length() == 0) { + ERROR_EXECUTION_THROW("Assign element has neither id nor location"); + } // flags on attribute are ignored? if (key.compare("_sessionid") == 0) // test 322 - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Cannot assign to _sessionId"); if (key.compare("_name") == 0) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Cannot assign to _name"); if (key.compare("_ioprocessors") == 0) // test 326 - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Cannot assign to _ioprocessors"); if (key.compare("_invokers") == 0) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Cannot assign to _invokers"); if (key.compare("_event") == 0) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Cannot assign to _event"); if (HAS_ATTR(assignElem, "expr")) { evalAsValue(key + " = " + ATTR(assignElem, "expr")); @@ -666,13 +661,7 @@ void JSCDataModel::handleException(JSValueRef exception) { JSStringRelease(exceptionStringRef); std::string exceptionMsg(buffer); - Event exceptionEvent; - exceptionEvent.data.compound["exception"] = Data(exceptionMsg, Data::VERBATIM); - exceptionEvent.name = "error.execution"; - exceptionEvent.eventType = Event::PLATFORM; - - throw(exceptionEvent); - + ERROR_EXECUTION_THROW(exceptionMsg); } JSValueRef JSCDataModel::jsPrint(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { diff --git a/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp index 98d2dda..45d7a5c 100644 --- a/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp +++ b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp @@ -65,7 +65,10 @@ void NULLDataModel::setEvent(const Event& event) { } Data NULLDataModel::getStringAsData(const std::string& content) { - Data data; + Data data = Data::fromJSON(content); + if (data.empty()) { + data = Data(content, Data::VERBATIM); + } return data; } diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp index ad0c42b..8f5e588 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp @@ -37,10 +37,7 @@ extern "C" { } #define RETHROW_PLEX_AS_EVENT \ catch (PlException plex) { \ - Event e; \ - e.name = "error.execution"; \ - e.data.compound["cause"] = (char*)plex; \ - throw e; \ + ERROR_EXECUTION_THROW((char*)plex); \ } \ #define PL_MODULE \ @@ -733,10 +730,7 @@ std::string SWIDataModel::evalAsString(const std::string& expr) { if (term.type() == PL_ATOM || term.type() == PL_CHARS || term.type() == PL_STRING) { return std::string(term); } else { - Event e; - e.name = "error.execution"; - e.data.compound["cause"] = (char*)plex; - throw e; + ERROR_EXECUTION_THROW((char*)plex); } } } diff --git a/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp b/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp index 8bfc39d..4300512 100644 --- a/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp +++ b/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp @@ -100,11 +100,11 @@ bool PromelaDataModel::validate(const std::string& location, const std::string& uint32_t PromelaDataModel::getLength(const std::string& expr) { if (!isDeclared(expr)) { - throwErrorExecution("Variable " + expr + " was not declared"); + ERROR_EXECUTION_THROW("Variable '" + expr + "' was not declared"); } if (!_variables[expr].hasKey("size")) { - throwErrorExecution("Variable " + expr + " is no array"); + ERROR_EXECUTION_THROW("Variable '" + expr + "' is no array"); } return strTo<int>(_variables[expr]["size"].atom); @@ -216,7 +216,7 @@ void PromelaDataModel::evaluateDecl(void* ast) { _variables.compound[name->value] = variable; } else { - throwErrorExecution("Declaring variables via " + PromelaParserNode::typeToDesc((*nameIter)->type) + " not implemented"); + ERROR_EXECUTION_THROW("Declaring variables via " + PromelaParserNode::typeToDesc((*nameIter)->type) + " not implemented"); } } assert(opIter == node->operands.end()); @@ -227,7 +227,7 @@ void PromelaDataModel::evaluateDecl(void* ast) { evaluateDecl(*declIter); } } else { - throwErrorExecution("Declaring variables via " + PromelaParserNode::typeToDesc(node->type) + " not implemented"); + ERROR_EXECUTION_THROW("Declaring variables via " + PromelaParserNode::typeToDesc(node->type) + " not implemented"); } } @@ -269,7 +269,7 @@ int PromelaDataModel::evaluateExpr(void* ast) { case PML_OR: return evaluateExpr(*opIter++) != 0 || evaluateExpr(*opIter++) != 0; default: - throwErrorExecution("Support for " + PromelaParserNode::typeToDesc(node->type) + " expressions not implemented"); + ERROR_EXECUTION_THROW("Support for " + PromelaParserNode::typeToDesc(node->type) + " expressions not implemented"); } return 0; } @@ -291,7 +291,7 @@ void PromelaDataModel::evaluateStmnt(void* ast) { break; } default: - throwErrorExecution("No support for " + PromelaParserNode::typeToDesc(node->type) + " statement implemented"); + ERROR_EXECUTION_THROW("No support for " + PromelaParserNode::typeToDesc(node->type) + " statement implemented"); } } @@ -306,15 +306,15 @@ void PromelaDataModel::setVariable(void* ast, int value) { int index = evaluateExpr(expr); if (_variables.compound.find(name->value) == _variables.compound.end()) { - throwErrorExecution("No variable " + name->value + " was declared"); + ERROR_EXECUTION_THROW("No variable " + name->value + " was declared"); } if (!_variables[name->value].hasKey("size")) { - throwErrorExecution("Variable " + name->value + " is no array"); + ERROR_EXECUTION_THROW("Variable " + name->value + " is no array"); } if (strTo<int>(_variables[name->value]["size"].atom) <= index) { - throwErrorExecution("Index " + toStr(index) + " in array " + name->value + "[" + _variables[name->value]["size"].atom + "] is out of bounds"); + ERROR_EXECUTION_THROW("Index " + toStr(index) + " in array " + name->value + "[" + _variables[name->value]["size"].atom + "] is out of bounds"); } _variables.compound[name->value].compound["value"][index] = Data(value, Data::VERBATIM); @@ -339,10 +339,10 @@ int PromelaDataModel::getVariable(void* ast) { switch(node->type) { case PML_NAME: if (_variables.compound.find(node->value) == _variables.compound.end()) { - throwErrorExecution("No variable " + node->value + " was declared"); + ERROR_EXECUTION_THROW("No variable " + node->value + " was declared"); } if (_variables[node->value].compound.find("size") != _variables[node->value].compound.end()) { - throwErrorExecution("Type error: Variable " + node->value + " is an array"); + ERROR_EXECUTION_THROW("Type error: Variable " + node->value + " is an array"); } return strTo<int>(_variables[node->value]["value"].atom); case PML_VAR_ARRAY: { @@ -351,20 +351,20 @@ int PromelaDataModel::getVariable(void* ast) { int index = evaluateExpr(expr); if (_variables.compound.find(name->value) == _variables.compound.end()) { - throwErrorExecution("No variable " + name->value + " was declared"); + ERROR_EXECUTION_THROW("No variable " + name->value + " was declared"); } if (!_variables[name->value].hasKey("size")) { - throwErrorExecution("Variable " + name->value + " is no array"); + ERROR_EXECUTION_THROW("Variable " + name->value + " is no array"); } if (strTo<int>(_variables[name->value]["size"].atom) <= index) { - throwErrorExecution("Index " + toStr(index) + " in array " + name->value + "[" + _variables[name->value]["size"].atom + "] is out of bounds"); + ERROR_EXECUTION_THROW("Index " + toStr(index) + " in array " + name->value + "[" + _variables[name->value]["size"].atom + "] is out of bounds"); } return strTo<int>(_variables.compound[name->value].compound["value"][index].atom); } default: - throwErrorExecution("Retrieving value of " + PromelaParserNode::typeToDesc(node->type) + " variable not implemented"); + ERROR_EXECUTION_THROW("Retrieving value of " + PromelaParserNode::typeToDesc(node->type) + " variable not implemented"); } return 0; } diff --git a/src/uscxml/plugins/datamodel/promela/PromelaParser.cpp b/src/uscxml/plugins/datamodel/promela/PromelaParser.cpp index cd3bbaf..d12b7fc 100644 --- a/src/uscxml/plugins/datamodel/promela/PromelaParser.cpp +++ b/src/uscxml/plugins/datamodel/promela/PromelaParser.cpp @@ -19,6 +19,7 @@ #include "PromelaParser.h" #include "parser/promela.tab.hpp" +#include "uscxml/messages/Event.h" #include <iostream> @@ -35,10 +36,7 @@ int promela_lex_destroy (void*); void promela_error (uscxml::PromelaParser* ctx, void* yyscanner, const char* err) { // mark as pending exception as we cannot throw from constructor and have the destructor called - uscxml::Event excEvent; - excEvent.data.compound["exception"] = uscxml::Data(err, uscxml::Data::VERBATIM); - excEvent.name = "error.execution"; - excEvent.eventType = uscxml::Event::PLATFORM; + ERROR_EXECUTION(excEvent, err); ctx->pendingException = excEvent; } @@ -53,12 +51,7 @@ PromelaParser::PromelaParser(const std::string& expr, Type expectedType) { if (type != expectedType) { std::stringstream ss; ss << "Promela syntax type mismatch: Expected " << typeToDesc(expectedType) << " but got " << typeToDesc(type); - - uscxml::Event excEvent; - excEvent.data.compound["exception"] = uscxml::Data(ss.str(), uscxml::Data::VERBATIM); - excEvent.name = "error.execution"; - excEvent.eventType = uscxml::Event::PLATFORM; - throw excEvent; + ERROR_EXECUTION_THROW(ss.str()); } } diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp index 4d9854b..5800f98 100644 --- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp @@ -296,9 +296,7 @@ uint32_t XPathDataModel::getLength(const std::string& expr) { return result.asNodeSet().size(); break; default: - Event exceptionEvent("error.execution", Event::PLATFORM); - exceptionEvent.data.compound["exception"] = Data("'" + expr + "' does not evaluate to an array.", Data::VERBATIM); - throw(exceptionEvent); + ERROR_EXECUTION_THROW("'" + expr + "' does not evaluate to an array."); } return 0; } @@ -326,7 +324,7 @@ void XPathDataModel::setForeach(const std::string& item, if (!isDeclared(item)) { if (!isValidIdentifier(item)) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Expression '" + item + "' not a valid identifier."); Element<std::string> container = _doc.createElement("data"); container.setAttribute("id", item); container.appendChild(arrayResult.asNodeSet()[iteration].cloneNode(true)); @@ -400,9 +398,9 @@ bool XPathDataModel::evalAsBool(const Arabica::DOM::Node<std::string>& node, con try { result = _xpath.evaluate_expr(expr, _doc); } catch(SyntaxException e) { - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW(e.what()); } catch(std::runtime_error e) { - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW(e.what()); } return result.asBool(); } @@ -413,9 +411,9 @@ std::string XPathDataModel::evalAsString(const std::string& expr) { try { result = _xpath.evaluate_expr(expr, _doc); } catch(SyntaxException e) { - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW(e.what()); } catch(std::runtime_error e) { - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW(e.what()); } switch (result.type()) { case STRING: @@ -440,7 +438,7 @@ std::string XPathDataModel::evalAsString(const std::string& expr) { break; } case ANY: - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Type ANY not supported to evaluate as string"); break; } return "undefined"; @@ -472,13 +470,13 @@ void XPathDataModel::assign(const Element<std::string>& assignElem, for (int i = 0; i < key.asNodeSet().size(); i++) { Node<std::string> node = key.asNodeSet()[i]; if (node == _varResolver.resolveVariable("", "_ioprocessors").asNodeSet()[0]) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Cannot assign _ioProcessors"); if (node == _varResolver.resolveVariable("", "_sessionid").asNodeSet()[0]) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Cannot assign _sessionid"); if (node == _varResolver.resolveVariable("", "_name").asNodeSet()[0]) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Cannot assign _name"); if (node == _varResolver.resolveVariable("", "_event").asNodeSet()[0]) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Cannot assign _event"); } } catch (Event e) {} } @@ -570,11 +568,11 @@ void XPathDataModel::init(const Element<std::string>& dataElem, } case Arabica::XPath::BOOL: case ANY: - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("expr evaluates to type ANY"); } _datamodel.appendChild(container); } catch (SyntaxException e) { - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW(e.what()); } } else { LOG(ERROR) << "data element has no content"; @@ -595,7 +593,7 @@ void XPathDataModel::assign(const XPathValue<std::string>& key, switch (key.type()) { case NODE_SET: if (key.asNodeSet().size() == 0) { - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("key for assign is empty nodeset"); } switch (value.type()) { case STRING: @@ -611,14 +609,14 @@ void XPathDataModel::assign(const XPathValue<std::string>& key, assign(key.asNodeSet(), value.asNodeSet(), assignElem); break; case ANY: - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Type ANY as key for assign not supported"); } break; case STRING: case Arabica::XPath::BOOL: case NUMBER: case ANY: - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Type ANY as key for assign not supported") break; } } @@ -637,7 +635,7 @@ void XPathDataModel::assign(const XPathValue<std::string>& key, case Arabica::XPath::BOOL: case NUMBER: case ANY: - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Type ANY as key for assign not supported") } } @@ -665,7 +663,7 @@ void XPathDataModel::assign(const NodeSet<std::string>& key, // addattribute: Add an attribute with the name specified by 'attr' // and value specified by 'expr' to the node specified by 'location'. if (!HAS_ATTR(assignElem, "attr")) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Assign element is missing 'attr'") element.setAttribute(ATTR(assignElem, "attr"), value); } else { /// test 547 @@ -677,7 +675,7 @@ void XPathDataModel::assign(const NodeSet<std::string>& key, break; } default: - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Unsupported node type with assign"); break; } } @@ -709,7 +707,7 @@ void XPathDataModel::assign(const NodeSet<std::string>& key, break; default: // std::cout << key[i].getNodeType() << std::endl; - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Unsupported node type for assign"); break; } } @@ -740,7 +738,7 @@ void XPathDataModel::assign(const Element<std::string>& key, // node specified by 'location', keeping the same parent. Node<std::string> parent = element.getParentNode(); if (!parent) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Node has no parent"); for (int i = 0; i < value.size(); i++) { Node<std::string> importedNode = (value[i].getOwnerDocument() == _doc ? value[i].cloneNode(true) : _doc.importNode(value[i], true)); parent.insertBefore(importedNode, element); @@ -750,7 +748,7 @@ void XPathDataModel::assign(const Element<std::string>& key, // specified by 'location', keeping the same parent. Node<std::string> parent = element.getParentNode(); if (!parent) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Node has no parent"); for (int i = value.size(); i; i--) { Node<std::string> importedNode = (value[i-1].getOwnerDocument() == _doc ? value[i-1].cloneNode(true) : _doc.importNode(value[i-1], true)); Node<std::string> nextSibling = element.getNextSibling(); @@ -764,16 +762,16 @@ void XPathDataModel::assign(const Element<std::string>& key, // replace: Replace the node specified by 'location' by the value specified by 'expr'. Node<std::string> parent = element.getParentNode(); if (!parent) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Node has no parent"); if (value.size() != 1) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Value not singular"); Node<std::string> importedNode = (value[0].getOwnerDocument() == _doc ? value[0].cloneNode(true) : _doc.importNode(value[0], true)); parent.replaceChild(importedNode, element); } else if (assignElem && HAS_ATTR(assignElem, "type") && iequals(ATTR(assignElem, "type"), "delete")) { // delete: Delete the node specified by 'location'. ('expr' is ignored.). Node<std::string> parent = element.getParentNode(); if (!parent) - throw Event("error.execution", Event::PLATFORM); + ERROR_EXECUTION_THROW("Node has no parent"); parent.removeChild(element); } else { // replacechildren: Replace all the children at 'location' with the value specified by 'expr'. @@ -791,7 +789,7 @@ NodeSetVariableResolver::resolveVariable(const std::string& namepaceUri, const std::string& name) const { std::map<std::string, NodeSet<std::string> >::const_iterator n = _variables.find(name); if(n == _variables.end()) { - throw Event("error.execution"); + ERROR_EXECUTION_THROW("No varable named '" + name + "'"); } #if VERBOSE std::cout << std::endl << "Getting " << name << ":" << std::endl; diff --git a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp index 5ee7357..bd62467 100644 --- a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp @@ -157,7 +157,7 @@ bool BasicHTTPIOProcessor::httpRecvRequest(const HTTPServer::Request& req) { if (reqEvent.name.length() == 0) reqEvent.name = "http." + req.data.compound.at("type").atom; - returnEvent(reqEvent); + returnEvent(reqEvent, true); evhttp_send_reply(req.evhttpReq, 200, "OK", NULL); return true; } @@ -287,7 +287,7 @@ void BasicHTTPIOProcessor::downloadCompleted(const URL& url) { Event event; event.data = url; event.name = "HTTP." + statusPrefix + "." + statusRest; - returnEvent(event); +// returnEvent(event); } _sendRequests.erase(reqIter); return; diff --git a/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp index becc00a..00b47f4 100644 --- a/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp @@ -129,10 +129,10 @@ void SCXMLIOProcessor::send(const SendRequest& req) { boost::shared_ptr<InterpreterImpl> other = instances[sessionId].lock(); other->receive(reqCopy); } else { - LOG(ERROR) << "Can not send to scxml session " << sessionId << " - not known" << std::endl; - Event error("error.communication", Event::PLATFORM); + ERROR_COMMUNICATION(error, "Can not send to scxml session " + sessionId + " - not known"); error.sendid = reqCopy.sendid; _interpreter->receiveInternal(error); + } } else if (iequals(reqCopy.target, "#_parent")) { /** @@ -143,8 +143,7 @@ void SCXMLIOProcessor::send(const SendRequest& req) { if (_interpreter->_parentQueue != NULL) { _interpreter->_parentQueue->push(reqCopy); } else { - LOG(ERROR) << "Can not send to parent, we were not invoked" << std::endl; - Event error("error.communication", Event::PLATFORM); + ERROR_COMMUNICATION(error, "Can not send to parent, we were not invoked or no parent queue is set"); error.sendid = reqCopy.sendid; _interpreter->receiveInternal(error); } @@ -167,8 +166,7 @@ void SCXMLIOProcessor::send(const SendRequest& req) { LOG(ERROR) << "Exception caught while sending event to invoker " << invokeId; } } else { - LOG(ERROR) << "Can not send to invoked component '" << invokeId << "', no such invokeId" << std::endl; - Event error("error.communication", Event::PLATFORM); + ERROR_COMMUNICATION(error, "Can not send to invoked component '" + invokeId + "', no such invokeId"); error.sendid = reqCopy.sendid; _interpreter->receiveInternal(error); } @@ -177,8 +175,7 @@ void SCXMLIOProcessor::send(const SendRequest& req) { if (target.isAbsolute()) { BasicHTTPIOProcessor::send(reqCopy); } else { - LOG(ERROR) << "Not sure what to make of the target '" << reqCopy.target << "' - raising error" << std::endl; - Event error("error.execution", Event::PLATFORM); + ERROR_EXECUTION(error, "Not sure what to make of the target '" + reqCopy.target + "' - raising error"); error.sendid = reqCopy.sendid; // test 159 still fails // _interpreter->receiveInternal(error); diff --git a/src/uscxml/transform/ChartToFSM.cpp b/src/uscxml/transform/ChartToFSM.cpp index 3bce169..fea97d8 100644 --- a/src/uscxml/transform/ChartToFSM.cpp +++ b/src/uscxml/transform/ChartToFSM.cpp @@ -972,9 +972,7 @@ GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet<std::string>& t for (int i = 0; i < transitions.size(); i++) { if (HAS_ATTR(transitions[i], "eventexpr")) { - Event e("error.execution", Event::PLATFORM); - e.data.compound["cause"] = "Cannot flatten document with eventexpr attributes"; - throw e; + ERROR_EXECUTION_THROW("Cannot flatten document with eventexpr attributes"); } if (HAS_ATTR(transitions[i], "event")) { foundWithEvent = true; diff --git a/test/src/test-lifecycle.cpp b/test/src/test-lifecycle.cpp index 4c044c4..c0fb55c 100644 --- a/test/src/test-lifecycle.cpp +++ b/test/src/test-lifecycle.cpp @@ -88,8 +88,115 @@ void customTerminate() { #endif abort(); } + +using namespace uscxml; + +enum CallbackType { + USCXML_BEFOREPROCESSINGEVENT, + USCXML_BEFOREMICROSTEP, + USCXML_BEFOREEXITINGSTATE, + USCXML_AFTEREXITINGSTATE, + USCXML_BEFOREEXECUTINGCONTENT, + USCXML_AFTEREXECUTINGCONTENT, + USCXML_BEFOREUNINVOKING, + USCXML_AFTERUNINVOKING, + USCXML_BEFORETAKINGTRANSITION, + USCXML_AFTERTAKINGTRANSITION, + USCXML_BEFOREENTERINGSTATE, + USCXML_AFTERENTERINGSTATE, + USCXML_BEFOREINVOKING, + USCXML_AFTERINVOKING, + USCXML_AFTERMICROSTEP, + USCXML_ONSTABLECONFIGURATION, + USCXML_BEFORECOMPLETION, + USCXML_AFTERCOMPLETION +}; + +std::list<CallbackType> callBackSeq; + +#define CHECK_CALLBACK_TYPE(type)\ +{\ + assert(!callBackSeq.empty());\ + assert(callBackSeq.front() == type);\ + callBackSeq.pop_front();\ +} + + +class SequenceCheckingMonitor : public InterpreterMonitor { + virtual void beforeProcessingEvent(Interpreter interpreter, const Event& event) { + CHECK_CALLBACK_TYPE(USCXML_BEFOREPROCESSINGEVENT); + } + virtual void beforeMicroStep(Interpreter interpreter) { + CHECK_CALLBACK_TYPE(USCXML_BEFOREMICROSTEP); + } + + virtual void beforeExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) { + if (!moreComing) + CHECK_CALLBACK_TYPE(USCXML_BEFOREEXITINGSTATE); + } + virtual void afterExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) { + if (!moreComing) + CHECK_CALLBACK_TYPE(USCXML_AFTEREXITINGSTATE); + } + + virtual void beforeExecutingContent(Interpreter interpreter, const Arabica::DOM::Element<std::string>& element) { + CHECK_CALLBACK_TYPE(USCXML_BEFOREEXECUTINGCONTENT); + } + virtual void afterExecutingContent(Interpreter interpreter, const Arabica::DOM::Element<std::string>& element) { + CHECK_CALLBACK_TYPE(USCXML_AFTEREXECUTINGCONTENT); + } + + virtual void beforeUninvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) { + CHECK_CALLBACK_TYPE(USCXML_BEFOREUNINVOKING); + } + virtual void afterUninvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) { + CHECK_CALLBACK_TYPE(USCXML_AFTERUNINVOKING); + } + + virtual void beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, bool moreComing) { + if (!moreComing) + CHECK_CALLBACK_TYPE(USCXML_BEFORETAKINGTRANSITION); + } + virtual void afterTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, bool moreComing) { + if (!moreComing) + CHECK_CALLBACK_TYPE(USCXML_AFTERTAKINGTRANSITION); + } + + virtual void beforeEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) { + if (!moreComing) + CHECK_CALLBACK_TYPE(USCXML_BEFOREENTERINGSTATE); + } + virtual void afterEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) { + if (!moreComing) + CHECK_CALLBACK_TYPE(USCXML_AFTERENTERINGSTATE); + } + + virtual void beforeInvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) { + CHECK_CALLBACK_TYPE(USCXML_BEFOREINVOKING); + } + virtual void afterInvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) { + CHECK_CALLBACK_TYPE(USCXML_AFTERINVOKING); + } + + virtual void afterMicroStep(Interpreter interpreter) { + CHECK_CALLBACK_TYPE(USCXML_AFTERMICROSTEP); + } + + virtual void onStableConfiguration(Interpreter interpreter) { + CHECK_CALLBACK_TYPE(USCXML_ONSTABLECONFIGURATION); + } + + virtual void beforeCompletion(Interpreter interpreter) { + CHECK_CALLBACK_TYPE(USCXML_BEFORECOMPLETION); + } + virtual void afterCompletion(Interpreter interpreter) { + CHECK_CALLBACK_TYPE(USCXML_AFTERCOMPLETION); + } + +}; + + int main(int argc, char** argv) { - using namespace uscxml; std::set_terminate(customTerminate); @@ -99,80 +206,213 @@ int main(int argc, char** argv) { google::InitGoogleLogging(argv[0]); google::LogToStderr(); - InterpreterState state; + SequenceCheckingMonitor* mon = new SequenceCheckingMonitor(); + int iterations = 1; while(iterations--) { if (1) { // syntactic xml parse error - const char* xml = "<invalid>"; - Interpreter interpreter = Interpreter::fromXML(xml); - state = interpreter.getState(); - assert(!interpreter); - assert(state == uscxml::InterpreterState::USCXML_FAULTED); - std::cout << interpreter.getState() << std::endl; + try { + const char* xml = "<invalid"; + Interpreter interpreter = Interpreter::fromXML(xml); + assert(false); + } catch (Event& e) { + std::cout << e; + } } if (1) { // semantic xml parse error - const char* xml = "<invalid />"; - Interpreter interpreter = Interpreter::fromXML(xml); - state = interpreter.getState(); - assert(state == uscxml::InterpreterState::USCXML_INSTANTIATED); + try { + const char* xml = "<invalid />"; + Interpreter interpreter = Interpreter::fromXML(xml); + interpreter.addMonitor(mon); + assert(interpreter.getState() == USCXML_INSTANTIATED); + interpreter.step(); + assert(false); + } catch (Event& e) { + std::cout << e; + } + } - assert(interpreter.step() == uscxml::InterpreterState::USCXML_FAULTED); - std::cout << interpreter.getState() << std::endl; + if (1) { + // request unknown datamodel + try { + const char* xml = + "<scxml datamodel=\"invalid\">" + " <state id=\"start\">" + " <transition target=\"done\" />" + " </state>" + " <final id=\"done\" />" + "</scxml>"; + Interpreter interpreter = Interpreter::fromXML(xml); + interpreter.addMonitor(mon); + assert(interpreter.getState() == USCXML_INSTANTIATED); + interpreter.step(); + assert(false); + } catch (Event& e) { + std::cout << e; + } } if (1) { + // two microsteps + const char* xml = + "<scxml>" + " <state id=\"start\">" + " <transition target=\"s2\" />" + " </state>" + " <state id=\"s2\">" + " <transition target=\"done\" />" + " </state>" + " <final id=\"done\" />" + "</scxml>"; + + Interpreter interpreter = Interpreter::fromXML(xml); + interpreter.addMonitor(mon); + + callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERENTERINGSTATE); + + callBackSeq.push_back(USCXML_BEFOREMICROSTEP); + callBackSeq.push_back(USCXML_BEFOREEXITINGSTATE); + callBackSeq.push_back(USCXML_AFTEREXITINGSTATE); + callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION); + callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION); + callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERMICROSTEP); + + callBackSeq.push_back(USCXML_BEFOREMICROSTEP); + callBackSeq.push_back(USCXML_BEFOREEXITINGSTATE); + callBackSeq.push_back(USCXML_AFTEREXITINGSTATE); + callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION); + callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION); + callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERMICROSTEP); + + callBackSeq.push_back(USCXML_BEFORECOMPLETION); + callBackSeq.push_back(USCXML_AFTERCOMPLETION); + + assert(interpreter.getState() == USCXML_INSTANTIATED); + assert(interpreter.step() == USCXML_MICROSTEPPED); + assert(interpreter.step() == USCXML_MICROSTEPPED); + assert(interpreter.step() == USCXML_FINISHED); + assert(callBackSeq.empty()); + } + + if (1) { // single macrostep, multiple runs const char* xml = - "<scxml>" - " <state id=\"start\">" - " <transition target=\"done\" />" - " </state>" - " <final id=\"done\" />" - "</scxml>"; - + "<scxml>" + " <state id=\"start\">" + " <transition target=\"done\" />" + " </state>" + " <final id=\"done\" />" + "</scxml>"; + Interpreter interpreter = Interpreter::fromXML(xml); - assert(interpreter.getState() == uscxml::InterpreterState::USCXML_INSTANTIATED); - assert(interpreter.step() == uscxml::InterpreterState::USCXML_MICROSTEPPED); - assert(interpreter.step() == uscxml::InterpreterState::USCXML_FINISHED); - interpreter.reset(); - assert(interpreter.getState() == uscxml::InterpreterState::USCXML_INSTANTIATED); - assert(interpreter.step() == uscxml::InterpreterState::USCXML_MICROSTEPPED); - assert(interpreter.step() == uscxml::InterpreterState::USCXML_FINISHED); - interpreter.reset(); - assert(interpreter.getState() == uscxml::InterpreterState::USCXML_INSTANTIATED); - assert(interpreter.step() == uscxml::InterpreterState::USCXML_MICROSTEPPED); - assert(interpreter.step() == uscxml::InterpreterState::USCXML_FINISHED); + interpreter.addMonitor(mon); + + callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERENTERINGSTATE); + + callBackSeq.push_back(USCXML_BEFOREMICROSTEP); + callBackSeq.push_back(USCXML_BEFOREEXITINGSTATE); + callBackSeq.push_back(USCXML_AFTEREXITINGSTATE); + callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION); + callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION); + callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERMICROSTEP); + + callBackSeq.push_back(USCXML_BEFORECOMPLETION); + callBackSeq.push_back(USCXML_AFTERCOMPLETION); + + assert(interpreter.getState() == USCXML_INSTANTIATED); + assert(interpreter.step() == USCXML_MICROSTEPPED); + assert(interpreter.step() == USCXML_FINISHED); interpreter.reset(); - assert(interpreter.getState() == uscxml::InterpreterState::USCXML_INSTANTIATED); - assert(interpreter.step() == uscxml::InterpreterState::USCXML_MICROSTEPPED); - assert(interpreter.step() == uscxml::InterpreterState::USCXML_FINISHED); - } + callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERENTERINGSTATE); + + callBackSeq.push_back(USCXML_BEFOREMICROSTEP); + callBackSeq.push_back(USCXML_BEFOREEXITINGSTATE); + callBackSeq.push_back(USCXML_AFTEREXITINGSTATE); + callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION); + callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION); + callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERMICROSTEP); + + callBackSeq.push_back(USCXML_BEFORECOMPLETION); + callBackSeq.push_back(USCXML_AFTERCOMPLETION); + + assert(interpreter.getState() == USCXML_INSTANTIATED); + assert(interpreter.step() == USCXML_MICROSTEPPED); + assert(interpreter.step() == USCXML_FINISHED); + } + if (1) { - // two microsteps + // macrostep in between const char* xml = - "<scxml>" - " <state id=\"start\">" - " <transition target=\"s2\" />" - " </state>" - " <state id=\"s2\">" - " <transition target=\"done\" />" - " </state>" - " <final id=\"done\" />" - "</scxml>"; - + "<scxml>" + " <state id=\"start\">" + " <onentry>" + " <send event=\"continue\" delay=\"2s\"/>" + " </onentry>" + " <transition target=\"s2\" event=\"continue\" />" + " </state>" + " <state id=\"s2\">" + " <transition target=\"done\" />" + " </state>" + " <final id=\"done\" />" + "</scxml>"; + Interpreter interpreter = Interpreter::fromXML(xml); - - assert(interpreter.getState() == uscxml::InterpreterState::USCXML_INSTANTIATED); - assert(interpreter.step() == uscxml::InterpreterState::USCXML_MICROSTEPPED); - assert(interpreter.step() == uscxml::InterpreterState::USCXML_MICROSTEPPED); - assert(interpreter.step() == uscxml::InterpreterState::USCXML_FINISHED); + interpreter.addMonitor(mon); + + callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE); + callBackSeq.push_back(USCXML_BEFOREEXECUTINGCONTENT); + callBackSeq.push_back(USCXML_AFTEREXECUTINGCONTENT); + callBackSeq.push_back(USCXML_AFTERENTERINGSTATE); + callBackSeq.push_back(USCXML_ONSTABLECONFIGURATION); + + callBackSeq.push_back(USCXML_BEFOREPROCESSINGEVENT); + callBackSeq.push_back(USCXML_BEFOREMICROSTEP); + callBackSeq.push_back(USCXML_BEFOREEXITINGSTATE); + callBackSeq.push_back(USCXML_AFTEREXITINGSTATE); + callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION); + callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION); + callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERMICROSTEP); + + callBackSeq.push_back(USCXML_BEFOREMICROSTEP); + callBackSeq.push_back(USCXML_BEFOREEXITINGSTATE); + callBackSeq.push_back(USCXML_AFTEREXITINGSTATE); + callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION); + callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION); + callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERENTERINGSTATE); + callBackSeq.push_back(USCXML_AFTERMICROSTEP); + + callBackSeq.push_back(USCXML_BEFORECOMPLETION); + callBackSeq.push_back(USCXML_AFTERCOMPLETION); + + assert(interpreter.getState() == USCXML_INSTANTIATED); + assert(interpreter.step() == USCXML_IDLE); + assert(interpreter.step(true) == USCXML_MACROSTEPPED); + assert(interpreter.step() == USCXML_MICROSTEPPED); + assert(interpreter.step() == USCXML_FINISHED); } + +#if 0 + if (0) { // macrostep in between @@ -271,7 +511,7 @@ int main(int argc, char** argv) { assert(!(state & InterpreterState::USCXML_THREAD_RUNNING)); } +#endif } - return EXIT_SUCCESS; }
\ No newline at end of file diff --git a/test/w3c/confEcma.xsl b/test/w3c/confEcma.xsl index af3c8d2..ffc922d 100644 --- a/test/w3c/confEcma.xsl +++ b/test/w3c/confEcma.xsl @@ -165,6 +165,8 @@ <content xmlns="http://www.w3.org/2005/07/scxml">foo</content> </xsl:template> + + <!-- this returns something that is guaranteed not to be the ID of the current session --> <xsl:template match="//@conf:invalidSessionID"> <xsl:attribute name="expr">27</xsl:attribute> @@ -241,8 +243,14 @@ </xsl:template> <!-- delayexpr takes the value of the specified variable --> -<xsl:template match="//@conf:delayExpr"> - <xsl:attribute name="delayexpr">Var<xsl:value-of select="." /></xsl:attribute> +<xsl:template match="//@conf:delayFromVar"> + <xsl:attribute name="delayexpr">(Var<xsl:value-of select="." />.slice(0, - 1)) * 50 + 'ms'</xsl:attribute> +</xsl:template> + +<!-- computes a delayexpr based on the value passed in. this lets platforms determine how long to delay timeout +events which cause the test to fail. The default value provided here is pretty long --> +<xsl:template match="//@conf:delay"> + <xsl:attribute name="delayexpr">'<xsl:value-of select=". * 50"/>ms'</xsl:attribute> </xsl:template> <!-- the specified variable is used as idlocation --> @@ -722,4 +730,4 @@ it allows anything after the = --> <xsl:template match="//@conf:msgIsBody"> <xsl:attribute name="cond">_event.raw.match(/\n\naddress=(.*)$/)</xsl:attribute> </xsl:template> -</xsl:stylesheet>
\ No newline at end of file +</xsl:stylesheet> diff --git a/test/w3c/confXPath.xsl b/test/w3c/confXPath.xsl index fa67f3b..71286ce 100644 --- a/test/w3c/confXPath.xsl +++ b/test/w3c/confXPath.xsl @@ -206,6 +206,7 @@ is of the same type as array123 --> + <!-- this returns something that is guaranteed not to be the ID of the current session --> <xsl:template match="//@conf:invalidSessionID"> <xsl:attribute name="expr">27</xsl:attribute> @@ -239,10 +240,16 @@ is of the same type as array123 --> </xsl:template> <!-- delayexpr takes the value of the specified variable --> -<xsl:template match="//@conf:delayExpr"> +<xsl:template match="//@conf:delayFromVar"> <xsl:attribute name="delayexpr">$Var<xsl:value-of select="." /></xsl:attribute> </xsl:template> +<!-- returns a delayexpr. this lets platforms determine how long to delay timeout +events which cause the test to fail. The default value provided here is pretty long --> +<xsl:template match="//@conf:delay"> + <xsl:attribute name="delayexpr">'<xsl:value-of select="."/>s'</xsl:attribute> +</xsl:template> + <!-- the specified variable is used as idlocation --> <xsl:template match="//@conf:idlocation"> <xsl:attribute name="idlocation">$Var<xsl:value-of select="." /></xsl:attribute> diff --git a/test/w3c/ecma/test175.scxml b/test/w3c/ecma/test175.scxml index 4876821..cda3b5a 100644 --- a/test/w3c/ecma/test175.scxml +++ b/test/w3c/ecma/test175.scxml @@ -7,9 +7,9 @@ event1 will be raised first. Succeed if event1 occurs before event2, otherwise <state id="s0"> <onentry> - <assign location="Var1" expr="'3s'"/> - <send delayexpr="Var1" event="event2"/> - <send delay="1s" event="event1"/> + <assign location="Var1" expr="'1s'"/> + <send delayexpr="(Var1.slice(0, - 1)) * 50 + 'ms'" event="event2"/> + <send delayexpr="'25ms'" event="event1"/> </onentry> <transition event="event1" target="s1"/> diff --git a/test/w3c/ecma/test185.scxml b/test/w3c/ecma/test185.scxml index cdf8a77..6a83574 100644 --- a/test/w3c/ecma/test185.scxml +++ b/test/w3c/ecma/test185.scxml @@ -4,7 +4,7 @@ <state id="s0"> <onentry> - <send event="event2" delay="2s"/> + <send event="event2" delayexpr="'50ms'"/> <send event="event1"/> </onentry> diff --git a/test/w3c/ecma/test186.scxml b/test/w3c/ecma/test186.scxml index 20f0063..68254d3 100644 --- a/test/w3c/ecma/test186.scxml +++ b/test/w3c/ecma/test186.scxml @@ -8,7 +8,7 @@ in the interval.) If var2 ends up == 1, we pass. Otherwise we fail --><scxml <state id="s0"> <onentry> - <send event="event1" delay="2s"> + <send event="event1" delayexpr="'50ms'"> <param name="aParam" expr="Var1"/> </send> <assign location="Var1" expr="2"/> diff --git a/test/w3c/ecma/test187.scxml b/test/w3c/ecma/test187.scxml index d03c16d..c4f2a6f 100644 --- a/test/w3c/ecma/test187.scxml +++ b/test/w3c/ecma/test187.scxml @@ -6,7 +6,7 @@ parent session, should not receive childToParent. If it does, we fail. Otherwis <state id="s0"> <onentry> - <send event="timeout" delay="10s"/> + <send event="timeout" delayexpr="'50ms'"/> </onentry> <invoke type="scxml"> <content> @@ -14,7 +14,7 @@ parent session, should not receive childToParent. If it does, we fail. Otherwis <scxml initial="sub0" version="1.0" datamodel="ecmascript"> <state id="sub0"> <onentry> - <send event="childToParent" target="#_parent" delay="1s"/> + <send event="childToParent" target="#_parent" delayexpr="'25ms'"/> </onentry> <transition target="subFinal"/> </state> diff --git a/test/w3c/ecma/test207.scxml b/test/w3c/ecma/test207.scxml index aa5786a..fe30bf1 100644 --- a/test/w3c/ecma/test207.scxml +++ b/test/w3c/ecma/test207.scxml @@ -6,7 +6,7 @@ raised in another session, but the spec doesn't define any way to refer to an ev <state id="s0" initial="s01"> <onentry> - <send event="timeout" delay="10s"/> + <send event="timeout" delayexpr="'100ms'"/> </onentry> <invoke type="scxml"> <content> @@ -18,8 +18,8 @@ raised in another session, but the spec doesn't define any way to refer to an ev <scxml initial="sub0" version="1.0" datamodel="ecmascript"> <state id="sub0"> <onentry> - <send event="event1" id="foo" delay="3s"/> - <send event="event2" delay="5s"/> + <send event="event1" id="foo" delayexpr="'50ms'"/> + <send event="event2" delayexpr="'75ms'"/> <send target="#_parent" event="childToParent"/> </onentry> diff --git a/test/w3c/ecma/test208.scxml b/test/w3c/ecma/test208.scxml index 6faa9c1..043e537 100644 --- a/test/w3c/ecma/test208.scxml +++ b/test/w3c/ecma/test208.scxml @@ -4,8 +4,8 @@ we get event1 or an error first, cancel didn't work and we fail. --><scxml xmln <state id="s0"> <onentry> - <send id="foo" event="event1" delay="1s"/> - <send event="event2" delay="5s"/> + <send id="foo" event="event1" delayexpr="'50ms'"/> + <send event="event2" delayexpr="'75ms'"/> <cancel sendid="foo"/> </onentry> diff --git a/test/w3c/ecma/test210.scxml b/test/w3c/ecma/test210.scxml index e29b65d..f103ecd 100644 --- a/test/w3c/ecma/test210.scxml +++ b/test/w3c/ecma/test210.scxml @@ -6,8 +6,8 @@ delayed event1. Thus we get event2 first and pass. If we get event1 or an erro <state id="s0"> <onentry> - <send id="foo" event="event1" delay="1s"/> - <send event="event2" delay="5s"/> + <send id="foo" event="event1" delayexpr="'50ms'"/> + <send event="event2" delayexpr="'75ms'"/> <assign location="Var1" expr="'foo'"/> <cancel sendidexpr="Var1"/> </onentry> diff --git a/test/w3c/ecma/test236.scxml b/test/w3c/ecma/test236.scxml index 700c6f8..acb1cda 100644 --- a/test/w3c/ecma/test236.scxml +++ b/test/w3c/ecma/test236.scxml @@ -5,7 +5,7 @@ events after the done.invoke. Hence timeout indicates success --><scxml xmlns <state id="s0"> <onentry> - <send event="timeout" delay="2s"/> + <send event="timeout" delayexpr="'100ms'"/> </onentry> <invoke type="http://www.w3.org/TR/scxml/"> <content> diff --git a/test/w3c/ecma/test237.scxml b/test/w3c/ecma/test237.scxml index b23811d..442b04c 100644 --- a/test/w3c/ecma/test237.scxml +++ b/test/w3c/ecma/test237.scxml @@ -6,7 +6,7 @@ the time timeout2 fires, success --><scxml xmlns="http://www.w3.org/2005/07/sc <state id="s0"> <onentry> - <send event="timeout1" delay="1s"/> + <send event="timeout1" delayexpr="'50ms'"/> </onentry> <invoke type="http://www.w3.org/TR/scxml/"> <content> @@ -14,7 +14,7 @@ the time timeout2 fires, success --><scxml xmlns="http://www.w3.org/2005/07/sc <scxml initial="sub0" version="1.0" datamodel="ecmascript"> <state id="sub0"> <onentry> - <send event="timeout" delay="2s"/> + <send event="timeout" delayexpr="'100ms'"/> </onentry> <transition event="timeout" target="subFinal"/> </state> @@ -29,7 +29,7 @@ the time timeout2 fires, success --><scxml xmlns="http://www.w3.org/2005/07/sc <state id="s1"> <onentry> - <send event="timeout2" delay="2s"/> + <send event="timeout2" delayexpr="'75ms'"/> </onentry> <!-- here we should NOT get done.invoke --> <transition event="done.invoke" target="fail"/> diff --git a/test/w3c/ecma/test409.scxml b/test/w3c/ecma/test409.scxml index 9b4f1aa..0fa71a2 100644 --- a/test/w3c/ecma/test409.scxml +++ b/test/w3c/ecma/test409.scxml @@ -5,7 +5,7 @@ be raised. Therefore the timeout should fire to indicate success --><scxml xm <state id="s0" initial="s01"> <onentry> - <send event="timeout" delay="1s"/> + <send event="timeout" delayexpr="'50ms'"/> </onentry> <transition event="timeout" target="pass"/> diff --git a/test/w3c/ecma/test422.scxml b/test/w3c/ecma/test422.scxml index 803f75f..637ff77 100644 --- a/test/w3c/ecma/test422.scxml +++ b/test/w3c/ecma/test422.scxml @@ -10,7 +10,7 @@ in s11. So we should receive invokeS1, invokeS12, but not invokeS12. Furthermor </datamodel> <state id="s1" initial="s11"> <onentry> - <send event="timeout" delay="5s"/> + <send event="timeout" delayexpr="'100ms'"/> </onentry> <transition event="invokeS1 invokeS12"> <assign location="Var1" expr="Var1 + 1"/> diff --git a/test/w3c/ecma/test423.scxml b/test/w3c/ecma/test423.scxml index f6287ab..ab6c84f 100644 --- a/test/w3c/ecma/test423.scxml +++ b/test/w3c/ecma/test423.scxml @@ -4,7 +4,7 @@ <state id="s0"> <onentry> <send event="externalEvent1"/> - <send event="externalEvent2" delay="1s"/> + <send event="externalEvent2" delayexpr="'50ms'"/> <raise event="internalEvent"/> </onentry> <!-- in this state we should process only internalEvent --> diff --git a/test/w3c/ecma/test553.scxml b/test/w3c/ecma/test553.scxml index 114c4a2..0beddea 100644 --- a/test/w3c/ecma/test553.scxml +++ b/test/w3c/ecma/test553.scxml @@ -5,7 +5,7 @@ of <send>'s args causes an error.. --><scxml xmlns="http://www.w3.org/2005/07/s <state id="s0"> <onentry> <!-- timeout event --> - <send event="timeout" delay="3s"/> + <send event="timeout" delayexpr="'50ms'"/> <!-- include a non-existing var in the namelist --> <send event="event1" namelist="Var2"/> </onentry> diff --git a/test/w3c/ecma/test554.scxml b/test/w3c/ecma/test554.scxml index b328ae9..960f5ac 100644 --- a/test/w3c/ecma/test554.scxml +++ b/test/w3c/ecma/test554.scxml @@ -5,7 +5,7 @@ before the timer goes off. --><scxml xmlns="http://www.w3.org/2005/07/scxml" xm <state id="s0"> <onentry> - <send event="timer" delay="2s"/> + <send event="timer" delayexpr="'50ms'"/> </onentry> <!-- namelist references an undeclared variable --> diff --git a/test/w3c/ecma/test579.scxml b/test/w3c/ecma/test579.scxml index f89b1a9..c315f82 100644 --- a/test/w3c/ecma/test579.scxml +++ b/test/w3c/ecma/test579.scxml @@ -14,7 +14,7 @@ parent state has been visited and exited, the default history content must not b </transition> </initial> <onentry> - <send delay="2s" event="timeout"/> + <send delayexpr="'50ms'" event="timeout"/> <raise event="event1"/> </onentry> <onexit> diff --git a/test/w3c/txml/test175.txml b/test/w3c/txml/test175.txml index aba7ac4..0c5065d 100644 --- a/test/w3c/txml/test175.txml +++ b/test/w3c/txml/test175.txml @@ -10,9 +10,9 @@ event1 will be raised first. Succeed if event1 occurs before event2, otherwise <state id="s0"> <onentry> - <assign conf:location="1" conf:quoteExpr="3s"/> - <send conf:delayExpr="1" event="event2"/> - <send delay="1s" event="event1"/> + <assign conf:location="1" conf:quoteExpr="1s"/> + <send conf:delayFromVar="1" event="event2"/> + <send conf:delay=".5" event="event1"/> </onentry> <transition event="event1" target="s1"/> diff --git a/test/w3c/txml/test185.txml b/test/w3c/txml/test185.txml index c036cbf..f9663c5 100644 --- a/test/w3c/txml/test185.txml +++ b/test/w3c/txml/test185.txml @@ -7,7 +7,7 @@ <state id="s0"> <onentry> - <send event="event2" delay="2s"/> + <send event="event2" conf:delay="1"/> <send event="event1"/> </onentry> diff --git a/test/w3c/txml/test186.txml b/test/w3c/txml/test186.txml index e91c290..ef903f8 100644 --- a/test/w3c/txml/test186.txml +++ b/test/w3c/txml/test186.txml @@ -11,7 +11,7 @@ in the interval.) If var2 ends up == 1, we pass. Otherwise we fail --> <state id="s0"> <onentry> - <send event="event1" delay="2s"> + <send event="event1" conf:delay="1"> <param name="aParam" conf:varExpr="1"/> </send> <assign conf:location="1" conf:expr="2"/> diff --git a/test/w3c/txml/test187.txml b/test/w3c/txml/test187.txml index 994a489..a39b6a3 100644 --- a/test/w3c/txml/test187.txml +++ b/test/w3c/txml/test187.txml @@ -9,7 +9,7 @@ parent session, should not receive childToParent. If it does, we fail. Otherwis <state id="s0" > <onentry> - <send event="timeout" delay="10s"/> + <send event="timeout" conf:delay="1"/> </onentry> <invoke type="scxml" > <content> @@ -17,7 +17,7 @@ parent session, should not receive childToParent. If it does, we fail. Otherwis <scxml initial="sub0" version="1.0" conf:datamodel="" xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance"> <state id="sub0"> <onentry> - <send event="childToParent" target="#_parent" delay="1s"/> + <send event="childToParent" target="#_parent" conf:delay=".5"/> </onentry> <transition target="subFinal"/> </state> diff --git a/test/w3c/txml/test207.txml b/test/w3c/txml/test207.txml index 6893dcf..df37f54 100644 --- a/test/w3c/txml/test207.txml +++ b/test/w3c/txml/test207.txml @@ -10,7 +10,7 @@ raised in another session, but the spec doesn't define any way to refer to an ev <state id="s0" initial="s01"> <onentry> - <send event="timeout" delay="10s"/> + <send event="timeout" conf:delay="2"/> </onentry> <invoke type="scxml"> <content> @@ -22,8 +22,8 @@ raised in another session, but the spec doesn't define any way to refer to an ev <scxml initial="sub0" version="1.0" conf:datamodel="" xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance"> <state id="sub0"> <onentry> - <send event="event1" id="foo" delay="3s"/> - <send event="event2" delay="5s"/> + <send event="event1" id="foo" conf:delay="1"/> + <send event="event2" conf:delay="1.5"/> <send target="#_parent" event="childToParent"/> </onentry> diff --git a/test/w3c/txml/test208.txml b/test/w3c/txml/test208.txml index 5a86e6d..cce0316 100644 --- a/test/w3c/txml/test208.txml +++ b/test/w3c/txml/test208.txml @@ -8,8 +8,8 @@ we get event1 or an error first, cancel didn't work and we fail. --> <state id="s0"> <onentry> - <send id="foo" event="event1" delay="1s"/> - <send event="event2" delay="5s"/> + <send id="foo" event="event1" conf:delay="1"/> + <send event="event2" conf:delay="1.5"/> <cancel sendid="foo"/> </onentry> diff --git a/test/w3c/txml/test210.txml b/test/w3c/txml/test210.txml index 402ed36..24fdce0 100644 --- a/test/w3c/txml/test210.txml +++ b/test/w3c/txml/test210.txml @@ -10,8 +10,8 @@ delayed event1. Thus we get event2 first and pass. If we get event1 or an erro <state id="s0"> <onentry> - <send id="foo" event="event1" delay="1s"/> - <send event="event2" delay="5s"/> + <send id="foo" event="event1" conf:delay="1"/> + <send event="event2" conf:delay="1.5"/> <assign conf:location="1" conf:quoteExpr="foo"/> <cancel conf:sendIDExpr="1"/> </onentry> diff --git a/test/w3c/txml/test236.txml b/test/w3c/txml/test236.txml index 5d18c2f..34e76ab 100644 --- a/test/w3c/txml/test236.txml +++ b/test/w3c/txml/test236.txml @@ -9,7 +9,7 @@ events after the done.invoke. Hence timeout indicates success --> <state id="s0"> <onentry> - <send event="timeout" delay="2s"/> + <send event="timeout" conf:delay="2"/> </onentry> <invoke type="http://www.w3.org/TR/scxml/"> <content> diff --git a/test/w3c/txml/test237.txml b/test/w3c/txml/test237.txml index c6097bc..5923705 100644 --- a/test/w3c/txml/test237.txml +++ b/test/w3c/txml/test237.txml @@ -10,7 +10,7 @@ the time timeout2 fires, success --> <state id="s0"> <onentry> - <send event="timeout1" delay="1s"/> + <send event="timeout1" conf:delay="1"/> </onentry> <invoke type="http://www.w3.org/TR/scxml/"> <content> @@ -18,7 +18,7 @@ the time timeout2 fires, success --> <scxml initial="sub0" version="1.0" conf:datamodel="" xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance"> <state id="sub0"> <onentry> - <send event="timeout" delay="2s"/> + <send event="timeout" conf:delay="2"/> </onentry> <transition event="timeout" target="subFinal"/> </state> @@ -33,7 +33,7 @@ the time timeout2 fires, success --> <state id="s1"> <onentry> - <send event="timeout2" delay="2s"/> + <send event="timeout2" conf:delay="1.5"/> </onentry> <!-- here we should NOT get done.invoke --> <transition event="done.invoke" conf:targetfail=""/> diff --git a/test/w3c/txml/test409.txml b/test/w3c/txml/test409.txml index abc92ee..020f097 100644 --- a/test/w3c/txml/test409.txml +++ b/test/w3c/txml/test409.txml @@ -9,7 +9,7 @@ be raised. Therefore the timeout should fire to indicate success --> <state id="s0" initial="s01"> <onentry> - <send event="timeout" delay="1s"/> + <send event="timeout" conf:delay="1"/> </onentry> <transition event="timeout" conf:targetpass=""/> diff --git a/test/w3c/txml/test422.txml b/test/w3c/txml/test422.txml index 2e830d9..0349bd0 100644 --- a/test/w3c/txml/test422.txml +++ b/test/w3c/txml/test422.txml @@ -13,7 +13,7 @@ in s11. So we should receive invokeS1, invokeS12, but not invokeS12. Furthermor </datamodel> <state id="s1" initial="s11"> <onentry> - <send event="timeout" delay="5s"/> + <send event="timeout" conf:delay="2"/> </onentry> <transition event="invokeS1 invokeS12"> <conf:incrementID id="1"/> diff --git a/test/w3c/txml/test423.txml b/test/w3c/txml/test423.txml index fd64587..0e877cf 100644 --- a/test/w3c/txml/test423.txml +++ b/test/w3c/txml/test423.txml @@ -7,7 +7,7 @@ <state id="s0"> <onentry> <send event="externalEvent1"/> - <send event="externalEvent2" delay="1s"/> + <send event="externalEvent2" conf:delay="1"/> <raise event="internalEvent"/> </onentry> <!-- in this state we should process only internalEvent --> diff --git a/test/w3c/txml/test553.txml b/test/w3c/txml/test553.txml index 322d4bb..0c6a622 100644 --- a/test/w3c/txml/test553.txml +++ b/test/w3c/txml/test553.txml @@ -9,7 +9,7 @@ of <send>'s args causes an error.. --> <state id="s0"> <onentry> <!-- timeout event --> - <send event="timeout" delay="3s"/> + <send event="timeout" conf:delay="1"/> <!-- include a non-existing var in the namelist --> <send event="event1" conf:namelist="2"/> </onentry> diff --git a/test/w3c/txml/test554.txml b/test/w3c/txml/test554.txml index d9ad55b..663424f 100644 --- a/test/w3c/txml/test554.txml +++ b/test/w3c/txml/test554.txml @@ -9,7 +9,7 @@ before the timer goes off. --> <state id="s0"> <onentry> - <send event="timer" delay="2s"/> + <send event="timer" conf:delay="1"/> </onentry> <!-- namelist references an undeclared variable --> diff --git a/test/w3c/txml/test579.txml b/test/w3c/txml/test579.txml index 7c48c37..9b1ef2a 100644 --- a/test/w3c/txml/test579.txml +++ b/test/w3c/txml/test579.txml @@ -18,7 +18,7 @@ parent state has been visited and exited, the default history content must not b </transition> </initial> <onentry> - <send delay="2s" event="timeout"/> + <send conf:delay="1" event="timeout"/> <raise event="event1"/> </onentry> <onexit> diff --git a/test/w3c/update-txml.sh b/test/w3c/update-txml.sh index b733c6b..09a9602 100755 --- a/test/w3c/update-txml.sh +++ b/test/w3c/update-txml.sh @@ -9,4 +9,9 @@ wget -rl1 -Atxml,txt,xsl http://www.w3.org/Voice/2013/scxml-irp/ find ./www.w3.org -name "*.txml" -exec cp {} ./txml \; find ./www.w3.org -name "*.txt" -exec cp {} ./txml \; find ./www.w3.org -name "*.xsl" -exec cp {} . \; -rm -rf www.w3.org
\ No newline at end of file +rm -rf www.w3.org + +sed -ie "s/<xsl:attribute name=\"delayexpr\">Var<xsl:value-of select=\".\" \/><\/xsl:attribute>/<xsl:attribute name=\"delayexpr\">(Var<xsl:value-of select=\".\" \/>.slice(0, - 1)) * 50 + 'ms'<\/xsl:attribute>/" confEcma.xsl +sed -ie "s/<xsl:attribute name=\"delayexpr\">'<xsl:value-of select=\".\"\/>s'<\/xsl:attribute>/<xsl:attribute name=\"delayexpr\">'<xsl:value-of select=\". * 50\"\/>ms'<\/xsl:attribute>/" confEcma.xsl + +rm confEcma.xsle
\ No newline at end of file diff --git a/test/w3c/xpath/test175.scxml b/test/w3c/xpath/test175.scxml index 8dfd670..67fa473 100644 --- a/test/w3c/xpath/test175.scxml +++ b/test/w3c/xpath/test175.scxml @@ -7,9 +7,9 @@ event1 will be raised first. Succeed if event1 occurs before event2, otherwise <state id="s0"> <onentry> - <assign location="$Var1" expr="'3s'"/> + <assign location="$Var1" expr="'1s'"/> <send delayexpr="$Var1" event="event2"/> - <send delay="1s" event="event1"/> + <send delayexpr="'.5s'" event="event1"/> </onentry> <transition event="event1" target="s1"/> diff --git a/test/w3c/xpath/test185.scxml b/test/w3c/xpath/test185.scxml index c6b4b48..387086d 100644 --- a/test/w3c/xpath/test185.scxml +++ b/test/w3c/xpath/test185.scxml @@ -4,7 +4,7 @@ <state id="s0"> <onentry> - <send event="event2" delay="2s"/> + <send event="event2" delayexpr="'1s'"/> <send event="event1"/> </onentry> diff --git a/test/w3c/xpath/test186.scxml b/test/w3c/xpath/test186.scxml index 8353bf2..8121a17 100644 --- a/test/w3c/xpath/test186.scxml +++ b/test/w3c/xpath/test186.scxml @@ -8,7 +8,7 @@ in the interval.) If var2 ends up == 1, we pass. Otherwise we fail --><scxml <state id="s0"> <onentry> - <send event="event1" delay="2s"> + <send event="event1" delayexpr="'1s'"> <param name="aParam" expr="$Var1/text()"/> </send> <assign location="$Var1" expr="2"/> diff --git a/test/w3c/xpath/test187.scxml b/test/w3c/xpath/test187.scxml index 12cbb8b..5cbb817 100644 --- a/test/w3c/xpath/test187.scxml +++ b/test/w3c/xpath/test187.scxml @@ -6,7 +6,7 @@ parent session, should not receive childToParent. If it does, we fail. Otherwis <state id="s0"> <onentry> - <send event="timeout" delay="10s"/> + <send event="timeout" delayexpr="'1s'"/> </onentry> <invoke type="scxml"> <content> @@ -14,7 +14,7 @@ parent session, should not receive childToParent. If it does, we fail. Otherwis <scxml initial="sub0" version="1.0" datamodel="xpath"> <state id="sub0"> <onentry> - <send event="childToParent" target="#_parent" delay="1s"/> + <send event="childToParent" target="#_parent" delayexpr="'.5s'"/> </onentry> <transition target="subFinal"/> </state> diff --git a/test/w3c/xpath/test207.scxml b/test/w3c/xpath/test207.scxml index e74ec8f..b99e511 100644 --- a/test/w3c/xpath/test207.scxml +++ b/test/w3c/xpath/test207.scxml @@ -6,7 +6,7 @@ raised in another session, but the spec doesn't define any way to refer to an ev <state id="s0" initial="s01"> <onentry> - <send event="timeout" delay="10s"/> + <send event="timeout" delayexpr="'2s'"/> </onentry> <invoke type="scxml"> <content> @@ -18,8 +18,8 @@ raised in another session, but the spec doesn't define any way to refer to an ev <scxml initial="sub0" version="1.0" datamodel="xpath"> <state id="sub0"> <onentry> - <send event="event1" id="foo" delay="3s"/> - <send event="event2" delay="5s"/> + <send event="event1" id="foo" delayexpr="'1s'"/> + <send event="event2" delayexpr="'1.5s'"/> <send target="#_parent" event="childToParent"/> </onentry> diff --git a/test/w3c/xpath/test208.scxml b/test/w3c/xpath/test208.scxml index e768e7c..4aa9ebe 100644 --- a/test/w3c/xpath/test208.scxml +++ b/test/w3c/xpath/test208.scxml @@ -4,8 +4,8 @@ we get event1 or an error first, cancel didn't work and we fail. --><scxml xmln <state id="s0"> <onentry> - <send id="foo" event="event1" delay="1s"/> - <send event="event2" delay="5s"/> + <send id="foo" event="event1" delayexpr="'1s'"/> + <send event="event2" delayexpr="'1.5s'"/> <cancel sendid="foo"/> </onentry> diff --git a/test/w3c/xpath/test210.scxml b/test/w3c/xpath/test210.scxml index 5ec8f23..17dfc95 100644 --- a/test/w3c/xpath/test210.scxml +++ b/test/w3c/xpath/test210.scxml @@ -6,8 +6,8 @@ delayed event1. Thus we get event2 first and pass. If we get event1 or an erro <state id="s0"> <onentry> - <send id="foo" event="event1" delay="1s"/> - <send event="event2" delay="5s"/> + <send id="foo" event="event1" delayexpr="'1s'"/> + <send event="event2" delayexpr="'1.5s'"/> <assign location="$Var1" expr="'foo'"/> <cancel sendidexpr="$Var1"/> </onentry> diff --git a/test/w3c/xpath/test236.scxml b/test/w3c/xpath/test236.scxml index 2c2d41a..0964f71 100644 --- a/test/w3c/xpath/test236.scxml +++ b/test/w3c/xpath/test236.scxml @@ -5,7 +5,7 @@ events after the done.invoke. Hence timeout indicates success --><scxml xmlns <state id="s0"> <onentry> - <send event="timeout" delay="2s"/> + <send event="timeout" delayexpr="'2s'"/> </onentry> <invoke type="http://www.w3.org/TR/scxml/"> <content> diff --git a/test/w3c/xpath/test237.scxml b/test/w3c/xpath/test237.scxml index 19c2480..a81e36a 100644 --- a/test/w3c/xpath/test237.scxml +++ b/test/w3c/xpath/test237.scxml @@ -6,7 +6,7 @@ the time timeout2 fires, success --><scxml xmlns="http://www.w3.org/2005/07/sc <state id="s0"> <onentry> - <send event="timeout1" delay="1s"/> + <send event="timeout1" delayexpr="'1s'"/> </onentry> <invoke type="http://www.w3.org/TR/scxml/"> <content> @@ -14,7 +14,7 @@ the time timeout2 fires, success --><scxml xmlns="http://www.w3.org/2005/07/sc <scxml initial="sub0" version="1.0" datamodel="xpath"> <state id="sub0"> <onentry> - <send event="timeout" delay="2s"/> + <send event="timeout" delayexpr="'2s'"/> </onentry> <transition event="timeout" target="subFinal"/> </state> @@ -29,7 +29,7 @@ the time timeout2 fires, success --><scxml xmlns="http://www.w3.org/2005/07/sc <state id="s1"> <onentry> - <send event="timeout2" delay="2s"/> + <send event="timeout2" delayexpr="'1.5s'"/> </onentry> <!-- here we should NOT get done.invoke --> <transition event="done.invoke" target="fail"/> diff --git a/test/w3c/xpath/test409.scxml b/test/w3c/xpath/test409.scxml index 2d5a63d..e321d46 100644 --- a/test/w3c/xpath/test409.scxml +++ b/test/w3c/xpath/test409.scxml @@ -5,7 +5,7 @@ be raised. Therefore the timeout should fire to indicate success --><scxml xm <state id="s0" initial="s01"> <onentry> - <send event="timeout" delay="1s"/> + <send event="timeout" delayexpr="'1s'"/> </onentry> <transition event="timeout" target="pass"/> diff --git a/test/w3c/xpath/test422.scxml b/test/w3c/xpath/test422.scxml index f62098d..4ef15ce 100644 --- a/test/w3c/xpath/test422.scxml +++ b/test/w3c/xpath/test422.scxml @@ -10,7 +10,7 @@ in s11. So we should receive invokeS1, invokeS12, but not invokeS12. Furthermor </datamodel> <state id="s1" initial="s11"> <onentry> - <send event="timeout" delay="5s"/> + <send event="timeout" delayexpr="'2s'"/> </onentry> <transition event="invokeS1 invokeS12"> <assign location="$Var1" expr="$Var1 + 1"/> diff --git a/test/w3c/xpath/test423.scxml b/test/w3c/xpath/test423.scxml index 7726963..f3bf8c8 100644 --- a/test/w3c/xpath/test423.scxml +++ b/test/w3c/xpath/test423.scxml @@ -4,7 +4,7 @@ <state id="s0"> <onentry> <send event="externalEvent1"/> - <send event="externalEvent2" delay="1s"/> + <send event="externalEvent2" delayexpr="'1s'"/> <raise event="internalEvent"/> </onentry> <!-- in this state we should process only internalEvent --> diff --git a/test/w3c/xpath/test553.scxml b/test/w3c/xpath/test553.scxml index eb6f24b..00bd1e8 100644 --- a/test/w3c/xpath/test553.scxml +++ b/test/w3c/xpath/test553.scxml @@ -5,7 +5,7 @@ of <send>'s args causes an error.. --><scxml xmlns="http://www.w3.org/2005/07/s <state id="s0"> <onentry> <!-- timeout event --> - <send event="timeout" delay="3s"/> + <send event="timeout" delayexpr="'1s'"/> <!-- include a non-existing var in the namelist --> <send event="event1" namelist="$Var2"/> </onentry> diff --git a/test/w3c/xpath/test554.scxml b/test/w3c/xpath/test554.scxml index 64274aa..1a2b58a 100644 --- a/test/w3c/xpath/test554.scxml +++ b/test/w3c/xpath/test554.scxml @@ -5,7 +5,7 @@ before the timer goes off. --><scxml xmlns="http://www.w3.org/2005/07/scxml" xm <state id="s0"> <onentry> - <send event="timer" delay="2s"/> + <send event="timer" delayexpr="'1s'"/> </onentry> <!-- namelist references an undeclared variable --> diff --git a/test/w3c/xpath/test579.scxml b/test/w3c/xpath/test579.scxml index 311c0a9..28cdf28 100644 --- a/test/w3c/xpath/test579.scxml +++ b/test/w3c/xpath/test579.scxml @@ -14,7 +14,7 @@ parent state has been visited and exited, the default history content must not b </transition> </initial> <onentry> - <send delay="2s" event="timeout"/> + <send delayexpr="'1s'" event="timeout"/> <raise event="event1"/> </onentry> <onexit> |