SMC does not allow a transition to issue a transition itself. The reason for this is explained in SMC's FAQ. But if it is absolutely necessary for you to do so, this section explains how you can do so by creating your own transition queue in C++, Java, Tcl, VB.net and C#.
Warning! The following code assumes that you are not using transition arguments in your code. While it is possible to do transition queuing together with transition arguments, it is more difficult and error prone.
The following code should be added to a class which has an associated FSM and which will be issuing transitions from a transition action.
(The example code is based on examples/C++/EX1.)
-
Add a transition enum private member. The
enum will contain one entry for each unique
transition.
private: enum Transitions { ZERO_TRANS = 1, ONE_TRANS, UNKNOWN_TRANS, EOS_TRANS };
-
Add a transition queue private member.
Enqueue enum values here for later execution
rather the calling the transition methods
directly.
private: Queue<list<int> > _transitionQueue;
-
Add a private
transition
method.. This method first places a transition on the queue and, only if it detects this call is outside a transition, dequeues a transition and executes it.private: void transition(int transition) { _transitionQueue.push_back(transition); if (_fsm.isInTransition() == false) { while (_transitionQueue.empty() == false) { transition = _transitionQueue.pop_front(); switch (transition) { case ZERO_TRANS: _fsm.Zero(); break; case ONE_TRANS: _fsm.One(); break; case UNKNOWN_TRANS: _fsm.Unknown(); break; case EOS_TRANS: _fsm.EOS(); break; } } } return; } -
Replace transition calls. Replace your
transition method calls:
_fsm.Zero();
with
transition
method calls:transition(ZERO_TRANS)
The following code should be added to a class which has an associated FSM and which will be issuing transitions from a transition action.
(The example code is based on examples/Java/EX1.)
-
Add a transition table private member. This
table is a list of all transition methods. The
table is static because the FSM is common for all
instances of the context class.
import java.util.HashMap; ... private static HashMap _transition_map;
-
Add a transition queue private member.
Place transitions here for later execution. One
transition queue is needed for each context class
instance.
import java.util.LinkedList; ... private LinkedList _transition_queue;
-
Find all transition methods. In the class
static
block, fill in the transition table with the transition methods using Java reflection:import java.lang.reflect.Method; ... static { try { Class context = AppClassContext.class; Method[] transitions = context.getDeclaredMethods(); String name; int i; for (i = 0; i < transitions.length; ++i) { name = transitions[i].getName(); // Ignore the getState and getOwner methods. if (name.compareTo("getState") != 0 && name.compareTo("getOwner") != 0) { _transition_map.put(name, transitions[i]); } } } catch (Exception ex) {} } -
Add a
transition
method. Queues up a transition and issues it only if the FSM is not currently in a transition:private synchronized void transition(String trans_name) { // Add the transition to the queue. _transition_queue.add(trans_name); // Only if a transition is not in progress should a // transition be issued. if (_fsm.isInTransition() == false) { String name; Method transition; Object[] args = new Object[0]; while (_transition_queue.isEmpty() == false) { name = (String) _transition_queue.remove(0); transition = (Method) _transition_map.get(name); try { transition.invoke(_fsm, args); } catch (Exception ex) { // Handle exception. } } } return; } -
Replace transition calls. Replace your
transition method calls:
_fsm.Zero();
with
transition
method calls:transition("Zero")
The following code should be added to a class which has an associated FSM and which will be issuing transitions from a transition action.
(The example code is based on examples/Tcl/EX1.)
-
Add a transition queue private member.
Place transitions here for later execution. One
transition queue is needed for each context class
instance.
private variable _transition_queue;
-
Add a
Transition
method. Queues up a transition and issues it only if the FSM is not currently in a transition:private method Transition {transname} { lappend _transition_queue $transname; if {[$_fsm isInTransition] == 0} { while {[llength $_transition_queue] > 0} { set transition [lindex $_transition_queue 0]; set _transition_queue [lrange $_transition_queue 1 end]; // Issue the transition. $_fsm $transition; } } return -code ok; } -
Replace transition calls. Replace your
transition method calls:
$_fsm Zero;
with
transition
method calls:transition "Zero";
The following code should be added to a class which has an associated FSM and which will be issuing transitions from a transition action.
(The examples code is based on examples/VB/EX1.)
-
Add a transition enum private member. This
table is a list of all transition methods. The
table is Shared because the FSM is common for all
instances of the context class.
Private Enum Transition As Integer = _ { _ ZERO_TRANS, _ ONE_TRANS, _ UNKNOWN_TRANS, _ EOS_TRANS _ }
-
Add a transition queue private member.
Place transitions here for later execution. One
transition queue is needed for each context class
instance.
Imports System.Collections ... Private _transitionQueue As ArrayList
-
Add a private
transition
method. This method first places a transition on the queue and executes it only if it detects there is no transition in progress is the specified transition dequeued and executed.Private Sub Transition(ByVal transition As Integer) _transitionQueue.Add(transition) While _fsm.IsInTransition = False And _transitionQueue.Count = 0 transition = _transitionQueue.RemoveAt(0) Select Case transition Case Transition.ZERO_TRANS _fsm.Zero() Case Transition.ONE_TRANS _fsm.One() Case Transition.UNKNOWN_TRANS _fsm.Unknown() Case Transition.EOS_TRANS _fsm.EOS() End Select End While End Sub -
Replace transition calls. Replace your
transition method calls:
_fsm.Zero()
with
transition
method calls:transition(Transition.ZERO_TRANS)
The following code should be added to a class which has an associated FSM and which will be issuing transitions from a transition action.
(The examples code is based on examples/CSharp/EX1.)
-
Add a transition table private member. This
table is a list of all transition methods. The
table is static because the FSM is common for all
instances of the context class.
using System.Collections; ... private static Hashtable _transition_map;
-
Add a transition queue private member.
Place transitions here for later execution. One
transition queue is needed for each context class
instance.
private Queue _transition_queue;
-
Find all transition methods. In the class
static
block, fill in the transition table with the transition methods using This method first places a transition on the queue and executes it only if it detects there is no transition in progress is the specified transition dequeued and executed.using System.Reflection; ... static AppClass() { try { Type context = Type.GetType("AppClassContext"); MethodInfo[] transitions = context.GetMethods(); string name; int i; for (i = 0; i < transitions.Length; i++) { // Ignore the getState and getOwner methods. if (transitions[i].Name != "getState" && transitions[i].Name != "getOwner") { _transition_map.Add( transitions[i].Name, transitions[i]); } } } catch {} } -
Add a
transition
method. Queues up a transition and issues it only if the FSM is not currently in a transition:internal void transition(string trans_name) { lock (_transition_queue) { string name; Method transition; // Add the transition to the queue. _transition_queue.Enqueue(trans_name); // Only if a transition is not in progress should a // transition be issued. while (_fsm.isInTransition() == false && _transition_queue.Count > 0) { name = (string) _transition_queue.Dequeue(); transition = (MethodInfo) _transition_map[name]; try { transition.Invoke(_fsm, null); } catch { // Handle exception. } } } return; } -
Replace transition calls. Replace your
transition method calls:
_fsm.Zero()
with
transition
method calls:transition("Zero")