S-SCXML Web Laboratory is a web interface to an implementation of a simplified version of State Chart XML (SCXML). You may want to start by looking at something which is more in the spirit of the January Draft, namely SCXML Web Laboratory, and then return here to study our change proposals.
Based on our experiences trying to implement the current draft we would like to propose a number of changes to SCXML. We think they would make SCXML simpler and more intuitive to use, as well as easier to implement.
As a consequence of 1)
<state id="s0">
<initial>
<transition target="s1" >
</initial>
<state id="s1" ... />
<state id="s2" ... />
<state>
can be written as
<state id="s0" target="s1">
<state id="s1" ... />
<state id="s2" ... />
<state>
As a consequence of 2)
<state id="s0" target="s1">
<state id="s1" ... />
<state id="s2">
<parallel ... />
</state>
<state>
can be replaced with
<state id="s0" target="s1">
<state id="s1" ... />
<parallel ... />
<state>
As a consequence of 3), the Hello world example can now be written as
<?xml version="1.0"?>
<scxml version="1.0" final="true">
<onentry>
<log expr="'Hello world'"/>
</onentry>
<scxml>
In the current implementation, a source to source (or rather DOM to DOM) transformation takes place, transforming the above to
<state id="main" final="true">
<onentry>
<log expr="'Hello world'"/>
</onentry>
<transition event="error.*">
<exit/>
</transition>
<state>
That is...
This also has consequences for how the 'src' attribute of <state> and <parallel> is handled. If the file "hello.scxml" contains
<?xml version="1.0"?>
<scxml version="1.0" final="true">
<onentry>
<log expr="'Hello world'"/>
</onentry>
<scxml>
then
... <state id="s1" src="hello.scxml"/> ...
is transformed into
...
<state id="s1" final="true">
<onentry>
<log expr="'Hello world'"/>
</onentry>
<state>
...
Note: This may not be a change proposal proper. The January draft is a bit vague when it comes to the generation of completion events. What I propose here may be exactly what they meant!
In Synergy SCXML, completion events of the form ID.done are generated for
Note that completion events are not generated for states that are neither final, parallel or sequential.
The completion events of children are used to detect when the completion events of their parents should be generated.
A completion event of the form ID.done is generated
That is:
An scxml process completes (terminates) when any of the toplevel states (children of <scxml>) generates a completion event.
A perhaps surprising consequence of this semantics is that the following scxml does not reach the state named "Final".
<scxml xmlns="http://www.w3.org/2005/07/SCXML"
version="1.0"
target="S">
<state id="S" target="S1">
<state id="S1" final="true"/>
<transition event="S1.done" target="Final"/>
</state>
<state id="Final" final="true"/>
</scxml>
The events generated for this example are
S1.done S.done main.done
and the trace looks like so:
main:<s> ==> S:<s> S:<s> ==> S1:<s>(final)
However, the following scxml does reach "Final":
<scxml xmlns="http://www.w3.org/2005/07/SCXML"
version="1.0"
target="P">
<parallel id="P">
<state id="S1" final="true"/>
<state id="S2">
<transition event="S1.done" target="Final"/>
</state>
</parallel>
<state id="Final" final="true"/>
</scxml>
Here the generated events are
S1.done Final.done main.done
and the trace:
main:<s> ==> P:<p> P:<p> ==> S1:<s>(final) P:<p> ==> S2:<s> S2:<s> = [S1.done] => Final:<s>(final)
The morale, and fortunately rather simple rule-of-thumb, is that if you want a state to listen to the *.done event of another state, then these states need to run in parallel, i.e. they have to be active at the same time.
Another way to implement (what is presumably) the intended behavior is to listen for a user defined 'done event' rather than the system generated one. Like so:
<scxml xmlns="http://www.w3.org/2005/07/SCXML"
version="1.0"
target="S">
<state id="S" target="S1">
<state id="S1">
<onentry>
<send event="S1.mydone"/>
</onentry>
</state>
<transition event="S1.mydone" target="Final"/>
</state>
<state id="Final" final="true"/>
</scxml>
This works like a charm, placing the following events in the queue:
S1.mydone send.successful Final.done main.done
and taking the following route through the chart:
main:<s> ==> S:<s> S:<s> ==> S1:<s> S1:<s> = [S1.mydone] => Final:<s>(final)
Finally, note that there is an example in the January draft section F.1 where a state tries to listen to its own *.done event. That won't work under the proposed semantics either, for the reasons stated above. Here's the significant part of this example:
<!-- Really simple state showing the basic syntax. -->
<state id="Test1">
<initial>
<transition target="Test1Sub1"/>
</initial>
<!-- Runs before we go into the substate -->
<onentry>
<log expr="'Inside Test1'"/>
</onentry>
<!-- Here is our first substate -->
<state id="Test1Sub1">
<onentry>
<log expr="'Inside Test1Sub1.'"/>
</onentry>
<onexit>
<log expr="'Leaving Test1Sub1'"/>
</onexit>
<!-- Go to Sub2 on Event1 -->
<transition event="Event1" target="Test1Sub2"/>
</state>
<!-- Here is the second substate
- It is final, so Test1 is done when we get here -->
<state id="Test1Sub2" final="true">
<onentry>
<log expr="'Inside Test1Sub2...'"/>
</onentry>
<onexit>
<log expr="'Leaving Test1Sub2'"/>
</onexit>
</state>
<!-- We get this event when we reach Test1Sub2. -->
<transition event="Test1.done" target="Test2"/>
<!-- We run this on the way out of Test1 -->
<onexit>
<log expr="'Leaving Test1...'"/>
</onexit>
</state>
Torbjörn Lager wrote this particular version, based on discussions with Fredrik Kronlid and based on a previous version written by Fredrik Kronlid and Torbjörn Lager.
The source code will be made available as soon as we've cleaned it up a bit.
We'll appreciate your feedback! Please write to the Synergy Team.