Altova UModel 2024 Enterprise Edition

The parent class of the state machine (i.e. the "controller class", or "context class") is the one, and only, "interface" between the state machine user and the state machine implementation.

 

The controller class provides methods which can be used from "outside" to change the states (e.g. after external events occur).

 

The state machine implementation however, calls controller class methods ("callbacks") to inform the state machine user about state changes (OnEntry, OnExit, ...), transition effects, and the possibility to override and implement methods for conditions (guards).

 

UModel can automatically create simple operations (without any parameter) for entry/exit/do behaviors, transition effects, ... when the corresponding option is turned on (also see Creating states, activities and transitions). These methods can be changed to whatever you want in UModel (add parameters, set them as abstract, etc.).

 

A state machine (i.e. its controller class) can be instantiated several times. All instances work independently of each other.

 

The UML State machine execution is designed for the "Run-to-completion execution model".

UML state machines assume that processing of each event is completed before the next event is processed.

This also means no entry/exit/do action or transition effect may directly trigger a new transition/state change.

 

Initialization

Every region of a state machine has to have an initial state.

The code generated by UModel automatically initializes all regions of the state machine (or when the Initialize() method of the controller class is called).

If OnEntry events are not wanted during initialization, you can call the Initialize() method manually and ignore OnEntry events during the startup.

 

Getting the current state(s)

UModel supports composite states as well as orthogonal states, so there is not just one current state—every region (in any hierarchy level) can have one current state.

 

The AirCondition.ump example shows how to walk through the regions to the current state(s):

 

TreeNode rootNode = m_CurrentStateTree.Nodes.Add(m_STM.getRootState().getName());
UpdateCurrentStateTree(m_STM.getRootState(), rootNode);
 
private void UpdateCurrentStateTree(AirCondition.AirConditionController.IState state, TreeNode node)
{
  foreach (AirCondition.AirConditionController.IRegion r in state.getRegions())
  {
    TreeNode childNode = node.Nodes.Add(r.getName() + " : " + r.getCurrentState().getName());
    UpdateCurrentStateTree(r.getCurrentState(), childNode);
  }
}

 

Example 1 - a simple transition

SimpleTransition11

The corresponding operation is automatically generated in UModel

SimpleTransition12

Generated method in code:

 

private class CTestStateMachine : IState
{
     
      public bool MyEvent1()
      {
             
      }
}

 

Notes:

 

The state machine user should call the generated method "MyEvent1" when the corresponding event occurs (outside the state machine).

The return parameter of these event-methods provides information about whether the event caused a state change (i.e. if it had any effect on the state machine) or not. For example, if "State1" is active and event "MyEvent1()" occurs, the current state changes to "State2" and "MyEvent1()" returns true. If "State2" is active and  "MyEvent1()" occurs, nothing changes in the state machine and MyEvent1() returns false.

 

Example 2 - a simple transition with an effect

SimpleTransition21

The corresponding operation is automatically generated in UModel

SimpleTransition22

Generated method in code:

 

private class CTestStateMachine : IState
{
     
      // Override to handle entry/exit/do actions, transition effects,...:
      public virtual void OnState1State2Effect() {}
}

 

Notes:

 

"OnState1State2Effect()" will be called by the state machine implementation, whenever the transition between "State1" and "State2" is fired.

To react to this effect, "OnState1State2Effect()" should be overridden in a derived class of "CTestStateMachine".

"CTestStateMachine:: OnState1State2Effect()" can also be set to abstract, and you will get compiler errors until the method is overridden.

When "OnState1State2Effect()" is not abstract, and the "Generate debug messages" option is active, UModel will generate following debug output:

 

// Override to handle entry/exit/do actions, transition effects,...:
public virtual void OnState1State2Effect() {OnDebugMessage("ACTION: OnState1State2Effect");}

 

Example 3 - a simple transition with an effect and parameter

SimpleTransition31

The corresponding operation is automatically generated in UModel

SimpleTransition32

Generated method in code:

 

private class CTestStateMachine : IState
{
     
      // Additional defined operations of the controller class:
      public virtual void OnState1State2Effect(String text)
      {
      }
}

 

Notes:

 

To effect operations (automatically created by UModel) parameters can be added manually (UModel cannot know the required type).

In this sample, the parameter "text:String" has been added to the Effect method in TestController. A proper argument has to be specified when calling this method (here: "1 => 2").

Another possibility would be: e.g. to call static methods ("MyStatic.OnState1State2Effect("1 => 2")"), or methods of singletons ("getSingleton().OnState1State2Effect("1 => 2")").

 

Example 4 - entry/exit/do actions

SimpleTransition41

The corresponding operations are automatically generated in UModel

SimpleTransition32

Generated method in code:

 

private class CTestStateMachine : IState
{
     
      // Override to handle entry/exit/do actions, transition effects,...:
      public virtual void OnExitState3() {}
      public virtual void OnEntryState4() {}
      public virtual void OnDoState4() {}
}

 

Notes:

 

States can have entry/exit/do behaviors. UModel automatically creates the corresponding operations to handle them.

When "MyEvent2()" occurs in the sample above, the state machine implementation calls "OnExitState3()". If "MyEvent2" would have an Effect, it would be subsequently called, then "OnEntryState4" and "OnDoState4" would be called.

Normally, these methods should be overridden. When they are not abstract and the "Generate debug messages" option is active, UModel provides default debug output as described in Example 2.

These methods can also have parameters as shown in Example 3.

 

Example 5 - guards

Transitions can have guards, which determine if the transition really can fire.

SimpleTransition51

The corresponding operation is automatically generated in UModel

SimpleTransition52

Generated method in code:

 

private class CTestStateMachine : IState
{
     
      // Additional defined operations of the controller class:
      public virtual bool CanGoState6()
      {
          return true; // Override!
      }
}

 

Notes:

 

If "State5" is the active state and "MyEvent2" occurs, the state machine implementation will call "CanGoState6" and, depending on its result, the transition will fire or not.

Normally, these methods should be overridden. When they are not abstract and the "Generate debug messages" option is active, UModel provides default debug output as described in Example 2.

These methods also can have parameters as shown in Example 3.

Multiple transitions with the same event, but having different guards, are possible. The order in which the different guards are polled is undefined. If a transition does not have a guard, or the guard is "else", it will be considered as the last (i.e., only when all other transition guards return false, will this one will fire). For example, in the diagram below, it is undefined whether CanGoState6() or CanGoState7() is called first. The third transition will only fire if CanGoState6() and CanGoState7() return false.

SimpleTransition6

Additional constructs and functionality can be found in the AirCondition.ump and Complex.ump samples.

© 2017-2023 Altova GmbH