Tip
Review the example first

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.

Tip 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 SbbStateMachine interface (see the runtime javadocs). You must deploy the runtime classes with the SBB, either as a library jar or with classes included in the SBB jar. (The "Hello World" example uses the first approach.)

2

Extend the class

The developer-defined SBB class extends the state-machine SBB class that FSM Tool generated, as follows:

public abstract class [fsm-name]Sbb extends [fsm-name]StateMachineSbb {

   ... class body ...


}

3

Map events to state machine inputs

Warning
Think different!

JAIN SLEE developers are accustomed to writing logic in SBB event-handler methods. FSM Tool turns this style on its head, implementing all the service-logic code in action methods. With FSM Tool, you only use event-handler methods for mapping events to inputs, calling getInputScheduler().raise(Input, Object), associating the ActivityContextInterface object with the endpoint, calling getEndpoints().\[endpoint-name\].setAci(aci), and perhaps doing some logging.

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:

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().[endpoint-name].[input-name], event);

        // Associate the aci with the 'tcp' endpoint
        getEndpoints().[endpoint-name].setAci(aci);

        // Execute the FSM logic
        execute();
}

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 getInputScheduler().raise(getInputs().tcp.hello, event) method to raise the input and associate the handled SLEE event object with the input as data object.

If you need to set more than one input before executing the state machine, simply add more getInputScheduler().raise(…​) methods.

Finally, trigger the FSM execution cycle by calling execute(), which runs the state machine and executes any actions.

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:

public void helloWorldAction(Inputs inputs, InputScheduler<FSMInput> inputScheduler, Endpoints endpoints, Facilities facilities) {

      inputScheduler.clear(inputs.tcp.hello);
}

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.

public interface FsmToolExampleActions extends Actions{

      /** helloWorld */
      public void helloWorldAction(Inputs inputs, InputScheduler<FSMInput> inputScheduler, Endpoints endpoints, Facilities facilities);
}

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 setSbbContext() method). Action methods execute all logic associated with an event’s arrival. For example, the following code snippet shows the method implementation for the helloWorld action, defined in the "Hello World" example state machine specification:

...
 //implementing the actions interface
private class ActionsImplementation implements FsmToolExampleActions {

    public void helloWorldAction(Inputs inputs, InputScheduler<FSMInput> inputScheduler, Endpoints endpoints, Facilities facilities) {

        //this is the action implementation for action 'helloWorld' from the specification
        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;
        }
    }
}
...
 //registration of an instance with the state-machine executor
public void setSbbContext(SbbContext context) {
    super.setSbbContext(context);
    registerActionImplementation(new ActionsImplementation());
}
Tip
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

Tip
Follow standard procedures

Once you’ve finished the steps to implement an SBB, use the Ant tasks to compile, package, and deploy the service. See the Sample Application.

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.

Note 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).

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]
Previous page Next page