Copyright © 2005 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark and document use rules apply.
This document describes SCXML, or the "State Chart eXtensible Markup Language". SCXML provides a generic state-machine based execution environment based on CCXML and Harel State Tables.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This document is the first Public Working Draft of SCXML for review by W3C Members and other interested parties, and has been developed by the Voice Browser Working Group (W3C Members only) as part of the W3C Voice Browser Activity.
SCXML is a candidate for the control language within VoiceXML 3.0 (currently under development by the Voice Browser working group), CCXML 2.0 (anticipated development in 2006 by the Voice Browser working group), and the multimodal authoring language (under development by the Multimodal Interaction working group).
Comments for this specification are welcomed to www-voice@w3.org (archives).
This document was produced under the 5 February 2004 W3C Patent Policy. The Working Group maintains a public list of patent disclosures relevant to this document; that page also includes instructions for disclosing [and excluding] a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) with respect to this specification should disclose the information in accordance with section 6 of the W3C Patent Policy.
Per section 4 of the W3C Patent Policy, Working Group participants have 150 days from the title page date of this document to exclude essential claims from the W3C RF licensing requirements with respect to this document series. Exclusions are with respect to the exclusion reference document, defined by the W3C Patent Policy to be the latest version of a document in this series that is published no later than 90 days after the title page date of this document.
Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
1 Terminology
2 Overview
3 Basic State Notation
3.1 SCXML
3.1.1 Properties
3.2 STATE
3.2.1 Properties
3.3 TRANSITION
3.3.1 Properties
3.4 PARALLEL
3.4.1 Properties
4 Pseudo-States
4.1 INITIAL
4.1.1 Properties
4.2 HISTORY
4.2.1 Properties
4.3 JOIN
4.3.1 Properties
4.4 SYNCH
4.4.1 Properties
5 Executable Content
5.1 Variables and
Expressions
5.1.1 <assign> and <var>
5.1.1.1
Overview
5.1.1.2
<var> Attribute Details
5.1.1.3
<assign> Attribute Details
5.2 Event
Control
5.2.1 <send>
5.2.1.1
Overview
5.2.1.2
Attribute Details
5.2.2 <cancel>
5.2.2.1
Overview
5.2.2.2
Attribute Details
5.3 Flow Control
Elements
5.3.1 <if>
5.3.1.1
Overview
5.3.1.2
Attribute Details
5.3.2 <elseif>
5.3.2.1
Overview
5.3.2.2
Attribute Details
5.3.3 <else>
5.3.3.1
Overview
5.3.3.2
Attribute Details
5.4 Debugging
Elements
5.4.1 <log>
5.4.1.1
Overview
5.4.1.2
Attribute Details
6 Conditional Expressions
6.1 Special
Predicates
6.1.1 In
6.1.1.1
Overview
6.1.1.2
Attribute Details
7 Related Work
A Open Issues
A.1 Empty Event Property
of Transition
A.2 Scoping Rules for
ID
A.3 State
Templates
A.4 XML Content in
Send
A.5 junction, choice,
fork, and join
A.6 Automatic
Logging
B Schema
C CCXML to SCXML Conversion
D Examples
D.1 Language
Overview
E An Overview of Harel State Table Notation
and Semantics
E.1 A Simple State
Machine
E.2 Executing Actions On
Entering And Exiting
E.3 Complex
States
E.4 Parallel
States
E.5 Concurrency And
Event Queues
E.6 Synchronizing And
Concurrency
E.7 Sync
Explained
E.8 Microwave
Oven
F References
[Definition: The key words must, must not, required, shall, shall not, should, should not, recommended, may, and optional in this specification are to be interpreted as described in [IETF RFC 2119].]
The terms base URI and relative URI are used in this specification as they are defined in [IETF RFC 2396].
This document outlines a state machine notation that combines concepts from CCXML and Harel State Tables. It is intended to be a general-purpose state machine language that can be used in multiple contexts, including VoiceXML 3.0, CCXML 2.0, and the MultiModal Interaction framework. CCXML [W3C CCXML 1.0] is an event-based state machine language designed to support call control features in Voice Applications (specifically including VoiceXML but not limited to it). The CCXML 1.0 specification defines both a state machine and event handing syntax and a standardized set of call control elements. Harel State Tables are a state machine notation that are part of UML [UML 1.5]. They offer a clean and well-thought out semantics for sophisticated constructs such as a parallel states. They have been defined as a graphical specification language, however, and hence do not have an XML representation. The goal of this document is to combine Harel semantics with an XML syntax that is a logical extension of CCXML's state and event notation. For an overview of the UML notation and a brief outline of its semantics, see E An Overview of Harel State Table Notation and Semantics, below.
For simplicity's sake, the language definitions below refer to the 'properties' of elements, without specifying whether said properties are attributes or children. The markup samples at the end of the document make specific decisions about what is an attribute and what is a child element, but we may revise these decisions as refine the definitions.
For concreteness sake, we use ECMAScript as the language for data elements, but the complete language definition will permit other languages such as XPath to be used as well.
SCXML
Top-level root element. Carries version information etc. We may decide that we don't need a special root element, particularly since the purpose of this notation is to be embedded in other languages, such as VoiceXML 3.0.
STATE
Holds the representation of a state machine.
id
Identifier for this state.
src
Optional URL of a file containing the
definition of this state. Any definitions within the body of the
state
element override those in the external file.
final
Boolean property indicating whether this is a
final state or not. Default value is false
. Final
states may not have substates or outgoing transitions. When a final
state is entered, a completion event "parentID.done" is generated,
where "parentID" is the id
of this state's parent
state.
onentry
Optional property holding executable
content to be run upon entering this state
.
onexit
Optional property holding executable content
to be run when exiting this state
.
transition
Defines an outgoing transition
from this state
. May occur 0 or more times.
state
Defines a sequential substate of the parent
state. May occur 0 or more times. Incompatible with the
parallel
property.
initial
A child which identifies initial state for
state machines that have substates. This child is required
if and only if the machine has one or more state
children.
history
A child which represents the descendant
state that the parent state was in the last time the system
transitioned from the parent. A transition with this state
as its target is in fact a transition to one of the other
descendant states of the parent. May occur 0 or more times.
parallel
Defines a set of parallel substates. May
occur 0 or 1 times. Incompatible with the state
property.
TRANSITION
Transition rules are triggered by events
and
conditionalized via guard-conditions
. The optional
property target
specifies the destination of the
transition, which may be a state
or a
parallel
region. If the target
property
on a transition
is omitted, then taking the transition
has the effect of leaving the machine in the same state after
invoking any executable content that is supplied via the
actions
property. Such a transition is equivalent to
an 'event' handler in HST notation. Note that this is different
from a transition
whose target
is its
source state. In the latter case, the state is exited and
reentered, triggering execution of its onentry
and
onexit
executable content.
The target
property may specify the destination by
id or in-line. In the latter case, the in-lined state is
private to the transition in the sense that no other
transition may take it as a target. This convention allows an
in-lined state to be used as a form of scratch state which is
visible only locally.
event
Property that specifies the trigger
for this transition. We have not determined if it is optional.
Wildcarded event names are supported.
cond
Optional guard condition. If it is present,
the transition is taken only if the guard condition evaluates to
true
.
target
Optional property that specifies the new
state
or parallel
element to transition
to. May be specified by reference or in-line. May occur multiple
times, but if more than one instance is present, all must specify
descendants of the same parallel
element.
target
may not co-occur with exit
)
exit
Used as a shorthand for defining a transition
to an empty final state. (Exclusive with target
) As an
example the following two transitions are the same:
<transition> <exit/> </transition> <transition> <target> <state final="true"/> </target> </transition>
actions
Immediate children of
transition
other than those listed above are
executable content that is run after the onexit
handler for this state and before the onentry
handler
in the target state.
PARALLEL
Wrapper element to encapsulate parallel state machines. The
parallel
element has onenter
and
onexit
properties analogous state
. In
addition, the parallel
element holds a set of
state
elements that execute in parallel and
join at the onexit
handler of element
parallel
. In particular, when all of the parallel
substates reach a final state, a completion event "ID.done" is
generated, where "ID" is the id
of the
parallel
element. Either the parallel
element or one of its ancestors can trigger a transition off this
event, at which time the onexit
handler of the element
will be executed.
For the parallel
element to be useful, each of its
state
substates must itself be a complex state, i.e.,
one with either state
or parallel
children. When the state machine enters the parent
parallel
element, it simultaneously enters each
child
state. Transitions wihthin the individual
child
elements operate normally, but there may not be
transitions between the child
elements since
that would violate the semantics of parallelism. However any of the
child
elements may take a transition outside
the parallel
element. When this happens, the
parallel
element and all of its child
elements are exited and the corresponding onexit
handlers are executed. The handlers for the child
elements execute first, in no determinate order, followed by that
for the parent parallel
element, followed by an
action
expression in the transition
element, and then the onentry
handlers in the
target
state.
The following elements are called 'pseudo-states' because they
do not have the full properties of states (for example they lack
onentry
and onexit
handlers) and do not
map to states in the underlying semantics of the language. However,
they can be used like states in many places. In particular, they
can often be the target
of transition
.
They are a notational shorthand allowing the simple statement of
some sophisticated control constructs.
INITIAL
This element represents the default initial state for a complex
state with sequential substates. Suppose state
S1 has
child states S11, S12, and S13. if the system is in S1, it must
also be in one (and only one) of S11, S12, or S13. A
transition
in a distinct state
S2 may take
S11, S12, or S13 as its target
, but it may also simply
specify the parent S1. In that case, the initial
child
of S1 specifies which of S11, S12, or S13 the system should
transition to.
id
Identifier for this pseudo-state
src
Optional URL of a file containing the
definition of this pseudo-state. Any definitions within the body of
the initial
element override those in the external
file.
transition
A conditionless transition (i.e., one
without a cond
or event
property). Such a
transition is always enabled and will be taken as soon as the state
is entered. The target
of the transition must be a
descendant of the parent state
of
initial
. if state
S1 has an
initial
child with a transition
with
target
S12, there is no semantic difference between a
transition
that takes S1 as its target
and one that takes S1's initial
child as a
target
and one that takes S12 as its
target
. The result in all three cases is that the
system enters both S1 and S12 as an atomic action, executing the
onentry
handlers of first S1 and then S12.
HISTORY
The history
pseudo-state allows for 'pause and
resume' control flow. Whenever a complex state
is
exited, its history
pseudo-state, if present, records
the state configuration at exit. Later a transition
taking the history
state as its target
allows the state
to pick up where it left off.
id
Identifier for this pseudo-state
src
Optional URL of a file containing the
definition of this pseudo-state. Any definitions within the body of
the initial
element override those in the external
file.
type
. Legal values are 'shallow' and 'deep', with
default value 'shallow'. if the value is 'shallow' then this state
records only the immediate children of the parent
state
. In this case a transition
with the
history
pseudo-state as its target
will
end up in the immediate child state that the parent was in the last
time it was exited. On the other hand, if this property is set to
'deep', the history
pseudo-state will remember nested
states. In this case a transition
with the
history
pseudo-state as its target
will
end up in the mostly deeply nested descendant state
the parent was in the last time it was exited.
transition
A conditionless transition (i.e., one
without a cond
or event
property). Such a
transition is always enabled and may be taken as soon as the state
is entered. This transition
represents the default
history state and indicates the state
to transition to
if the parent state
has never been entered before. if
type
is 'shallow', then the target
of
this transition
must be an immediate child of the
parent state
. Otherwise it can be any descendant
state
.
JOIN
The join
pseudo-state provides barrier logic
allowing the synchronization of defined threads of control. For a
discussion of its semantics see E An
Overview of Harel State Table Notation and Semantics.
SYNCH
The sync
state is actually a normal state, not a
pseudo-state, but it is included here because of its close
association with the join
pseudo-state. For a
discussion of its semantics see E An
Overview of Harel State Table Notation and Semantics.
Executable Content consists of actions that are performed when the selected handler is executed. In general, such content must be able to set variables, raise events, and invoke functionality in the underlying platform. On the other hand, Executable Content may not cause transitions or any form of change of state, except indirectly, by raising events that are then caught by transitions. There are a variety of possible forms for Executable Content, particularly since the capabilities of the underlying platform vary across implementations. The content presented here is closely based on that in CCXML. This is partly for reasons of backward compatibility, but also because CCXML's executable content is quite flexible, consisting of Flow Control Elements, Event Control Elements or Custom Action Elements.
Flow Control Elements are used to control the flow of execution within Executable Content.
Event Control Elements are used to control how and when events are sent from SCXML.
Custom Acton Elements can be defined in other
specifications/namespaces and are responsible for performing
actions on behalf of custom components. Logically Custom Acton
Elements can be thoughts of a collection of actions and handlers to
perform specific tasks. An example of this is a CCXML
<accept>
element that is a Custom Acton
Element:
<transition event="ccxml:connection.alerting" name="evt"> <ccxml:accept connectionid="evt.connectionid"/> </transition>
This could be written using a <send>
element
using the following syntax:
<transition event="ccxml:connection.alerting" name="evt"> <var name="connectionid" expr="evt.connectionid"/> <send targettype="ccxml" event="ccxml:accept" namelist="connectionid"/> </transition>
A more complicated example might be a CCXML
<createcall>
where you are both providing
variables and getting values back that using only the
<send>
syntax would be more complex as it would
need to be broken over several steps. For example:
<onentry> <ccxml:createcall dest="'tel:+18315552020'" connectionid="myConnectionID"/> </onentry>
Would need to be modeled in two steps using
<send>
as you would need to do something like
the following:
<onentry> <var name="dest" expr="'tel:+18315552020'"/> <send targettype="ccxml" event="ccxml:createcall" namelist="dest"/> </onentry> <transition event="ccxml:createcall.success" name="evt"> <var name="connectionid" expr="evt.connectionid"/> </transition>
The exact mappings between Custom Action Elements and
<send>
actions are to be defined in the
individual Custom Action Element specifications.
<assign>
and <var>
Variables are declared using the <var>
element and are initialized with the results of evaluating the optional
expr
attribute as an expression. If the
expr
attribute is not present in the
<var>
declaration, the variable is initialized
to undefined
. The values of variables may be
subsequently changed with <assign>
.
Variables are declared explicitly by <var>
:
<var name="sessionid" /> <var name="currentstate" expr="'initial'" />
Variables can be assigned new values using
<assign>
:
<assign name="currentstate" expr="'cleanup'" />
The implementation MUST evaluate the expression
contained in the expr
attribute of
<assign>
, and assign the results to the variable
referenced in the name
attribute.
Name | Required | Attribute Constraints | Type | Default Value | Valid Values | Description |
---|---|---|---|---|---|---|
name | true | Variable name | none | Valid Variable name | Indicates the name of the variable. | |
expr | false | Expression | none | Valid Expression | Indicates the new value of the variable. This is the initial value. |
Name | Required | Attribute Constraints | Type | Default Value | Valid Values | Description |
---|---|---|---|---|---|---|
name | true | Left Hand Side Expression | none | Variable | An left hand side expression evaluating to a previously defined
variable. The value of the attribute will receive the result of the
expr attribute. |
|
expr | true | Expression | none | Valid Expression | Indicates the new value of the variable. |
<send>
<send>
is used to send messages containing
events or other information directly to another SCXML Interpreter,
other external systems using an Event I/O Processor or to raise
events in the current SCXML session.
The event target of <send/>
is specified
using the target
and targettype
attributes. These attributes control how the platform should
dispatch the event to its final destination.
The target
attribute specifies the unique
identifier of the event target that the Event I/O Processor should
send the event to. This can be the value of a SCXML Session ID to
another SCXML session. In the case where you are using some other
Event I/O Processor this attribute should be able to describe how
to connect to the event destination (For example a SIP URL for
SIP-INFO messages or a HTTP URL for Web Services). If no
target
attribute is specified the default target is
the current SCXML session. If the value of the target
attribute is not supported, invalid or unreachable by the Event I/O
Processor the Platform MUST throw a
error.send.targetunavailable
event.
The targettype
attribute controls what Event I/O
Processor the event should be sent to. The default value of this
attribute is 'ssxml'. If the event targettype
specified is not supported the platform MUST throw a
error.send.targettypeinvalid
event.
A platform must support the following values for the
targettype
attribute:
Value | Details |
---|---|
scxml |
SCXML Session Event Processor. |
Platforms may support other types of Event I/O Processors, for example: Web-services, SIP or basic HTTP GET. However, platforms SHOULD name the Event I/O Processor beginning with "x-" to signify that they are platform dependent.
<send>
also specifies the content of the
message to be sent. <send>
may specify message
content in one of two ways (the following mechanisms are mutually
exclusive):
event
attribute with an OPTIONAL
namelist
The event
attribute specifies an expression that
returns the name of the event.
The namelist
attribute specifies a space separated
list of variables to be included with the message.
<var name="target" expr="'tel:+18005551212'"/> <var name="content" expr="'http://www.example.com/mycontent.txt'"/> <send target="target" targettype="'x-messaging'" event="'fax.SEND'" namelist="content"/>
xmlns
attribute with explicit content inline XML
content specifying the message to sent the
xmlns:<namespace>
defines a namespace for the
inline content
<send target="'csta://csta-server.example.com/'" targettype="'x-csta'" xmlns:csta="http://www.ecma.ch/standards/ecma-323/csta"> <csta:MakeCall> <csta:callingDevice>22343</callingDevice> <csta:calledDirectoryNumber>18005551212</csta:calledDirectoryNumber> </csta:MakeCall> </send>
If an explicit namespace is provided as in the xmlns attribute
of the <send>
, this namespace can be used to
validate the content of the <send>
. A namespace
specified on a <send>
applies only to the
attributes and content of the <send>
. Multiple
namespaces MAY be included in the
<send>
to associate message content with more
than one namespace.
When an explicit namespace is specified for the
<send>
, the content of the
<send>
is parsed but can be ignored by the
sending SCXML Interpreter until the <send>
is
executed. XML namespace identifiers contained in the
<send>
MUST be preserved and it is the
responsibility of the Event I/O Processor responsible for
forwarding events to the <send>
target to parse
the incoming message and remove the namespace prefix, if required
by the <send>
target.
The sending SCXML Interpreter MUST NOT alter the
content of the <send>
. The data contained within
a <send>
MUST be sent to the
destination specified in the target attribute of
<send>
using the Event I/O Processor specified
by the targettype attribute. When <send>
is used
with inline XML content, and the target is a SCXML session, the
mapping of that XML content to event object properties is
implementation-specific, and outside the scope of this
specification. Although the full set of requirements for the Event
I/O Processor is not within the scope of this specification, an
event processor sending an event to a SCXML Interpreter is required
to generate an event which can be processed in a SCXML Session. See
Section 9.1 for details regarding the processing of incoming events
by an SCXML Interpreter.
When a message is successfully sent to the target, a
send.successful
event will be thrown. Note that this
does not mean that the target processed the message successfully.
It is up to the target to generate events specific to the message.
These events are application specific.
If the send request fails, an event signifying the error will be returned to the SCXML Session. The failure events are documented at the end of this section.
Name | Required | Attribute Constraints | Type | Default Value | Valid Values | Description |
---|---|---|---|---|---|---|
event | false | This attribute may not be specified in conjunction with inline content | Expression | none | An expression which returns a character string that indicates
the type of event being generated. The event type may include
alphanumeric characters and the "." (dot) character. The first
character may not be a dot or a digit. Event type names are
case-insensitive. If neither the data attribute or
inline content is specified, an error.fetch event will
be thrown. If used in conjunction with the inline content, an
error.fetch will be thrown. |
|
target | false | Expression | none | A valid target URL | An expression returning the target location of the event. The
target attribute specifies the unique identifier of
the event target that the Event I/O Processor should send the event
to. |
|
targettype | false | Expression | scxml | scxml | An expression which returns a character string that specifies
the type of the Event I/O Processor that the event should be
dispatched to. Values defined by the specification are:
|
|
sendid | false | Left Hand Side Expression | none | Variable | An left hand side expression evaluating to a previously defined variable. The value of the attribute will receive an internally generated unique string identifier to be associated with the event being sent. If this attribute is not specified, the event identifier is dropped. | |
delay | false | Expression | '0s' | An expression which returns a character string in CSS2 [CSS2] format | The character string returned is interpreted as a time
interval. The send tag will return immediately, but
the event is not dispatched until the delay interval elapses.
Timers are useful for a wide variety of programming tasks, and can
be implemented using this attribute. Note: The queue
for sending events is maintained locally. Any events waiting to be
sent will be purged when the session that issued this request
terminates. |
|
xmlns:[YourNameSpacePrefix] | false | string | none | This returns a namespace identifying the contained message
format. More than one xmlns attribute may be
included. |
||
namelist | false | This attribute may not be specified in conjunction with inline content | Var List | none | List of Variable names | A list of zero or more whitespace separated CCXML variable
names to be included with the event. When an variable is included
with the event, its value is first converted into a string. If the
variable is an Object, the mechanism by which it is included is not
currently defined. Instead of including Objects directly, the
application developer may explicitly include the properties of an
Object. e.g. "date.month date.year". If used in conjunction with
the inline content, an error.fetch will be
thrown. |
hints | false | Expression | none | An expression. | The data returned contains information which may be used by the implementing platform to configure the event processor. The meaning of these hints is specific to the implementing platform and the event processor. |
When a SCXML program uses <send>
to send an
event and includes a delay
attribute, the
<cancel>
command will cancel the pending event,
if possible.
The cancel operation will cancel a pending event by removing it
from the event queue of the SCXML session from which it has been
sent. If the delay has expired and the event has already been
removed from the event queue, the <cancel>
request will fail and an error.notallowed
event will
be delivered to the event queue of the SCXML session that executed
the <cancel>
.
The <cancel>
element may be used to cancel
events delivered to local or remote SCXML sessions. Compliant SCXML
implementations are REQUIRED to support the cancellation
of local events but may choose not to support the cancellation of
remote events in which case an error.notallowed
event
should be thrown for such requests. The format of the event
identifier returned by a <send>
request, and
specified in the sendid
attribute of
<cancel>
, is implementation specific but is
expected to uniquely define events across SCXML sessions.
<if>
is a container for conditionally
executed elements. <else>
and
<elseif>
can optionally appear within an
<if>
as immediate children, and serve to
partition the elements within an <if>
.
<else>
and <elseif>
have no
content. <else/>
is a synonym for
<elseif cond="true"/>
.
Each partition within an <if>
is preceded by
an element having a cond
attribute. The initial
partition is preceded by the <if>
and subsequent
partitions by <elseif>
s (or
<else>
s). The first partition in document order
with a cond
that evaluates to true
is
selected. <else>
always evaluate to
true
. A partition may be empty.
If an <if>
has no immediate
<elseif>
or <else>
children,
the full contents of the <if>
will be selected
when the cond
attribute is true
.
<else>
was chosen to match similar concepts
in other languages, and supports examples such as
<if cond="..."> <!- selected when <if cond> is true -> <else/> <!- selected when <if cond> is false -> </if>
However, <else>
is a synonym for
<elseif cond="true"/>
, so an example such
as:
<if cond="..."> <!- selected when <if cond> is true -> <else/> <!- selected when <if cond> is false -> <else/> <!- never selected -> </if>
is also possible and must be interpreted as:
<if cond="..."> <!- selected when <if cond> is true -> <elseif cond="true"/> <!- selected when <if cond> is false -> <elseif cond="true"/> <!- never selected -> </if>
With this definition for <else>
, a valid XML
[XML] document is also a valid SCXML document.
<log>
allows an application to generate a
logging or debug message which a developer can use to help in
application development or post-execution analysis of application
performance. The manner in which the message is displayed or logged
is platform-dependent. The usage of label is platform-dependent.
The use of <log>
SHOULD have no other
side-effects on interpretation. <log>
is an empty
element.
Name | Required | Attribute Constraints | Type | Default Value | Valid Values | Description |
---|---|---|---|---|---|---|
label | false | Expression | none | An expression which returns a character string which may be used, for example, to indicate the purpose of the log. | ||
expr | true | Expression | none | An expression evaluating to a string to be logged. |
This section describes the content that can be placed in guard
conditions inside cond
elements in a
transition
. In general, a restricted subset of
executable content is permitted, namely that which evaluates to a
boolean and does not have side effects. (Note that in particular
send
is not permitted inside cond
.) In
addition to general side-effect free executable content, certain
extra predicates are defined, as defined below.
A number of other XML-based state machine notations have been developed, but none serves the same purpose as SCXML. XMI [UML XMI] is a notation developed for representing UML diagrams, including Harel State charts. However it is intended as a machine interchange format and is not readily authorable by humans. ebXML [OASIS ebXML] is a language for business process specification intended to support B2B e-commerce applications. It contains a state machine language that is in some ways similar to the one presented here, but its syntax and semantics are closely tied to its intended use in e-commerce. It is therefore not suitable as a general-purpose state machine language. XTND [XTND], also called XML Transition Network Definition, is a notation for simple finite state machines but lacks Harel's notions of hierarchical and parallel states and are thus not suitable for a general-purpose state machine that is semantically equivalent to Harel statecharts.
Need to define exactly how state templates work. Suppose the template contains a transition for event Foo with cond P1, while the in-line definition defines a transition for Foo with cond P2. Does the resulting state contain both transitions or just the second?
Resolution:
None recorded.
junction
,
choice
, fork
, and join
Do we need junction
, choice
,
fork
and join
pseudo-states? They are
mostly a graphical convenience in UML and don't add anything to the
actual semantics of the language. junction
and
choice
states have one or more incoming transitions
and multiple outgoing ones with a case-statement logic. Thus their
semantics are "if x go to S1, else if y go to S2 else go to S3".
They are thus equivalent to having multiple transitions with the
same conditions in the source state. Thus their only purpose is to
make the lines neater in a graphical representation. Similarly,
fork
pseudo-states have one or more incoming
transitions and multiple outgoing transitions which are all taken
simultaneously once the state is entered. The targets of the
outgoing transitions must all be the same parallel
region. A transition entering a fork pseudo-state is thus exactly
equivalent to one with multiple values for target
, one
for each of the outgoing transitions from the fork pseudo-state.
Finally the join
pseudo state has multiple incoming
transitions, which must all be from the same parallel region, and
one or more outgoing transitions. The outgoing transition is taken
only when all of the incoming ones have been taken. Thus the join
pseudo-state provide barrier logic allowing different threads of
control to wait for each other. But that functionality is already
present in our definition of parallel
.
Resolution:
None recorded.
Should we add some form of automatic logging, e.g., of all
events and transitions? This would be a convenience for authors and
could be controlled via a log-level attribute on
state
, allowing authors to control the amount of
logging on a per-state basis. Would we then need to specify the
format of the logged data? Whether it was written to a file or sent
to a database? Or can we just specify that certain data be logged
and leave all details up to the implementation?
Resolution:
None recorded.
A RELAX NG Schema is available for the markup proposed in this specification and examples
Download SCXML.rng
One of the goals of the SCXML activity is to make sure that the resulting language is compatible with CCXML and that there is an easy path for CCXML scripts to be converted to SCXML without major changes to the programing model or document structure. To help facilitate this the working group has developed a XSLT script to convert a CCXML document into SCXML.
Note: This XSLT assumes that the CCXML working group develops a standalone set of events and Custom Action Elements for SCXML. This XSLT is currently only a prototype and is currently only shown as an example of how a script like this may work in the future.
Download CCXMLtoSCXML.xsl
CCXMLtoSCXML.xsl:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ccxml="http://www.w3.org/2002/09/ccxml" xmlns="http://www.w3.org/2005/07/scxml" xmlns:str="http://exslt.org/strings" version="1.0"> <xsl:preserve-space elements="*"/> <xsl:output method="xml" standalone="yes" indent="yes" encoding="UTF-8"/> <xsl:template match="/ccxml:ccxml"> <!-- - - Take the <ccxml/> and map it into a <scxml/> - and set the intial state to CCXML. - This beast will only be a single-state - state machine as we handle CCXML's - state vars using cond's on the transition - elements. - --> <scxml version="1.0" initalstate="CCXML"> <!-- - - There really should ever be one of - these but we are going to do a for-each - just for the fun of it. - --> <xsl:for-each select="ccxml:eventprocessor"> <xsl:variable name="statevariable" select="@statevariable"/> <state id="CCXML"> <!-- - - If there is a statevar create the - var to hold it - --> <xsl:if test="@statevariable != ''"> <var> <xsl:attribute name="name"><xsl:value-of select="@statevariable" /></xsl:attribute> </var> </xsl:if> <!-- - - Process each of the ccxml <transition> - elements and map them in SCXML <transition>'s - --> <xsl:for-each select="ccxml:transition"> <transition> <!-- - - @event and @name move over without - really any magic. - --> <xsl:if test="@event != ''"> <xsl:attribute name="event"><xsl:value-of select="@event" /></xsl:attribute> </xsl:if> <xsl:if test="@name != ''"> <xsl:attribute name="name"> <xsl:value-of select="@name" /> </xsl:attribute> </xsl:if> <!-- - - @state and @cond require a bit of - munging to get to work right as - the CCXML states are modeled as - cond attributes in SCXML. - --> <xsl:choose> <xsl:when test="@state != '' and @cond !='' "> <xsl:attribute name="cond">(<xsl:for-each select="str:split(@state)">(<xsl:value-of select="$statevariable" /> == '<xsl:value-of select="." />')<xsl:if test="not(position()=last())"> || </xsl:if></xsl:for-each>) && (<xsl:value-of select="@cond" />)</xsl:attribute> </xsl:when> <xsl:when test="@state != ''"> <xsl:attribute name="cond"><xsl:for-each select="str:split(@state)">(<xsl:value-of select="$statevariable" /> == '<xsl:value-of select="." />')<xsl:if test="not(position()=last())"> || </xsl:if></xsl:for-each></xsl:attribute> </xsl:when> <xsl:when test="@cond != ''"> <xsl:attribute name="cond"> <xsl:value-of select="@cond" /> </xsl:attribute> </xsl:when> </xsl:choose> <!-- - - This should pick up all - the executable content - --> <xsl:apply-templates/> </transition> </xsl:for-each> </state> </xsl:for-each> </scxml> </xsl:template> <!-- - - The CCXML <if>/<elseif>/<else> elements - just need to be mapped into their SCXML versions. - --> <xsl:template match="ccxml:if"> <if> <xsl:attribute name="cond"><xsl:value-of select="@cond" /></xsl:attribute> <xsl:apply-templates/> </if> </xsl:template> <xsl:template match="ccxml:elseif"> <elseif> <xsl:attribute name="cond"><xsl:value-of select="@cond" /></xsl:attribute> <xsl:apply-templates/> </elseif> </xsl:template> <xsl:template match="ccxml:else"> <else> <xsl:apply-templates/> </else> </xsl:template> <!-- - - The CCXML <exit> also needs to be remaped. - --> <xsl:template match="ccxml:exit"> <exit/> </xsl:template> <!-- - - This should pick up all the executable content. - For this stuff we just copy it in keeping - the original namespace. - --> <xsl:template match="/ | @* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
This SCXML document gives an overview of the SCXML language and shows the use of it's state machine transition flows:
Note. In this example, the namespace URI http://www.w3.org/2005/07/vxml3 qualifies VoiceXML 3.0 markup. However, VoiceXML3.0 is currently under development by the Voice Browser Working Group and no specification has been published yet. The namespace URI is therefore only defined for this example.
<?xml version="1.0" encoding="us-ascii"?> <!-- A wrapper state that contains all other states in this file - it represents the complete state machine --> <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initalstate="Main"> <state id="Main"> <!-- its initial state is Test1 --> <initial> <transition> <target next="Test1"/> </transition> </initial> <!-- Really simple state showing the basic syntax. --> <state id="Test1"> <initial> <transition> <target next="Test1Sub1"/> </transition> </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 next="Test1Sub2"/> </transition> </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 next="Test2"/> </transition> <!-- We run this on the way out of Test1 --> <onexit> <log expr="'Leaving Test1...'"/> </onexit> </state> <state id="Test2"> <initial> <transition> <target next="Test2Sub1"/> </transition> </initial> <!-- This time we reference a state - defined in an external file --> <state id="Test2Sub1" src="Test2Sub1.scxml"/> <!-- This time we reference a state - defined in an external file and - use the templating support to add - an onexit hander. --> <state id="Test2Sub2" src="Template.scxml"> <onexit> <log expr="'Leaving Substate Test2Sub2'"/> </onexit> </state> <!-- Test2Sub2 is defined as final, so this - event is generated when we reach it --> <transition event="Test2.done"> <target next="Test3"/> </transition> </state> <state id="Test3"> <initial> <transition> <target next="Test3Sub1"/> </transition> </initial> <state id="Test3Sub1"> <onentry> <log expr="'Inside Test3Sub1...'"/> <!-- Send our self an event in 5s --> <send event="Timer" delay="5s"/> </onentry> <transition event="Timer"> <!-- Transition on to Test4. - This will exit both us and our parent. --> <target next="Test4"/> </transition> <onexit> <log expr="'Leaving Test3Sub1...'"/> </onexit> </state> <onexit> <log expr="'Leaving Test3...'"/> </onexit> </state> <state id="Test4"> <onentry> <log expr="'Inside Test4...'"/> </onentry> <!-- Here we use the inline features of - target to create our scratch state.--> <initial> <transition> <target> <state id="Test4Sub1" > <onexit> <log expr="'Leaving Test4Sub1...'"/> </onexit> <!-- This transition causes the state to exit immediately - after entering Test4Sub1. The transition has no event or guard - so it is always active --> <transition> <target next="Test5"/> </transition> </state> </target> </transition> </initial> </state> <state id="Test5"> <onentry> <log expr="'Inside Test5...'"/> </onentry> <initial> <transition> <target next="Test5P"/> </transition> </initial> <!-- Fire off our parallel states --> <parallel id="Test5P"> <state id="Test5PSub1" final="true"> <onentry> <log expr="'Inside Test5PSub1...'"/> </onentry> </state> <state id="Test5PSub2" final="true"> <onentry> <log expr="'Inside Test5PSub2...'"/> </onentry> </state> <onexit> <log expr="'all parallel states done'"/> </onexit> </parallel> <!-- The parallel states are all final, so this - event is generated immediately --> <transition event="Test5P.done"> <target next="Test6"/> </transition> </state> <!-- - This state shows invocation of external component - We will use CCXML + VoiceXML actions as an example - as it is a good smoke test to show how it all - fits together. - Note: Odds are in a real app you would - split this over several states but we - are trying to keep it simple here. --> <state id="Test6" xmlns:ccxml="http://www.w3.org/2002/09/ccxml" xmlns:v3="http://www.w3.org/2005/07/vxml3"> <onentry> <!-- - Use <send> to run a createcall using the - CCXML component / Event I/O Processor --> <var name="dest" expr="'tel:+18315552020'"/> <send targettype="ccxml" event="ccxml:createcall" namelist="dest"/> </onentry> <transition event="ccxml:connection.connected" name="evt"> <!-- - Here we use example V3 - Custom Action Elements instead of send . --> <v3:form id="HelloWorld"> <v3:block><v3:prompt>Hello World!</v3:prompt></v3:block> </v3:form> </transition> <!-- - Here we are using the low level <send> - element to run a v3 form. Note that the event "v3:HelloWorld.done" is assumed either to be set/sent explicitly by the v3:form code or implicitly by some process outside of the v3:form --> <transition event="v3:HelloWorld.done" name="evt"> <var name="src" expr="'helloworld2.vxml'"/> <var name="id" expr="'HelloWorld'"/> <send targettype="v3" event="v3:formstart" namelist="src id"/> </transition> <transition event="v3:HelloWorld2.done" name="evt"> <ccxml:disconnect connectionid="evt.connectionid"/> </transition> <transition event="ccxml:connection.disconnected"> <!-- - Here we are using the <exit/> shorthand to - move ourself to a final state. - In this example you could do <target next="Done"/> - and get the same result. --> <exit/> </transition> <!-- Transitions to handle events generated by the component - component invoked successfully. this transition has no target - so Test6 is not exited. - We are just going to log tha we were able to send an event. --> <transition event="send.successful"> <log expr="'Event was able to be sent'"/> </transition> <!-- - If we get an error event we move to the Done state that - is a final state. --> <transition event="error.send"> <log expr="'Sending to and External component failed'"/> <target next="Done"/> </transition> <onexit> <log expr="'Finished with external component'"/> </onexit> </state> <!-- This final state is an immediate child of Main - when we get here, Main.done is generated. --> <state id="Done" final="true"/> <!-- End of Main > --> </state> </scxml>
<?xml version="1.0" encoding="us-ascii"?> <scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml"> <!-- - - This is our template state. - We end up referencing this in the - Main.scxml code. - --> <state id="Template" final="true"> <onentry> <log expr="'Loaded the template'"/> </onentry> </state> </scxml>
<?xml version="1.0" encoding="us-ascii"?> <scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml"> <!-- - - This is an example substate defined in - an external file referenced by Main.scxml. - --> <state id="Test2Sub1"> <onentry> <log expr="'Inside Test2Sub1'"/> </onentry> <transition event="Event2"> <target next="Test2Sub2"/> </transition> </state> </scxml>
The event processing model and the semantics of states and transitions are defined in detail in the UML specification [UML 1.5]. Nevertheless it is worth outlining some of their salient features here. The most basic concepts are states and transitions. Diagram 1 shows a simple state machine with three states S1, S2, and S3.
SCXML Equivalent
<?xml version="1.0" encoding="us-ascii"?> <scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml"> <state id="S1"> <transition event="Event1"> <target next="S2"/> </transition> </state> <state id="S2"> <transition event="Event2"> <target next="S1" cond="X>0"/> </transition> <transition event="Event2"> <target next="S3" cond ="X<0"/> </transition> </state> <state id="S3"> </state> </scxml>
These states linked by transitions, which are triggered by events. In this example State S1 transitions to state S2 when the event Event1 occurs. This is the only way the system can move from S1 to S2, since it is the only transition between those two states. Any other events that occur while the system is in S1 will therefore be ignored. The logic in S2 is slightly more complex. It has two transitions, both triggered by event Event2. Both transitions have guard conditions that check the value of the variable X. If X < 0, S2 will transition to S3 when Event2 occurs. If X > 0, it will transition back to S2. Note that there is no condition covering the case where X = 0. Therefore the system will remain in state S2 if X = 0 when Event2 occurs. As in state S1, all events not mentioned in transitions will be ignored.
OnEntry and OnExit handlers are a useful feature of Harel State Tables. They allow code to be embedded in states that will be executed whenever the state is entered or exited. In Diagram 2 we see the same three states, but now S1 has an OnEntry handler that decrements X , while S2 has an OnExit handler that also decrements X. S3 has both OnEntry and OnExit handlers, both of which increment X. Now suppose that X has a current value of 2, and that the system enters S1. When it does so, X is decremented to 1. When Event1 occurs, the system will transition to S2, as before. Now when Event2 occurs, X is set to 1, so the system will transition back to S1. As the system exits state S2, the OnExit handler will decrement X to 0. Note that this happens after the transition is selected and the guard condition has been evaluated. X. The entry into S1 decrements X again to -1. Now if Event1 occurs again and the system returns to S2, it will transition to S3 when Event2 occurs, since X is now < 0. Leaving S2 will decrement X again, but entering S3 will increment it, so X = -1 when the system is in S3. S3 has no transitions so the system will stay in S3 forever. However if a transition is added to S3, the OnExit handler in S3 will set Y to 0 when S3 is exited.
SCXML Equivalent
<?xml version="1.0" encoding="us-ascii"?> <scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml"> <state id="S1"> <onentry> <assign name="X" expr="X--"/> </onentry> <transition event="Event1"> <target next="S2"/> </transition> </state> <state id="S2"> <transition event="Event2"> <target next="S1" cond= "X > 0"/> </transition> <transition event="Event2"> <target next="S3" cond ="X > 0"/> </transition> <onexit> <assign name="X" expr="X--"/> </onexit> </state> <state id="S3"> <onentry> <assign name="X" expr="X++"/> </onentry> <onexit> <assign name="Y" expr="0"/> </onexit> </state> </scxml>
Of particular interest is the concept of a complex state, namely one that has substates. In Diagram 3 below, the State S1 now has two substates, labeled S11 and S12.
SCXML Equivalent
<?xml version="1.0" encoding="us-ascii"?> <scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml"> <state id="S1"> <state id="S11"> </state> <state id="s12"> </state> <initial> <transition> <target next="S11"/> </transition> </initial> </state> </scxml>
In this particular case, S1 has sequential substates.
When a state machine is in a state with such substates, it must
also be in one and only one of the substates. The substates have a
kind of "Or" semantics and can be thought of as representing a
decomposition of the parent state. A transition moving the system
to S1 may specify S11 or S12 as its target
directly.
However, to handle the case where it doesn't, S1 contains an
initial
element defining the default substate that it
will start in if the transition simplify specifies S1 as its
destination. In Diagram 3, the default substate is S11.
In addition to sequential substates, Harel State Charts provide
concurrent substates, which represent a form of "And"
logic. When a state machine is in a state with concurrent substates
it must be simultaneously in each of the concurrent child
states. The concurrent child states operate independently until
they all terminate (normally by reaching terminal child states) at
which point the parent state also terminates. Concurrent substates
thus represent fork and join logic. They are represented in our
notation by the parallel
tag. Diagram 4 below
represents an elaboration of Diagram 3. First of all, State S11 has
been decomposed into further sequential substates, S111 and S112,
with S111 being the default initial state. Secondly, concurrent
substates S121, S122, and S123 have been added to State S12.
SCXML Equivalent
<?xml version="1.0" encoding="us-ascii"?> <scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml"> <state id="S1"> <state id="S11"> <state id="S111"/> <state id="S112"/> <initial> <transition> <target next="S111"/> </transition> </initial> </state> <state id="s12"> <parallel> <state id="S121"/> <state id="S122"/> <state id="S123"/> </parallel> </state> <initial> <transition> <target next="S11"/> </transition> </initial> </state> <state> </state> </scxml>
As Diagram 4 shows, the notion of complex state is fully recursive, so that the child states of a complex parent may themselves have sequential or concurrent children. Thus a complex state machine is not normally in a single state, but in a configuration of compatible states. Applying the rules for sequential and concurrent states recursively in Diagram 4, we see that when the machine is in S1 it must also be in S11 or S12. When the machine is in S11, it must be in S111 or S112. When the machine is in S12, on the other hand, it must simultaneously be in all three substates S121, S11 and S1123. Thus there are 3 legal configurations they machine can be in: S1 plus S11 plus S111, S1 plus S11 plus S112, and S1 plus S12 plus S121, S122, and S123.
The Harel semantics for transitions is based on the notion of an
underlying event queue. At any given point, the state machine is in
a specific configuration of states. If there is an event in the
queue, it is processed according to the given state configuration,
and a transition may be triggered. The transition is then taken and
it and all actions associated with it are executed before the next
event in the queue is examined. Of particular interest is the way
that onexit
and onevent
handlers interact
with transitions. Suppose the machine is in state S2 (which is not
shown in the diagram) and an event occurs which triggers a
transition to state S112 in Diagram 4. In this case, the machine
first leaves S2, executing S2's onexit
handlers. It
then executes any actions
in the selected transitions.
Then it enters S1, S11, and S112 executing their
onentry
handlers in that order. Only when all these
actions have been executed will the machine check its queue for
another event. Suppose that there is an event in the queue and it
triggers a transition from S112 to S12. Going to S12 entails
leaving both S112 and S11, so both their onexit
handlers fire in that order, before the actions
in the
transition. (Note that the onexit
handlers fire in the
reverse order of the onentry
handlers.) Since S11 and
S12 are both substates of S1, this transition does not entail
leaving S1 so its onexit
handler does not fire. After
the transition's actions
, S12's onentry
handler will fire. Furthermore, the semantics of parallel states
requires that entering S12 also involves entering each of its
concurrent substates simultaneously. Therefore the
onentry
handlers for S121, S122, and S123 will all
fire after the one for S12. Since entry into the parallel substates
is simultaneous, however, there is no guarantee on the order in
which the three substate handlers fire.
Complex state configurations also interact with the selection of the transition to execute. First off, note that even a simple state may contain multiple transitions that match a given event. For example State S1 may contain two transitions, T1 which is triggered by event E1 with guard Cond1, and T2 which is also triggered by E1, but with a different guard expression Cond2. If the machine is in S2 when event E1 is taken from the queue and processed, it is possible that both Cond1 and Cond2 will evaluate to true. In this case, we will say that both T1 and T2 are enabled, but only one of them can be selected and executed. In the case of a single state, we will use document order as the tie-breaker, choosing whichever transition occurs first in the definition of S1. With complex states, the issue is more difficult. Returning to Diagram 4, suppose that we are in the complex configuration S1, S11, and S112, when event E1 is processed. It is possible that all three states, S1, S11, and S112, contain transitions that are enabled. In this case, we start in the innermost state S112. If it has an enabled transition, we select it (using document order as a tie-breaker if it has more than one.) If S112 does not contain an enabled transition, we look in S11 and then in S1. Thus the most narrowly scoped transition wins. The motivation for this choice becomes clear when we remember that sequential substates are decompositions of the parent state. Thus S112 is a refinement of S11 and S11 in turn is a refinement of S1. The innermost state thus "knows the most" about the situation so its transitions are preferred to those in outer states, which can be treated as defaults or fallbacks.
In the case of concurrent substates, the event is processed by all concurrent states simultaneously and they select their transitions independently. Thus if we are in S1, S12 and parallel substates S121, S122, and S123, any event will be processed by S121, S122, and S123 simultaneously, and they may all select transitions. This makes most sense if all three states are themselves complex and the event is triggering transitions among their substates. If none of the three states handles the event, we move to S12 and then to S1.
Although parallel substates run independently their operations
can be coordinated by means of Join and Synch states. The Join
pseudo-state is has multiple incoming transitions and one or more
outgoing transition. The incoming transitions must be unconditional
(i.e., they cannot have cond
or event
properties.) The outgoing transitions on the join
may
not have event
triggers and at least one must lack a
cond
guard condition. Thus when the join
pseudo-state is finally entered, there is always a transition that
can be taken immediately. The join
pseudo-state is not
entered until all its incoming transitions are enabled.
Thus the various threads of control wait in their current states
until they are all ready to enter the join
, at which
point they all enter simultaneously and an outgoing transition is
selected.
Now suppose we have two parallel states, S1 and S2, with sequential substates S11, S12, S13 and S21, S22 and S23, as shown in Diagram 5.
SCXML Equivalent
<?xml version="1.0" encoding="us-ascii"?> <scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml"> <state> <parallel> <state id="S1"> <state id="S11"> <transition> <target next ="S12"/> </transition> </state> <state id="S12"> <transition> <target next="S13"/> </transition> </state> <state id="S13"/> </state> <state id="S2"> <state id="S21"> <transition> <target next ="S22"/> </transition> </state> <state id="S22"> <transition> <target next="S23"/> </transition> </state> <state id="S23"/> </state> </parallel> </state> </scxml>
Given the basic Harel semantics S1 and S2 will function
independently, so that S1 will move from S11 to S12 to S13 without
regard to what S2 is doing, and vice-versa. But now suppose that we
want to ensure that S2 does not transition from S22 to S23 until S1
has left S11. Diagram 6 shows how we can do this using
join
and sync
states.
SCXML Equivalent
<?xml version="1.0" encoding="us-ascii"?> <scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml"> <state> <parallel> <state id="S1"> <state id="S11"> <transition> <target next ="S12"/> <target next="synch1"/> </transition> </state> <state id="S12"> <transition> <target next="S13"/> </transition> </state> <state id="S13"/> </state> <state id="S2"> <state id="S21"> <transition> <target next ="S12"/> </transition> </state> <state id="S22"> <transition> <target next="j1"/> </transition> </state> <state id="S23"/> </state> <sync id="synch1"> <transition> <target next="j1"/> </transition> </sync> <join id="j1"> <transition> <target next="S23"/> </transition> </join> </parallel> </state> </scxml>
We have inserted a join
pseudo-state between S22
and S23, with a conditionless incoming transition from S22 and a
conditionless outgoing transition to S23. (The join
pseudo-state is represented as a vertical bar with multiple
incoming transitions and a single outgoing transition.) We also
added a sync
state with a conditionless outgoing
transition to the same join
. Then we took all the
transitions that leave S11 and have them branch to include the
sync
state as an extra target. (In the diagram this is
shown by inserting a 'fork' vertical bar, with a single incoming
transition and multiple outgoing transitions. In our SCXML
notation, we would use multiple values in the target
element). Now when the machine reaches S22, it will wait until the
sync
state is active (and therefore ready to
transition) before entering the join
and transitioning
to S23. When S1 is ready to leave S11, it in effect branches
control, with its normal execution continuing along one branch of
the transition
while the other branch enters the
sync
state, which triggers the join
and
allows S2 to proceed. Note that S1 may reach the sync
state before or after S2 reaches S22. In either case, the combined
effect of the sync
state and the join
is
to allow S1's processing to continue as before, while ensuring that
S2 will wait in S22, if necessary, for the signal that S1 has left
S11.
The sync
state is really serving as a buffer to
keep the effect of the join
from propagating back into
S1. For example, it would be possible to omit the sync
state and connect S11's branching transition directly to the
join
. However, in that case, if S1 was ready to leave
S11 before S2 reached S22, by the semantics of the
join
, S1 would have to block in S11 waiting for S2.
This is not the behavior we want because the purpose of the
synchronization is to control the behavior of S2 without changing
the flow of S1. If we want to synchronize multiple regions, so that
both S2 and S3 would wait until S1 left S11, we can use multiple
sync
states, one for S2 and one for S3, and have the
transition
from S11 branch to both of them.
The sync
state uses an internal counter to keep
track of how often it has been entered and exited, augmenting the
counter when it is entered and decrementing it when it is exited.
The sync
state will take its outgoing transition only
when the counter is positive. The bound
value puts a
limit on how large a value the counter can hold. For example,
setting bound
to 1 turns the state into a binary
semaphore, that can be exited only once no matter how often it has
been entered. The default value for bound
is
unlimited.
For an example of the use of a higher bound, consider states S1
and S2 as before, but now suppose that we want to restrict S2 to
wait in S21 until S1 exits S11 and to wait in S22 until S1 exits
S12. We could use two separate sync
steps for this, but
one will suffice, as Diagram 7 shows.
SCXML Equivalent
<?xml version="1.0" encoding="us-ascii"?> <scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml"> <state> <parallel> <state id="S1"> <state id="S11"> <transition> <target next ="S12"/> <target next="synch1"/> </transition> </state> <state id="S12"> <transition> <target next="S13"/> <target next="synch1"/> </transition> </state> <state id="S13"/> </state> <state id="S2"> <state id="S21"> <transition> <target next ="S12"/> </transition> </state> <state id="S22"> <transition> <target next="j1"/> </transition> </state> <state id="S23"/> </state> <sync id="synch1"> <transition> <target next="j1"/> </transition> <transition> <target next="j2"/> </transition> </sync> <join id="j1"> <transition> <target next="S23"/> </transition> </join> <join id="j2"> <transition> <target next="S23"/> </transition> </join> </parallel> </state> </scxml>
Here we have branching transitions from S11 and S12, and two
outgoing transitions, one to a join
between S21 and
S22, and another to a join
between S22 and S23.
Suppose S1 races ahead of S2, moving from S11 to S12 to S13. The
sync
state will have been entered twice, so its
counter will be 2. When S2 is ready to leave S21, the
sync
state will be ready and take the transition to the
join, decrementing its counter to 1. When S2 is ready to leave S2,
the fact that the counter is still positive means that the
sync
state will still be active and ready to take the
transition to the join
.
This example implements a simple microwave oven that can be in one of two states:
StateOn --- the oven is running
Off --- the oven is turned off
on
itself has two substates:
The oven responds to three external event sources:Cooking --- the oven is cooking
Idle --- the oven is idle
Door open/close
Timer that tracks cook-time
Power button
SCXML Equivalent:
<?xml version="1.0"?> <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initialstate="off"> <!-- trivial microwave oven example --> <state id="off"> <!-- off state --> <transition event="turn_on"> <target next="on"/> </transition> </state> <state id="on"> <initial> <transition> <target next="idle"/> </transition> </initial> <!-- on/pause state --> <onentry> <!-- we assume the cook_time is passed in as a context parameter --> <if cond="${empty cook_time}"> <!-- default setting --> <var name="cook_time" expr="${5}"/> </if> <!-- again, door_closed should be a part of a global context --> <if cond="${empty door_closed}"> <!-- default setting --> <var name="door_closed" expr="${true}"/> </if> <!-- timer variable --> <var name="timer" expr="${0}"/> </onentry> <transition event="turn_off"> <target next="off"/> </transition> <transition cond="${timer ge cook_time}"> <target next="off"/> </transition> <state id="idle"> <transition cond="${door_closed}"> <!-- default immediate transition --> <target next="cooking"/> </transition> <transition event="door_close"> <assign name="door_closed" expr="${true}"/> <!-- start cooking --> <target next="cooking"/> </transition> </state> <state id="cooking"> <transition event="door_open"> <assign name="door_closed" expr="${false}"/> <target next="idle"/> </transition> <transition event="time"> <assign name="timer" expr="${timer + 1}"/> <target next="cooking"/> </transition> </state> </state> </scxml>
Next, we show the same microwave example, but this time
implemented using parallel
.
SCXML Equivalent:
<?xml version="1.0"?> <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initialstate="oven"> <!-- trivial microwave oven example --> <!-- using parallel and In() predicate --> <state id="oven"> <parallel id="parts"> <state id="engine"> <transition> <target next="off"/> </transition> <state id="off"> <!-- off state --> <transition event="turn_on"> <target next="on"/> </transition> </state> <state id="on"> <transition> <target next="idle"/> </transition> <!-- on/pause state --> <onentry> <!-- we assume the cook_time is passed in as a context parameter --> <if cond="${empty cook_time}"> <!-- default setting --> <var name="cook_time" expr="${5}"/> </if> <!-- timer variable --> <var name="timer" expr="${0}"/> </onentry> <transition event="turn_off"> <target next="off"/> </transition> <transition cond="${timer ge cook_time}"> <target next="off"/> </transition> <state id="idle"> <transition cond="${In('closed')}"> <target next="cooking"/> </transition> </state> <state id="cooking"> <transition cond="${not In('closed')}"> <target next="idle"/> </transition> <transition event="time"> <assign name="timer" expr="${timer + 1}"/> <target next="cooking"/> </transition> </state> </state> </state> <state id="door"> <initial> <transition> <target next="closed"/> </transition> </initial> <state id="closed"> <transition event="door_open"> <target next="open"/> </transition> </state> <state id="open"> <transition event="door_close"> <target next="closed"/> </transition> </state> </state> </parallel> </state> </scxml>