Defining FSM Default Transitions

Now the mystery transitions Stop, Block and Delete are defined. The reason why these transitions have no start state is because they are taken no matter the current state. Well, not exactly.

SMC provides two ways to define default transitions: the Default state and the Default transtion. Manual section 2 describes how Default state and transition work. Go there to learn more about them. Task.sm is updated with the default Stop, Block and Delete transition definitions:

%{ // // Copyright (c) 2005 Acme, Inc. // All rights reserved. // // Acme - a name you can trust! // // Author: Wil E. Coyote (Hungericus Vulgarus) // %} // This FSM works for the Task class only and only the Task // class may instantiate it. %class Task %package com.acme.supercron %fsmclass TaskFSM %fsmfile TaskFSM %access package
// A %map name cannot be the same as the FSM class name.
%start TaskMap::Suspended %map TaskMap %% Suspended { // Time to do more work. // The timeslice duration is passed in as a transition // argument. Start(timeslice: long) Running { continueTask(); startSliceTimer(timeslice); }
Block Blocked { blockTask(); }
Running { // Wait for another time slice. Suspend Suspended { stopSliceTimer(); suspendTask(); }
Block Blocked { stopSliceTimer(); blockTask(); }
// Task has completed. Done Stopped { stopSliceTimer(); releaseResources(); } } // Wait here to be either unblocked, stopped or deleted. Blocked { // The task may continue working now. // No actions needed. Unblock Suspended {} } Stopping { // The task is now stopped. Stopped Stopped { releaseResources(); }
// We are stopping.
Stop
nil
{}
} Stopped {
// We are stopping.
Stop
nil
{}
// Ignore all transitions until deleted.
Default nil
{}
} Deleted {
// Define all known transitions as loopbacks.
Start(timeslice:
long
)
nil
{} Suspend()
nil
{} Block()
nil
{} Unblock()
nil
{} Done()
nil
{} Stop()
nil
{} Stopped()
nil
{} Delete()
nil
{}
}
Default
{
// Three states follow this transition, three states ignore. // So define the active definition.
Stop Stopping { stopTask(); }
// Block is ignored by four of six states. // Force the other two states to define this. // Note the "nil" end state. This is a loopback transition
Block
nil
{}
// All but the Delete state follow this transition. Define it here.
Delete Deleted {}
// Ignore a transition by default.
Default
nil
{} }
%%

The blockTask() and stopTask() methods are added to the Task class:

package com.acme.supercron; public final class Task implements TaskEventListener, TimerEventListener { public Task() { // Object initialization. ... } <snip> //----------------------------------------------------------- // State Machine Actions. // <snip>
// Block the underlying task from running. /* package */
void
blockTask() { ...
return;
}
// Permanently stop the underlying task. /* package */
void
stopTask() { ...
return;
}
<snip> // // end of State Machine Actions. //----------------------------------------------------------- // Remainder of class definition. ... }

There is one more improvement to the FSM that needs to be made before we finish. Notice that the Running state's transitions must stop the slice timer. If a new transtion is added to Running, the developer must remember to include the stopSliceTimer() action. This is a potential problem because a different developer maintaining this FSM may not know about this. But there is a solution to this.

Next: Defining State Entry/Exit Actions.