-
Notifications
You must be signed in to change notification settings - Fork 28
Plugin API for SCION 2.0 branch
This document proposes a plugin API for SCION.
In SCXML the following tags allow platform-specific extensions:
- Custom io processor (
send/@type
) - Custom invoke type (
invoke/@type
) - Custom action tags
This document describes an API for registering custom action tags on SCION.
The API for registering custom io processor is here.
Custom action tags are described in the SCXML specification:
Custom Action Elements can be defined in other specifications/namespaces and are responsible for performing actions on behalf of custom components. Logically Custom Action Elements can be thought of as a collection of actions and handlers to perform specific tasks.
http://www.w3.org/TR/scxml/#custom_action
This section describes a custom action element, and an example implementation using SCION's proposed plugin API.
Consider a custom action tag that does an HTTP GET request to a URL, and sends an event to the state machine when the HTTP request completes.
<scxml
xmlns="http://www.w3.org/2005/07/scxml"
xmlns:ext="http://foo.bar/"
name="custom-action-tag-example-1"
datamodel="ecmascript"
version="1.0">
<state id="fetching">
<ext:get url="http://google.com"/>
<transition event="response.success" target="succeeded"/>
<transition event="response.failure" target="failed"/>
</state>
<state id="succeeded"/>
<state id="failed"/>
</scxml>
scxml.registerCustomActionTags({
namespace : {
tagName : function template(action){
}
}
});
For example, the HTTP GET example would look like:
scxml.registerCustomActionTags({
"http://foo.bar/" : {
"get" : function (action) {
return "http.get(" + JSON.stringify(action.url) + ",function(res){" +
" this.send(res.statusCode === 200 ? 'response.success' : 'response.failure', res);" +
"}.bind(this));"
}
}
});
This would generate in the action code the following:
function $get_line_8_column_40(_event){
http.get("http://google.com",function(res){
this.send(res.statusCode === 200 ? 'response.success' : 'response.failure', res);
}.bind(this));
}
The action
parameter of the above template contains the following schema:
{
$line : integer
$column : integer
$type: string
}
It also contains an attribute for each attribute key-value pair from the source XML.
Consider an extension to the above example where the URL for the GET is
dynamic. The <get>
tag would need to reference the datamodel via a urlexpr
attribute:
<scxml
xmlns="http://www.w3.org/2005/07/scxml"
xmlns:ext="http://foo.bar/"
name="custom-action-tag-example-1"
datamodel="ecmascript"
version="1.0">
<datamodel>
<data id="foo" expr="'http://google.com'"/>
</datamodel>
<state id="fetching">
<ext:get urlexpr="foo"/>
<transition event="response.success" target="succeeded"/>
<transition event="response.failure" target="failed"/>
</state>
<state id="succeeded"/>
<state id="failed"/>
</scxml>
For example, the HTTP GET example would look like:
scxml.registerCustomActionTags({
"http://foo.bar/" : {
"get" : function (action) {
return "http.get(" + (action.url ? JSON.stringify(action.url) : action.urlexpr) + ",function(res){" +
" this.send(res.statusCode === 200 ? 'response.success' : 'response.failure', res);" +
"}.bind(this));"
}
}
});
This would generate in the action code the following:
function $get_line_8_column_40(_event){
http.get(foo, function(res){
this.send(res.statusCode === 200 ? 'response.success' : 'response.failure', res);
}.bind(this));
}
urlexpr
is exposed as a local variable to the $get_line_8_column_40
function.
The above example references a platform-specific http
variable.
The best approach to this is to add the http
module to the executionContext sandbox object
argument passed to model.prepare
.
npm can be used as infrastructure to package, version and distribute libraries of SCXML tags. An SCXML document can use a package.json to specify the particular tag library versions used in the associated SCXML.