A brief tutorial on SCXML Templating
SCXML allows for reusability of a certain FSM externally. This is helpful when a certain sequence of states, events and actions occur frequently. Instead of repeating the sequence multiple times, an FSM can be designed seperately which can be referred as a state body using src attribute of a state.
Use Case
In a typical call control application, the sequence to connect to an end-point would be something like
waiting-for-connection [connection.alerting/conection.accept()] --> accepting-connection
accepting-connection [connection.connected] --> connection-connected
This sequence is a completely reusable one and can be templated
Example based on the use case above
<scxml xmlns="http://www.w3.org/2005/07/SCXML" version="1.0" xmlns:ccxml="http://stack.mera.com/CCXML" initialstate="wait-for-connection-request"> <state id="wait-for-connection-request"> <transition event="connection.alerting" target="wait-for-connection-connected"/> </state> <state id="wait-for-connection-connected"> <onentry> <ccxml:accept callid="incoming-line"/> </onentry> <transition event="connection.connected" cond="_eventdata.ID eq 'incoming-line'"> <send event="connection.connected"/> </transition> </state> </scxml>
SCXML Using the template above
<scxml xmlns="http://www.w3.org/2005/07/SCXML" version="1.0" xmlns:ccxml="http://stack.mera.com/CCXML" initialstate="wait-for-connection-request"> <state id="wait-for-connection-request" src="accept-connection.scxml?call-id=incoming-line"> <transition event="connection.connected" target="send-dtmf"/> </state> <state id="send-dtmf"> <onentry> <ccxml:send-dtmf digits="'1234'"/> </onentry> <transition event="dtmf.sent" target="bye"/> </state> <state id="bye" src="send-bye.scxml" final="true"/> </scxml>
_Note: not conforming to Working Draft -
As I understand the current Working Draft, a state element with a source attribute must not have children. See section 3.2.1. On the other hand, the implementation Commons SCXML v0.6 does accept both the src attribute and children for a state element at the same time. See issues.apache.org/jira/browse/SCXML-37
- Wolfgang Frech_
Explanation
The example above is fairly elaborate and simple. As we can see, the otherwise complicated State Engine has been broken into three seperate FSMs, send-bye.scxml and accept-connection.scxml being fairly reusable.
Posting to external JSPs
In the example above, we used an SCXML doc to post the content to, we could also have used a JSP/Velocity Template which is able to return an SCXML doc. Using a JSP/Velocity template we can make the SCXML dynamic. Going back to the example above, the accept-connection.scxml accepts the connection in the incoming-line variable, to use a different value we could have used a JSP like in the example below
<state id="foo${param.id}"> <!-- some content --> </state> placed at URL http://foo.bar/baz.jsp , then src="http://foo.bar/baz.jsp?id=1" will get us: <state id="foo1"> <!-- some content --> </state>
A word of caution
- When the src attribute is used, it is highly recommended to use a path-resolver (Provide Link). This is done while creating the SCXML
SCXMLDigester.newInstance(SCXML, PathResolver);
API If the PathResolver is not used (By passing a null), then the src is taken as the path of the file.
- In many cases, it might be required to re-use the same template in the same "master" scxml. i.e. In our example above, after the send-bye, it might be required to reconnect to the incoming-line. This will lead to the same states being duplicated and the SCXML Engine to be indeterminate. This can be avoided by using a param=value after the URL, this mangles the url and avoids duplicate IDs
Contributed By: Fasihullah Askiri