This document describes and provides instructions for using OpenCloud’s FSM Tool to automate development of state-machine-based services for the Rhino SLEE.
The instructions in this section assume familiarity with JAIN SLEE and Rhino development, and the OpenCloud XDoclet tool. |
Topics
An overview of finite state machines (FSMs), FSM Tool finite state machine, FSM specifications, the FSM execution model, and how OpenCloud’s FSM Tool implements a FSM for the Rhino SLEE |
|
How FSM works with Rhino, using the FSM specification to code FSMs, current and planned features of the FSM Tool, and a sample FSM design |
|
Steps to download, install, and walk through a sample application developed with FSM Tool |
|
Instructions for developing a component with FSM Tool, including writing the FSM specification, generating an SBB and POJO FSM classes, extending the generated SBB and supporting classes, compiling, packaging, deploying, documenting, and tracing; plus configuring the FSM Tool Ant task for code generation; and descriptions and examples of common patterns in the FSM specification DSL |
|
A reference for the FSM definition language syntax |
|
A reference for the FSM definition language grammar. |
Other documentation for the FSM Tool can be found on the FSM Tool product page.
About FSM and the FSM Tool
OpenCloud’s FSM Tool is a lightweight service-creation tool designed to simplify service creation for the Rhino SLEE.
It powers the design, specification, implementation, testing, and documentation of JAIN SLEE Service Building Blocks (SBBs). From the developer’s perspective, the tool ensures that the specification and implementation artifacts remain completely accurate and synchronized throughout the development and maintenance life cycle of each component.
The following overview describes:
-
What is an FSM? — the abstract concept behind the FSM tool, linking states, transitions, and actions
-
What is an FSM Tool FSM? — how the FSM concept is applied to the processes involved in software engineering
-
What’s in an FSM Tool FSM specification? — how FSM Tool FSM-based specification can be used to automate creating executables
-
How does an FSM Tool FSM work? — a flowchart and explanation of how an FSM Tool FSM works
-
How the OpenCloud FSM Tool implements a FSM — how OpenCloud’s FSM Tool implements an FSM for the Rhino SLEE.
What is an FSM?
A finite state machine (FSM) is a behavioural model that consists of:
-
a set of states
-
a set of transitions between those states
-
actions in response to events or transitions.
Example: opening and closing a door
The Wikipedia FSM entry gives the following example of an elevator door opening and closing:
Finite State Machine | |
---|---|
|
|
Moore and Mealy FSMs
FSMs are classified as Moore or Mealy machines. Moore machines use only entry actions, and their output depends only on states. Mealy machines use only input actions, and their output depends on input and states. The illustration at left is an example of a Moore FSM. The same Wikipedia article (referenced at left) gives a related example of a Mealy machine:
Mealy Machine | |
---|---|
|
While Moore machines are often simpler, Mealy machines often have fewer states. |
What is an FSM Tool FSM?
An FSM Tool finite state machine (FSM) is an FSM that implements only the behavioural aspects of a JSLEE component.
Moore meets Mealy
An FSM Tool FSM is also a hybrid state machine model, in that it incorporates features of both Moore and Mealy FSMs. FSM Tool FSMs use three types of actions:
-
input (like a Mealy machine)
-
entry (like a Moore machine)
-
exit (an additional feature, useful for application requirements such as canceling timers).
FSM Tool FSM and communications development
OpenCloud has proven FSM Tool FSM’s effectiveness for large communications systems development. Our software developers have found it to be a flexible and easy-to-use model, with a well-defined language. FSM Tool FSM bridges the gap between the design/requirements/specification and implementation, like this:
-
Developers write an FSM Tool FSM specification that fully describes the behaviour of a software component.
-
They directly extend the specified behavioural model, adding implementations of the actions defined in the spec.
-
The FSM Tool FSM then automatically creates a software executable.
Inputs and actions
FSM Tool FSM inputs and actions define the interface between the behavioural model and the implementation:
-
Inputs are flags — they can be either 'set' or 'unset'.
-
Actions are unparameterized names or references (which are later mapped to specific Java method names in the implementation).
Using inputs and actions, the FSM Tool FSM provides a clean separation between the specification of behaviour and its implementation. This means that software and design evolve together, always in sync.
What’s in an FSM Tool FSM specification?
An FSM Tool FSM Specification consists of the following elements:
Element | Description | Explanation |
---|---|---|
States |
application states |
A finite number of states, each representing a point the application has reached in its execution, and possible future execution steps. |
Transitions |
conditional expressions of inputs which result in a transition from one state to another |
A change from one state to another, plus a guard condition, whereby the transition only happens if the condition is true. |
Input actions |
actions executed as a function of the current state and inputs |
References to logic in the implementation, executed when the FSM is in a particular state, receives a particular input, and a condition evaluates to true. |
Exit actions |
actions executed on transitioning away from a state |
A list of named references to logic in the implementation, executed in the source state at the beginning of a transition. |
Entry actions |
actions executed on transitioning to a state |
A list of named references to logic in the implementation, executed when reaching the sink state at the end of a transition. (Actions executed on transition |
Action dictionary |
names of actions to be executed |
A declared set of actions used in the FSM states' input, exit, and entry actions. |
Endpoints |
hubs for communication between FSMs |
A declared name which can be used when referring to an input, thus indicating that the input is expected to be received through the endpoint from another FSM. Additionally, each endpoint can have an associated SLEE activity context or parent SBB local reference. |
Input dictionary |
flags raised to indicate the arrival of an event or other condition |
A declared set of inputs used in conditional expressions of input actions or transitions. Additionally, inputs can have an associated data object. |
Conditions |
Boolean algebraic conditional expression |
Constructed using AND and OR operators on inputs. In FSM Tool, there is currently no concept of a NOT operator for conditional expressions. A NOT can be simulated by creating and setting a diametrical input for the input you want to negate. For example, to negate |
How does an FSM Tool FSM work?
The FSM Tool FSM execution model works like this:
|
|
During execution, the FSM uses an Input Register to store the currently set inputs (and their associated data objects). The FSM execution algorithm uses two "views" of the Input Register:
An FSM cycle will only ever perform a single execution cycle before returning to check for changes to the scheduled view of the input register or if their was a transition. |
How the OpenCloud FSM Tool implements a FSM
With OpenCloud’s FSM Tool, developers no longer need to hand code and maintain a complex hierarchy of state machines in Java. The tool formally defines a service’s state machines, in a domain-specific language — and automatically implements state machine behaviour — ready for use in Rhino.
Transient and durable inputs
The FSM Tool implements an FSM using transient and durable inputs:
-
The tool automatically unsets a transient input at the end of an execution cycle.
-
The tool does not automatically unset durable inputs.
Cutting out the interpreter
Traditional implementations of FSMs store the FSM specification in a table structure, and then execute it by using an FSM interpreter. By contrast, the FSM Tool generates Java code from the FSM specification — and compiles it directly. This approach reduces the overhead when compared with an the interpreter approach.
Using FSM Tool, generated code can be as efficient as handwritten. |
Support for Moore and Mealy machines
Developers who have experience in Moore and Mealy machines can use FSM Tool to support both machine styles by limiting the use to specific features:
-
Moore machines can be defined using FSM Tool by limiting the specifications to states, transitions, and entry actions.
-
Mealy machines can be defined using FSM Tool by limiting the specifications to states, transitions, and input actions.
Developing SLEE Services with FSM Tool
This chapter provides an overview of using the FSM Tool to develop JAIN SLEE services for the Rhino platform.
Below are descriptions of:
-
How FSM works with Rhino — how Rhino services handle events, and the merits of using FSM Tool versus hand-coding an application’s state machine behaviour
-
Using the FSM Specification to code FSMs — how the spec provides a clean separation of concerns, formalism, and simplicity that make it is easy for developers to create both simple and complex services
-
FSM Tool features — the FSM Tool’s development workflow, showing current and planned features that simplify and enhance coding JAIN SLEE services
-
Example: defining SBB state machines — a hierarchy of state machines for an SBB entity tree design, developed using FSM Tool.
How FSM works with Rhino
Rhino is an event-driven application server for JAIN SLEE services. A typical service must handle many different events from one or more sources (such as an MSC, S-CSCF, or SMSC). With Rhino, an event handler — defined by the service — processes each event a service receives. The event handler then does some logic associated with the event and the current state of the application.
JAIN SLEE does not define the concept of an application state or action. The service developer can choose how best to implement an application’s state machines. Many JAIN SLEE developers hand-code the state-machine logic associated with each application state, and transition directly with the JAIN SLEE APIs.
The perils of hand-coding
Hand-coding the behavioural model of a Rhino application breaks the link between the specification and its implementation. As a project progresses, the only reliable source of information on the behaviour of the application becomes the application code itself. |
How FSM Tool facilitates coding FSMs for Rhino
OpenCloud’s FSM Tool formalizes the definition of an application’s state machine behaviour. At the same time, it provides a framework for implementing and maintaining actions in Java (without having to hand-code the state machine behavioural logic). The tool provides the logic that executes actions when a service receives an event.
The benefits of using a tool
Using a formalized and executable state machine definition preserves the link between the application’s design and implementation as a project progresses. |
Taking a formal approach to state machine specification has some additional benefits. FSM Tool can automatically generate:
-
documentation — The formal state machine specification auto documents the behavioural model of the application component. FSM Tool automatically generates both a tabula state machine description and a diagram, and embeds them in the Javadoc of the Sbb under development. Developers and future maintainers of the application will automatically have well-documented components.
-
testing — Future versions of FSM Tool will introduce automatic generation of a set of JUnit tests for state machine behaviour, and a promela model of the state machine with static analysis on it using Spin model-checking software.
Using the FSM Specification to code FSMs
As described in About FSM and the FSM Tool, the FSM Tool uses a hybrid state machine specification, the FSM Tool Finite State Machine (FSM). Developers specify FSMs for an application, using an easy-to-use domain-specific language (DSL) that explicitly uses state-machine design terminology ("states", "events", "inputs", and "actions").
Some state machine tools, such as UML state charts and SCXML, have complex specifications that include features such as composite states (that represent embedded state machines, include conditional logic and provide embedded programming features). FSM Tool FSM does not try to be a self-contained programming environment. Instead, it focuses on the formal specification of state machine behaviour. |
Each FSM Tool FSM specification defines a single state machine. This makes it simple to understand and maintain. The hierarchies of state machines necessary to implement complex application are composed of multiple intercommunicating FSM specifications, which communicate using endpoints and a developer-defined endpoint-to-endpoint mapping logic.
FSM Tool FSM’s clean separation of concerns, formalism, and simplicity make it is easy for developers to create both simple and complex services. |
FSM Tool features
The following diagram illustrates a developer’s workflow when using FSM Tool, highlighting existing and planned features of the tool.
Example: defining SBB state machines
In JAIN SLEE services, a Service Building Block (SBB) may implements a component with one state machine. FSM Tool makes it simple to define the state machine of a single SBB. TIP: For advanced service development FSM Tool provides support for multiple FSMs per SBB.
A typical JAIN SLEE application includes an SBB entity tree. These are very well matched to a service design based on a hierarchy of state machines. SBBs implement each state machine in the hierarchy, and the local object interfaces between the parent and child SBBs provide the mechanism for inter-FSM communication, using endpoints.
The following diagram shows the component design of a service which uses a hierarchy of state machines developed using FSM Tool. The behavioural specification for each component labelled with the <<StateMachine>>
stereotype was defined using FSM Tool.
Quick Start
Below are the steps you need to get started using FSM Tool.
1 |
Check your prerequisites
|
||
---|---|---|---|
2 |
Download FSM Tool Please see the FSM Tool Download Page. |
||
3 |
Install FSM Tool
|
||
4 |
Try the "Hello World" example Review the sample application that comes with FSM Tool, for an example of how to define a service’s FSM specification (which creates JSLEE service components, by generating an SBB class and extending it to implement state-machine action Java logic). The |
Sample Application
The FSM Tool comes with a sample application, "Hello World", as an example of how to create and extend a service with the tool.
To review the sample application, please explore the following:
-
diagram and brief explanation of the sample state machine
-
the DSL definition of the sample state machine
-
instructions to build, deploy, and run the example
-
an example of how to extend the sample state machine
-
instructions for generating Javadocs and diagrams.
What the sample state machine looks like
The FSM Tool sample state machine works like this:
"Hello World" state machine | |||
---|---|---|---|
|
The "Hello World" state machine includes:
|
How the sample state machine is defined
You define FSM Tool state machines using a simple, easy-to-understand (and modify), text-based, domain-specific language (DSL). Below is the DSL definition for the Hello World example (FsmToolExampleStateMachineSbb.fsm
):
fsm FsmToolExampleStateMachineSbb { description "{product-name} Example State Machine"; endpoint tcp; initial state startState { description "Start state"; transition if(tcp.hello) stopState; } final state stopState { description "Stop state"; entryaction helloWorld; } inputdictionary { tcp.hello { description "Hello event received."; } } actiondictionary { helloWorld { description "Say Hello World!"; } } }
Running the example
Below are instructions to build, deploy, and run the "Hello World" sample FSM Tool service.
Build and deploy
First build and deploy the service, using the following commands:
cd ${fsmtool.home}/example ant deploy-example-ra ant deploy-helloworld
Run with telnet
Then run the service, using OpenCloud’s example RA (which uses a telnet connection to send lines of text as events to the service), as follows:
-
Start a command window or shell.
-
Enter
telnet localhost 9999
-
Type
hello
, and press Return.
What happens…
When you press Return:
-
The application wraps the text
hello
in a new ExampleRA MessageEvent event, and delivers it toFsmToolHelloWorldSbb
. -
The Sbb receives the event in the onMessageEvent() event handler. The code in the event handler sets the hello input, associating the received event object with the input as data object. It then associates the SLEE ActivityContext on which the event was received with the tcp endpoint and finally triggers a run of the FSM execution algorithm.
public void onMessageEvent(MessageEvent event, ActivityContextInterface aci) { // Use the input scheduler to raise the 'hello' input on the 'tcp' endpoint and associate // the event object with it getInputScheduler().raise(getInputs().tcp.hello, event); // Associate the aci with the 'tcp' endpoint getEndpoints().tcp.setAci(aci); // Execute the FSM logic execute(); }
-
The state machine executes, transitioning to
stopState
and running the helloWorld action. The FSM logic maps thehelloWorld
action to the method helloWorldAction() which is implemented by the developer to return the "Hello World" text on the telnet connection.public void helloWorldAction(Inputs inputs, InputScheduler<FSMInput> inputScheduler, Endpoints endpoints, Facilities facilities) { ... // The ACI stored using the endpoint setAci(ActivityContextInterface) method is accessed // in the action methods using getAci(). ActivityContextInterface aci = endpoints.tcp.getAci(); ConnectionActivity connection = (ConnectionActivity) aci.getActivity(); try { connection.sendMessage("Received " + event + ". Hello World."); } catch (IOException e) { facilities.getTracer().warning("Sbb failed to send response", e); return; } }
-
You receive the "Hello World" text in the telnet connection
Exit the telnet session (press Ctrl-], type
exit
and press Return).
Digging deeper
The FSM Tool package includes:
When you run the |
Extending the "Hello World" example
Now that you have successfully run the "Hello World" example you can extend the state-machine definition to implement more complex state-machine behaviour, as follows:
Extended "Hello World" state machine | |
---|---|
|
Steps to extend from the HelloWorld service
Extend the helloworld example, by editing the FsmToolExampleStateMachineSbb.fsm
file in your Java IDE, as follows:
1 |
Remove the final from the stopState declaration and then add a new transition* ... state stopState { description "Stop state"; entryaction helloWorld; transition if(tcp.hello) startState; } ... |
---|---|
2 |
Add a new entry action startingAgain to startState, and declare it in the output dictionary ... initial state startState { description "Start state"; entryaction startingAgain; transition if(tcp.hello) stopState; } actiondictionary { helloWorld { description "Say Hello World!"; } startingAgain { description "Starting again."; } } |
3 |
(Re)build the file ant build-helloworld The Ant task will re-generate |
4 |
Implement the startingAgainAction() method in the actions interface implementation. public void startingAgainAction(Inputs inputs, InputScheduler<FSMInput> inputScheduler, Endpoints endpoints, Facilities facilities) { // The tracer is provided via the facilities method argument facilities.getTracer().finest("Running Hello World Action"); // Objects passed in the InputScheduler.raise(Input, Object) can be accessed // from the input using the getAssociatedObject() method MessageEvent event = (MessageEvent) inputs.tcp.hello.getAssociatedObject(); // The ACI stored using the endpoint's setAci(ActivityContextInterface) method is accessed // in the action methods using getAci(). ActivityContextInterface aci = endpoints.tcp.getAci(); ConnectionActivity connection = (ConnectionActivity) aci.getActivity(); try { connection.sendMessage("Received " + event + ". Starting Again."); } catch (IOException e) { facilities.getTracer().warning("Sbb failed to send response", e); return; } } |
5 |
Recompile and redeploy ant undeploy-helloworld ant deploy-helloworld |
6 |
Run the extended example:
|
What happens…
As a result of your modifications:
-
The state machine executes, transitioning from
stopState
tostartState
, and executing thestartingAgain
action — which returns the text "Starting Again" on the telnet connection. -
You receive "Starting Again" in the telnet connection.
-
If you keep on entering inputs, you will get alternating messages as the state machine transitions between the two states.
Exit the telnet session (press Ctrl-], type exit
and press Return).
Generating Javadocs and diagrams
The FSM Tool supports the automatic generation of javadocs and state-machine diagrams.
The diagrams for the basic and extended example page were automatically generated from their respective state machine definitions. |
To generate state machine Javadocs and diagrams, run:
ant javadocs
FSM Tool Procedures
Work through the "Hello World" example to familiarize yourself with a example of installing, running, and extending a simple Service Building Block (SBB). Procedures for Multiple FSMs per SBB describes the creation of a Rhino service which hosts multiple POJO FSMs in a single SBB. For anything but simple applications this is the recommended this option is used in combination with FSMs hosted in other SBBs. |
Development tasks
To develop a component with FSM Tool:
-
write the FSM specification — use the FSM DSL to write a text file defining states, actions, transitions, inputs, and outputs
-
generate an SBB — use the spec you’ve written to generate SBB code
-
extend the generated SBB — deploy runtime classes, extend the class, map events to inputs, unset durable inputs, and implement action methods
-
compile, package, and deploy — use standard methods to deploy the completed SBB
-
document — use FSM Tool’s features to automatically document the SBB.
-
trace — use FSM Tool’s runtime tracing.
Specify the state machine
First, write the specification for component state machines. In a simple application there may only be one state machine, but in more complex applications there can be many state machines in a hierarchy.
FSM Tool uses the FSM Domain Specific Language (DSL) to specify state machines. The FSM DSL syntax includes:
-
state definitions and descriptions
-
exit, and entry actions associated with each state
-
input actions associated with each state, with conditions that must be met before executing
-
transitions, with conditions that must be met before transitioning
-
an input dictionary, declaring all inputs referenced in transition and input action conditions
-
an action dictionary, declaring all actions that are occurring as input, entry, or exit actions
-
endpoint declarations, naming all the endpoints which are used in conditional expressions and the input dictionary to express where inputs are received from.
For an example of an FSM specification, see the "Definition" tab in the Sample Application. For the full FSM DSL syntax, see the FSM Language Reference. |
Generate the FSM SBB Java class
FSM Tool uses the FSM specification to generate an FSM SBB Java class. To correctly generate the code, you need to:
-
Set properties for FSM Tool’s FSM SBB code-generation template.
-
Set up the Ant
build.xml file
to use the FSM Tool Ant task (see Configuring Code Generation):-
Add a
<fsmtool:generate-fsm>
task to the build file, and set the properties of the task for the component under development. -
Run Ant on the target that includes the
<fsmtool:generate-fsm>
task. -
Look for errors that the FSM Tool reports when parsing the specification — correct them, and re-run the Ant target.
-
Extend the generated SBB
The FSM specification defines the abstract behaviour of the component. To make it work, you must extend the generated FSM StateMachine SBB Java class with an SBB class that:
-
maps received events to raised inputs, and executes the state machine
-
defines, creates and registers an implementation of the actions interface (defined by the StateMachine SBB class) which contains implementations for the FSM’s action methods.
Follow these steps to extend the SBB:
1 |
Deploy runtime classes FSM Tool has a small runtime environment. The generated FSM SBB implements the |
||
---|---|---|---|
2 |
Extend the class The developer-defined SBB class extends the state-machine SBB class that FSM Tool generated, as follows:
|
||
3 |
Map events to state machine inputs
When using FSM Tool, you only use an SBB’s event handlers to map events to state-machine inputs, and to call the state machine. The following snippet shows the typical pattern of usage in an SBB event-handler method:
You can directly reference the inputs, which are kept internally in the generated state-machine SBB class. For example, if the declared input is hello and received on endpoint tcp, the service calls the If you need to set more than one input before executing the state machine, simply add more Finally, trigger the FSM execution cycle by calling |
||
4 |
Unset durable inputs Inputs are transient by default, in the state machine specification input dictionary. (FSMs automatically clear transient inputs after one execution cycle.) If you need to use durable inputs, you will need to manually unset them within an action method, as follows:
|
||
5 |
Implement actions interface Each action defined in the state machine specification renders into a method declaration in an actions interface, which is declared as an inner interface of the state-machine SBB class.
The actions interface must be implemented in the extended SBB, and an instance must be registered with the state machine execution class (best to do this in the
|
XDoclet
We recommend using OpenCloud’s XDoclet tool to generate deployment descriptors for the SBB (as the generated SBB class declares CMP fields using XDoclet tags). If you don’t use XDoclet, you’ll need to maintain deployment descriptors for the extended SBB by hand. |
Compile, package, and deploy the SBB
Follow standard procedures
Once you’ve finished the steps to implement an SBB, use the |
Generate documentation
To create a graphic illustration of the state machine, configure a <fsmtool:generate-dot>
task to generate the Graphviz dot file format (see the "Hello World" example for details).
FSM Tool uses code-generation templates to specify details of the implementation that a state-machine specification generates. The output of code generation does not depend on the FSM Tool directly — by changing only the templates, completely different output formats can be produced. This means that you can use FSM Tool to generate many different types of output file from the specification. For example, FSM Tool comes with the following templates for generating javadocs and graphics from the state machine specification:
-
fsm-for-multi-per-sbb.stg
— to generate a POJO FSM when multiple FSMs are required in a single SBB -
multi-fsm-sbb.stg
— to generate an SBB Java class used to host one or more POJO FSMs -
fsm.stg
— to generate an FSM SBB Java class supporting a single FSM -
dot.stg
— to generate a GraphViz dot file.
The Javadoc of the generated SBB makes reference to the Graphviz state-machine image. You can also reference the state-machine image in the Javadoc of the SBB that extends the generated class, by including the image there. |
FSM Tool can use the templates provided, use enhanced templates to meet specific requirements, or use templates created from scratch. The templates are written in StringTemplate
template group format (see the StringTemplate documentation for details of file syntax). Any code generation template group used by FSM Tool must implement the full set of template names used in the fsm.stg
template group file. This set of template names is the interface between the template group and the FSM Tool. The template implementations can generate any text output or empty strings that the final output format requires (.java
, .dot
, .html
, and so on).
See also Configuring Code Generation. |
Enable runtime tracing
The generated FSM SBB can be configured to produce state-transition tracer messages, by setting the tracer level for the deployed SBB to "Fine". Either the "" ({root})
tracer name or the "fsm"
tracer name for the SBB can be used.
Once the tracer is set, trace messages such as following are written to the rhino logging subsystem:
2010-08-18 10:38:16.340 Fine [trace.HelloWorldService_0_1.fsm] <jr-2> [HelloWorldService/FSM1_Sbb] pkey=101:182573003122:0 FSM[transition=CheckParam->PrintHW, InputRegister[scheduled=[], execution=[local_printHW]], Endpoints[Endpoint[name="local,aci=[not-set,sbb-not-attached],eventContext=[not-set],endpointInterface=[not-set],activityContextInterfaceFactory=[not-set],sbbLocalObject=[not-set]],Endpoint[name="ep,aci=[set,sbb-attached],eventContext=[not-set],endpointInterface=[not-set],activityContextInterfaceFactory=[not-set],sbbLocalObject=[not-set]]]]
Action tracing (as well as transition tracing) can be enabled by setting the trace level of the SBB to "Finest". Here is an example of action logging output:
2010-08-18 10:40:44.081 Finest [trace.HelloWorldService_0_1.fsm] <jr-3> [HelloWorldService/FSM1_Sbb] pkey=101:182573003122:0 FSM[action=checkParams, state=CheckParam, result=executed successfully] 2010-08-18 10:40:44.081 Fine [trace.HelloWorldService_0_1.fsm] <jr-3> [HelloWorldService/FSM1_Sbb] pkey=101:182573003122:0 FSM[transition=CheckParam->PrintHW, InputRegister[scheduled=[], execution=[local_printHW]], Endpoints[Endpoint[name="local,aci=[not-set,sbb-not-attached],eventContext=[not-set],endpointInterface=[not-set],activityContextInterfaceFactory=[not-set],sbbLocalObject=[not-set]],Endpoint[name="ep,aci=[set,sbb-attached],eventContext=[not-set],endpointInterface=[not-set],activityContextInterfaceFactory=[not-set],sbbLocalObject=[not-set]]]] 2010-08-18 10:40:44.082 Finest [trace.HelloWorldService_0_1.fsm] <jr-3> [HelloWorldService/FSM1_Sbb] pkey=101:182573003122:0 FSM[action=printHelloWorld, state=PrintHW, result=executed successfully]
Configuring Code Generation
FSM Tool includes Ant tasks for seamlessly integrating code generation with existing build infrastructure.
Below are:
-
instructions for declaring the Ant tasks
-
descriptions of Ant task parameters
-
examples of Ant tasks for use with FSM Tool code-generation templates.
Declaring the Ant tasks
The FSM Tool Ant tasks are:
-
fsmtool:make-multi-fsm-sbb
— generates an SBB Java class to host one or more generated Java classes for each state-machine specification. -
fsmtool:generate-fsm
— generates SBB Java class for the state-machine specification. -
fsmtool:generate-dot
— generates a GraphViz compatible dot file that visualises the state machine diagram.
The FSM Tool Ants task must be declared in the Ant build.xml file using a <taskdef>
tag. The FSM Tool ships with the fsmtool.jar file, which contains the Ant tasks. You need to install it in a path referenced by the <taskdef>
. In the "Hello World" example, the jar file is in the ${basedir}/lib directory. To declare the tasks, add an fsmtool namespace attribute to the <project>
tag, and then use the <taskdef> to pick up all task declarations from the antlib.xml file (which is contained in the fsmtool.jar).
<project name="{product-name} Example Service" default="help" basedir="." xmlns:fsmtool="antlib:com.opencloud.sce.fsmtool.ant">
...
<target name="init" depends="management-init">
<path id="fsmtool.classpath">
<fileset dir="${basedir}/../libs" includes="*.jar"/>
</path>
<taskdef uri="antlib:com.opencloud.sce.fsmtool.ant"
resource="com/opencloud/sce/fsmtool/ant/antlib.xml"
classpathref="fsmtool.classpath"/>
...
</target>
...
</project>
Ant task parameters
The make-multi-fsm-sbb, generate-fsm and generate-dot tasks use the following attributes.
make-multi-fsm-sbb
Attribute | Description | Type |
---|---|---|
sbbClassName |
Class name for the generated SBB class. |
Required |
package |
Package name for the output. |
Required |
destDir |
Destination directory for the generated classes; for example: ${basedir}/src/helloworld/com/opencloud/slee/services/fsmtool/helloworld |
Required |
tracerName |
The prefix used for trace messages. |
Required |
Element | Description | Type |
---|---|---|
fsmtool:fsm |
FSM specification details. |
One or more required |
The fsmtool:fsm
element has the following attributes:
Attribute | Description | Type |
---|---|---|
|
specification |
Filename of the FSM specification from which to generate code; for example: ${basedir}/src/helloworld/com/opencloud/slee/services/ fsmtool/helloworld/FsmToolExampleStateMachineSbb.fsm |
Required |
fsmClassname |
Class name for the generated FSM class. |
Required |
fsmFullClassname |
Package path and class name for the generated FSM class. |
generate-fsm
Attribute | Description | Type | ||
---|---|---|---|---|
fsmSpecificationFilename |
Filename of the FSM specification from which to generate code; for example: ${basedir}/src/helloworld/com/opencloud/slee/services/ fsmtool/helloworld/FsmToolExampleStateMachineSbb.fsm |
Required |
||
fsmTemplateFilename |
Path and filename of the template to use for code generation; for example: templates/fsm.stg
|
Required |
||
package |
Package name for the output. |
Required |
||
fileType |
Suffix for the generated file. For fsm.stg, must be set to |
Required |
||
class |
Class name for the generated code. |
Required |
||
superClass |
A Java class which will be the super class of the generated state-machine SBB. If set, a fully qualified class name is required. |
Optional |
||
outputRootDirectory |
The root directory used to write the generated class file. The package subdirectory structure will be created automatically. |
Required |
||
tracerName |
The prefix used for trace messages. |
Required |
generate-dot
Attribute | Description | Type | ||
---|---|---|---|---|
fsmSpecificationFilename |
Filename of the FSM specification from which to generate code; for example: ${basedir}/src/helloworld/com/opencloud/slee/services/ fsmtool/helloworld/FsmToolExampleStateMachineSbb.fsm |
Required |
||
fsmDotTemplateFilename |
Path and filename of the template to use for the dot-file generation; for example: ${basedir}/templates/fsm.dot
|
Required |
||
outputFile |
Path and filename to write the resulting state-machine dot-diagram code to. |
Required |
Examples for code-generation templates
Below are examples of FSM Tool Ant task definitions using the fsm.stg and dot.stg templates, from the "Hello World" sample application.
fsm-for-multi-per-sbb.stg and multi-fsm-sbb.stg
Using the fsm-for-multi-per-sbb.stg
and multi-fsm-sbb.stg
templates to generate the state-machine and hosting SBB Java class files:
<fsmtool:make-multi-fsm-sbb
sbbClassName="FsmToolMultiFsmExampleStateMachineSbb"
package="com.opencloud.slee.services.fsmtool.multifsmsbb"
destDir="${basedir}/generated/multifsmsbb/com/opencloud/slee/services/fsmtool/multifsmsbb"
tracerName="multifsmsbb">
<fsmtool:fsm specification="${basedir}/src/multifsmsbb/com/opencloud/slee/services/fsmtool/multifsmsbb/MessageFSM.fsm"
fsmClassname="MessageFSM"
fsmFullClassname="com.opencloud.slee.services.fsmtool.multifsmsbb.MessageFSM"/>
<fsmtool:fsm specification="${basedir}/src/multifsmsbb/com/opencloud/slee/services/fsmtool/multifsmsbb/TimerFSM.fsm"
fsmClassname="TimerFSM"
fsmFullClassname="com.opencloud.slee.services.fsmtool.multifsmsbb.TimerFSM"/>
</fsmtool:make-multi-fsm-sbb>
fsm.stg
Using the fsm.stg
template to generate the state-machine SBB Java class file:
<fsmtool:generate-fsm
fsmSpecificationFilename="${basedir}/src/helloworld/com/opencloud/slee/services/fsmtool/helloworld/FsmToolExampleStateMachineSbb.fsm"
fsmTemplateFilename="templates/fsm.stg"
package="com.opencloud.slee.services.fsmtool.helloworld"
class="FsmToolExampleStateMachineSbb"
fileType="java"
outputRootDirectory="${basedir}/generated/helloworld"
traceName="helloworld"/>
dot.stg
Using the dot.stg
template to generate a GraphViz dot-format file from the state-machine specification:
<fsmtool:generate-dot
fsmSpecificationFilename="${basedir}/src/helloworld/com/opencloud/slee/services/fsmtool/helloworld/FsmToolExampleStateMachineSbb.fsm"
fsmDotTemplateFilename="templates/dot.stg"
outputFile="${basedir}/doc/javadoc/helloworld/com/opencloud/slee/services/fsmtool/helloworld/FsmToolExampleStateMachineSbb.dot"/>
FSM Debugging
When an unchecked exception is thrown in an FSM action method, the FSMs on the call path will aggregate the current status of each FSM in an FSMExecutionException
.
This information is useful for debugging runtime issues in FSM-based Rhino services.
The following exception was generated by a modified version of the multifsmsbb
example provide in the FSM Tool examples:
com.opencloud.sce.fsmtool.FSMExecutionException:
FSM = TimerFSM
previous state = waitForTimerExpiry
current state = notifyExpiry
action = notifyOnTimerExpiry(entry)
input register = InputRegister[scheduled=[], execution=[local_timerExpiry]]
endpoints = Endpoints[Endpoint[local,aci=[set,sbb-not-attached]],Endpoint[timer]]
--------------------------------------------------
FSM = MessageFSM
previous state = waitForTimer
current state = sendResponse
action = sendResponseOnTimerExpiry(entry)
input register = InputRegister[scheduled=[], execution=[timer_timerExpiry]]
endpoints = Endpoints[Endpoint[local],Endpoint[tcp,aci=[set,sbb-attached]],Endpoint[timer]]
--------------------------------------------------
at com.opencloud.slee.services.fsmtool.multifsmsbb.MessageFSM.execute(MessageFSM.java:140)
at com.opencloud.slee.services.fsmtool.multifsmsbb.FsmToolMultiFsmExampleSbb$2.timerExpired(FsmToolMultiFsmExampleSbb.java:68)
at com.opencloud.slee.services.fsmtool.multifsmsbb.TimerFSMActionsImpl.notifyOnTimerExpiryAction(TimerFSMActionsImpl.java:63)
at com.opencloud.slee.services.fsmtool.multifsmsbb.TimerFSM$Action$2.execute(TimerFSM.java:399)
at com.opencloud.slee.services.fsmtool.multifsmsbb.TimerFSM.executeAction(TimerFSM.java:251)
at com.opencloud.slee.services.fsmtool.multifsmsbb.TimerFSM.access$1000(TimerFSM.java:39)
at com.opencloud.slee.services.fsmtool.multifsmsbb.TimerFSM$3.executeEntryActions(TimerFSM.java:619)
at com.opencloud.slee.services.fsmtool.multifsmsbb.TimerFSM$3.executeEntryActions(TimerFSM.java:600)
at com.opencloud.slee.services.fsmtool.multifsmsbb.TimerFSM.executeFsm(TimerFSM.java:211)
at com.opencloud.slee.services.fsmtool.multifsmsbb.TimerFSM.execute(TimerFSM.java:125)
at com.opencloud.slee.services.fsmtool.multifsmsbb.FsmToolMultiFsmExampleSbb.onTimerEvent(FsmToolMultiFsmExampleSbb.java:122)
at com.opencloud.rhino.deployed.sbb.OpenCloud.multifsmsbb_sbb_1_1.SbbOCBBBean.sbbDeliverEvent(SbbOCBBBean.java:327)
at com.opencloud.deployed.Service_multifsmsbb_OpenCloud_1_1_2.SBB_multifsmsbb_sbb_OpenCloud_1_1OCBB_Local.sbbDeliverEvent(SBB_multifsmsbb_sbb_OpenCloud_1_1OCBB_Local.java:1122)
... 7 more
Caused by: java.lang.IllegalStateException: Transition Action Error
at com.opencloud.slee.services.fsmtool.multifsmsbb.MessageFSM.executeAction(MessageFSM.java:272)
at com.opencloud.slee.services.fsmtool.multifsmsbb.MessageFSM.access$900(MessageFSM.java:39)
at com.opencloud.slee.services.fsmtool.multifsmsbb.MessageFSM$3.executeEntryActions(MessageFSM.java:670)
at com.opencloud.slee.services.fsmtool.multifsmsbb.MessageFSM$3.executeEntryActions(MessageFSM.java:651)
at com.opencloud.slee.services.fsmtool.multifsmsbb.MessageFSM.executeFsm(MessageFSM.java:211)
at com.opencloud.slee.services.fsmtool.multifsmsbb.MessageFSM.execute(MessageFSM.java:125)
... 19 more
Caused by: java.lang.IllegalArgumentException: Intentional exception
at com.opencloud.slee.services.fsmtool.multifsmsbb.MessageFSMActionsImpl.sendResponseOnTimerExpiryAction(MessageFSMActionsImpl.java:68)
at com.opencloud.slee.services.fsmtool.multifsmsbb.MessageFSM$Action$3.execute(MessageFSM.java:434)
at com.opencloud.slee.services.fsmtool.multifsmsbb.MessageFSM.executeAction(MessageFSM.java:251)
... 24 more
Other FSM Tasks
Below are descriptions and examples of common patterns in FSM code for:
-
event-parameter checking — defining an input action for a state, for example to verify that message parameters are correct before transitioning to another state
-
error handling — setting an error input that transitions the state machine to an error state
-
multiple-SBB applications — managing multiple
SbbLocalObject
calls for JSLEE services with several SBBs -
timers — starting, canceling, or handling a timer event (for applications where the network might not return a response).
Event-parameter checking
To check event parameters, applications typically use input actions. For example, when a service receives an InitialDP
or SIP INVITE
, it may need to verify that message parameters or headers are correct for the application, before transitioning to another state for further processing. You can implement this type of parameter checking by defining an input action for the state. For example:
initial state startState {
transition if(capv2.idp) checkingInitialDP;
}
state checkingInitialDP {
description "check the Initial DP";
entryaction checkIDP;
inputaction if(invalidParameter) incrementInvalidParameterCalls;
transition if(invalidParameter) errorState;
transition connectCallState;
}
In this example, when the state machine receives an idp
on the endpoint capv2
, it:
-
transitions from
startState
tocheckingInitialDP
-
executes entry action
checkIDP
-
sets the
invalidParameter
input if it finds a parameter to be incorrect -
checks if another iteration can be performed
-
checks input actions
-
executes the
incrementInvalidParameterCalls
action if inputinvalidParameter
is set -
transitions to
errorState
ifinvalidParameter
is set -
transitions to
connectCallState
ifinvalidParameter
isn’t set.
(This transition is unconditional, so will always be executed.)
-
The state machine performs two transitions, startState → checkingInitialDP → errorState (or connectCallState ), with only one call to execute() for the idp . The state machine only stops when no changes occur any more to the scheduled view of the Input Register. |
Error handling
The recommended way of handling an error during action execution is to set an error input that transitions the state machine to an error state — this makes the error-handling behaviour explicit in the FSM specification. |
For example:
public void sendReleaseCallAction(Inputs inputs, InputScheduler<FSMInput> inputScheduler, Endpoints endpoints, Facilities facilities) {
... action implementation goes here...
if (error_detected) {
inputScheduler.raise(inputs.local.internalError);
return;
}
}
The associated state has the following pattern:
state releaseCallState {
description "Release call state";
entryaction sendReleaseCall;
transition if(internalError) errorState;
}
In this example, when the FSM sets the internalError
in the sendReleaseCall
entry action, it transitions to the errorState
state.
Multiple FSMs
Many JSLEE services comprise multiple SBBs, and you can implement their FSMs with FSM Tool. The recommended way of communication between SBBs are synchronous calls across SbbLocalObject
interfaces. If the child FSM needs to communicate a value back to the calling parent FSM after executing its action methods, this can be achieved in two ways:
1. Set the response in a local instance field, and return it after the execute()
method has been called.
For example:
public abstract ChildSbb extends ChildStateMachineSbb {
...
private Response response;
// SBB local method called by parent FSM through the child's SBB local interface
public Response childCallLocalMethod(Object dataFromParent) {
//set an input in the child's FSM, associated with the
//data object provided by the parent
getInputScheduler(getInputs().tcp.childCall, dataFromParent);
//trigger execution of the child FSM
execute();
//return the computed value to the parent FSM
Response returnValue = response;
response = null;
return returnValue;
}
private class ActionImplementation extends ChildActions {
public void helloWorldAction(Inputs inputs, InputScheduler<FSMInput> inputScheduler, Endpoints endpoints, Facilities facilities) {
...
response = new Response(responseData);
}
}
2. Use re-entrant call to the parent SBB.
For example:
public abstract ChildSbb extends ChildStateMachineSbb {
...
// SBB local method called by parent FSM through the child's SBB local interface
public void childCallLocalMethod(CallbackInterface parentCallbackInterface, Object dataFromParent) {
//set an input in the child's FSM, associated with the
//data object provided by the parent
getInputScheduler(getInputs().tcp.childCall, dataFromParent);
//associate the provided callback interface to the parent Sbb
//with the endpoint on which the input was received
getEndpoints().tcp.setSbbLocalObject(parentCallbackInterface);
//trigger execution of the child FSM
execute();
}
private class ActionImplementation extends ChildActions {
public void helloWorldAction(Inputs inputs, InputScheduler<FSMInput> inputScheduler, Endpoints endpoints, Facilities facilities) {
...
//retrieve the callback reference from the endpoint
CallbackInterface parentCallback = ((CallbackInterface)endpoints.tcp.getSbbLocalObject());
//send the response back to the parent via the parent's Sbb local method
Response response = new Response(responseData);
parentCallback.sendResponse(response);
}
}
Approach 1 (using local instance fields) is recommended for most situations
If you use re-entrant callbacks, remember to set the attribute ... /* * @slee.sbb id="... name="... vendor="... reentrant="True" ... * ... */ public abstract class ParentFSMSbb extends ParentFSMVsaSbb { ... |
Channels between JSLEE components can be synchronous (using the SbbLocalObject interfaces between SBBs) or asynchronous using activity-context interfaces (ACIs). Future releases of FSM Tool may use a channel model, with an ACI channel and a local channel, so action methods can access channels directly from passed parameters. |
Timers
Applications need timers when networks might not return a response. For example, the following snippet from a FSM specification contains a state to start, cancel, or handle an timer event:
state waitForMTForwardSM {
entryaction sendMTForwardSM, startTimer;
exitaction cancelTimer;
transition if(MTForwardSMConf) nextState;
transition if(Timer) failure;
}
In this example, the FSM uses:
-
entry action
startTimer
to start the JSLEE timer -
exit action
cancelTimer
to cancel the timer started instartTimer
.
If the timer expires, the Sbb receives a TimerEvent
through its onTimer()
event handler method. It sets the Timer input and calls the execute()
method. For example:
/** * @slee.event-method * initial-event="False" * event-type-name="javax.slee.facilities.TimerEvent" * event-type-vendor="javax.slee" * event-type-version="1.0" */
public void onTimer(TimerEvent event, ActivityContextInterface aci) {
getInputScheduler().raise(getInputs().timerEndpoint.Timer, event);
getEndpoints().timerEndpoint.setAci(aci);
execute();
}
You implement the startTimer and cancelTimer actions using normal JSLEE timer-handling code. |
Procedures for Multiple FSMs per SBB
To develop a component with FSM Tool:
-
write the FSM specifications — use the FSM DSL to write a text file defining states, actions, transitions, inputs, and outputs
-
generate the classes — use the spec you’ve written to generate code
-
extend the generated SBB and FSM POJOs — deploy runtime classes, extend the class, map events to inputs, unset durable inputs, and implement action methods
-
compile, package, and deploy — use standard methods to deploy the completed SBB
-
document — use FSM Tool’s features to automatically document the SBB.
Specify the state machines
When creating multiple FSMs per SBB the process is the same as for bSBB FSM specification.
The FSM Tool installation has an example called multifsmsbb
. This example has two FSMs:
-
MessageFSM
— handles text string requests in seconds for delay before responding -
TimerFSM
— handles the timer for delayed responses.
Generate the FSM POJO classes and hosting SBB class
FSM Tool uses the FSM specifications to generate an FSM POJO classes and SBB class. To correctly generate the code:
-
Set up the Ant
build.xml file
to use the FSM Tool Ant task (see make-multi-fsm-sbb):-
Add a
<fsmtool:make-multi-fsm-sbb>
task to the build file, and set the properties of the task for the component under development. -
Run Ant on the target that includes the
<fsmtool:make-multi-fsm-sbb>
task. -
Look for errors that the FSM Tool reports when parsing the specification — correct them, and re-run the Ant target.
-
Implement the necessary classes
The FSM specification defines the abstract behaviour of the component. To make it work, you must:
-
create an SBB class which maps received events to raised inputs, and executes the state machines which have been registered. The SBB must extend the generated FSM host SBB.
-
define, create and register implementations of the actions interfaces (defined by a generated Actions interfaces) which contain implementations for the FSM’s action methods.
Here are the required steps:
1 |
Deploy runtime classes FSM Tool has a small runtime environment. The generated FSM SBB implements the |
---|---|
2 |
Extend the generated FSM hosting SBB The developer-defined SBB class extends the generated FSM hosting SBB class, as follows:
|
3 |
Wire up and register the actions implementation classes The FSMs are wired up to support interaction between the FSMs. The FSM action implementation POJO classes are registered to the generated FSMs.
|
4 |
Map events to state machine inputs Create SBB’s event handlers to map events to state-machine inputs, and to call the state machines. The following snippet shows the typical pattern of usage in an SBB event-handler method in a FSM hosting SBB:
You can directly reference the inputs, which are kept internally in the generated state-machine SBB class. For example, if the declared input is message and received on endpoint tcp, the service calls the If you need to set more than one input before executing the state machine, simply add more Finally, trigger the FSM execution cycle by calling In this example there is a second FSM called TimerFSM. It is accessed using |
5 |
Implement actions interfaces Each action defined in the state machine specification renders into a method declaration in an actions interface, which is declared as an inner interface of the state-machine POJO class. In this case
The action interfaces are typically implemented in POJO classes, and an instance must be registered with the state machine execution class (best to do this in the
|
Compile, package, and deploy the SBB and supporting POJO classes
Follow standard procedures
Once you’ve finished the steps to implement an classes, use the |
Generate documentation
To create a graphic illustration of the state machine, configure a <fsmtool:generate-dot>
task to generate the Graphviz dot file format (see the "Hello World" example for details).
FSM Tool FSM DSL Syntax
This page defines the FSM Tool specification language syntax.
For the specification language grammar, please see FSM Tool FSM DSL Grammar. |
FSM specification syntax
You define an FSM specification with the fsm
keyword, followed by the name of the FSM, and then a body contained by {
and }
. For example:
fsm NameOfFsmSpecification {
... fsm specification body ...
}
FSM specification body
The body of the FSM specification has the following elements:
description
The description element describes the FSM, using the description
keyword followed by the text in quotes (which can span multiple lines):
description "text of the description of the fsm";
state
The state element defines states in the FSM, including actions and transitions.
Keyword + name of state + body | Initial and final states | ||
---|---|---|---|
You define a state with the
|
You define initial and final states using the
|
state body
The order of declaration of elements must be in the order they are listed below. |
The state body has the following elements, defined by keywords and other variables, and declared in the following order:
Element | Keyword + … | Example | Number |
---|---|---|---|
description |
|
|
|
entry actions |
|
|
0 or 1 |
exit actions |
|
|
0 or 1 |
input actions |
|
|
0 or more |
transitions |
|
|
0 or more |
inputdictionary
The inputdictionary must declare all inputs used in the state body elements. You define an inputdictionary element with the inputdictionary
keyword, followed by the inputdictionary body.
inputdictionary {
... inputdictionary body ...
}
inputdictionary body
The inputdictionary body declares 0 or more inputs. Each input can either be an external input (received through an endpoint) or a local input (internal to the current FSM).
External inputs are declared by the name of the endpoint on which they are received, followed by a .
, the name of the input and finally a body enclosed in {
and }
:
tcp.hello {
... input declaration body ...
}
Local inputs are declared simply by the name of the input and followed by a body enclosed in {
and }
:
niceweather {
... input declaration body ...
}
Each input declaration body can contain the following elements:
-
description — keyword followed by text in quotes.
-
type — defined with the
type
keyword, followed by eithertransient
ordurable
; defaults totransient
if not specified; determines whether you need to manually unset the input (if durable) or whether the input is cleared automatically at the end of the FSM execution cycle (see "Extend the generated SBB" in FSM Tool Procedures). -
send — defiend with the
send
keyword, followed by an input name typically an endpoint related input. Used to specify the behaviour of an action.
Local inputs are declared in the FSM DSL without endpoint names. However, when referring to them when writing Java code in the implementation class, they are accessed through a default endpoint called local which is present in all FSMs. |
actiondictionary
The actiondictionary must declare all entry, exit and input actions used in state body elements. An actiondictionary element is defined with the actiondictionary
keyword, followed by the actiondictionary body.
actiondictionary {
... actiondictionary body ...
}
actiondictionary body
The actiondictionary body declares 0 or more actions, each with an action name followed by a body enclosed in {
and }
.
setTimer {
... action declaration body ...
}
Each action declaration body can contain the following elements:
-
description — keyword followed by text in quotes.
Conditional expressions
Conditional expressions consist of:
-
Variables (inputs)
-
AND (
&&
) and OR (||
) operators -
NOT (
!
) operator -
parentheses to specify the order of precedence — if not specified,
&&
(conditional AND) takes precedence over||
(conditional OR).!
(NOT) takes precedence over&&
and||
.
For example:
tcp.hello
tcp.hello && niceWeather
!niceWeather
capv2.idp
capv2.idp && parametersCorrect
(capv2.idp && authenticated) || (capv2.idp && authenticationNotRequired)
In the example, tcp.hello
and capv2.idp
are both external inputs, and niceWeather
, parameterCorrect
, authenticated
, and authenticationNotRequired
are all local inputs.
FSM Tool FSM DSL Grammar
This page defines the FSM Tool specification language grammar.
For the specification language syntax, please see FSM Tool FSM DSL Syntax. |
Below is a formal grammar reference for the FSM Tool Finite State Machine Domain Specific Language (DSL), generated as Extended Backus-Naur Form (EBNF) in ANother Tool for Language Recognition (ANTLR) notation.
fsm
: 'fsm' ID '{' fsm_body '}'
;
fsm_body
: description?
endpoint*
state+
inputdictionary?
actiondictionary?
;
endpoint
: 'endpoint' ID ';'
;
state
: statetype? 'state' ID '{' state_body '}'
;
state_body
: description? entryaction? exitaction? inputaction* transition*
;
description
: 'description' QUOTED ';'
;
statetype
: ('initial' ('final')?|'final')
;
entryaction
: 'entryaction' actionlist ';'
;
exitaction
: 'exitaction' actionlist ';'
;
actionlist
: ID (',' ID )*
;
inputaction
: 'inputaction' 'if' '(' conditionalExpression ')' actionlist ';'
;
parConditionalExpression
: '(' conditionalExpression ')'
;
conditionalExpression
: conditionalAndExpression ('||' conditionalExpression )?
;
conditionalAndExpression
: unaryExpression ( '&&' conditionalAndExpression )?
;
unaryExpression
: '!' primary
| primary
;
primary
: inputname
| parConditionalExpression
;
transition
: 'transition' ( transition_condition )? ID ';'
;
transition_condition
: 'if' '(' conditionalExpression ')'
;
inputdictionary
: 'inputdictionary' '{' input* '}'
;
input
: inputname '{' description? (inputtype)? actionspecification? '}'
;
inputname
: (ID '.')? ID
;
inputtype
: 'type' ('transient' |'durable' ) ';'
;
actiondictionary
: 'actiondictionary' '{' action* '}'
;
action
: ID '{' description? actionspecification? '}'
;
actionspecification
: 'send' inputname (',' inputname)* ';'
WS : (' '|'\r'|'\t'|'\n')+ {skip();}
;
ID
: Letter (Letter|JavaIDDigit)*
;
fragment
Letter
: '\u0024' /* $ */ |
'\u0041'..'\u005a' /* A-Z */ |
'\u005f' /* _ */ |
'\u0061'..'\u007a' /* a-z */ |
'\u00c0'..'\u00d6' |
'\u00d8'..'\u00f6' |
'\u00f8'..'\u00ff' |
'\u0100'..'\u1fff' |
'\u3040'..'\u318f' |
'\u3300'..'\u337f' |
'\u3400'..'\u3d2d' |
'\u4e00'..'\u9fff' |
'\uf900'..'\ufaff'
;
fragment
JavaIDDigit
: '\u0030'..'\u0039' |
'\u0660'..'\u0669' |
'\u06f0'..'\u06f9' |
'\u0966'..'\u096f' |
'\u09e6'..'\u09ef' |
'\u0a66'..'\u0a6f' |
'\u0ae6'..'\u0aef' |
'\u0b66'..'\u0b6f' |
'\u0be7'..'\u0bef' |
'\u0c66'..'\u0c6f' |
'\u0ce6'..'\u0cef' |
'\u0d66'..'\u0d6f' |
'\u0e50'..'\u0e59' |
'\u0ed0'..'\u0ed9' |
'\u1040'..'\u1049'
;
QUOTED
: '"' ( options {greedy=false;} : . )* '"'
;
// comments are ignored initially, and then extracted via the commentsBefore() method
COMMENT
: '/*' ( options {greedy=false;} : . )* '*/'
;