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