list of dots Digital Research Alliance of Canada logo  NSERC logo  University of Ottawa logo / UniversitĂ© d'Ottawa

User Manual    [Previous]   [Next]   

Basic State Machines

A state machine has a fixed set of of values (called states) The state machine transitions from state to state by the occurrence of events. State machines are very useful for quickly defining a program's behaviour.

In Umple, a state machine is modeled as a special type of attribute. In any class, simply specify the state machine name, and follow the name by a block starting with '{' and ending with '}'. This indicates to Umple that you are defining a state machine, and not an ordinary attribute.

Within the block, you list the names of the various states. Each state is followed by a block, again indicated using '{' to start and '} to end. This block defines the details of a state.

Details of each state can include:

  • Transitions. A transition has an event name, the symbol '->', and then the name of a destination state. The event name will become the name of a generated method. To trigger the transition, you simply call the method. When the event occurs while the state machine is in the origin state, the state machine will change to the destination state.
    Transitions can also have: 
    • transition actions, specified as '/' followed by a block of code to execute.
    • guards, which are boolean expressions in square brackets. Even if the event occurs, the transition only takes place if the guard evaluates to true.
  • Entry actions, exit actions and do activities. See the separate manual page.
  • Nested states. See the separate manual page. You can nest state machines to arbitrary levels of depth.
  • Final states. See the separate manual page.

Note that, in addition, you can specify code to be executed whenever an event is processed by using before or after directives.

The following diagram shows a garage door state machine as a UML diagram. The Umple code for this is in the second example shown, and is further explained in the video below.
 
state machne for garage door  

Basic Garage Door Example


// This example shows a simple state machine
// without any actions or guards
//
// In the following, status is a state machine,
// and acts like an attribute, whose value is set
// by various events.
//
// Open, Closing, Closed, Opening and HalfOpen are
// the possible values, or states, of status.
//
// buttonOrObstacle, reachBottom and reachTop are
// events. These become generated methods that can
// be called to cause a state change.
//
// To make the state diagram appear in
// UmpleOnline, select 'Options' then choose
// 'GraphViz State Diagram'
class GarageDoor
{
   status {
      Open { buttonOrObstacle -> Closing;  }
      Closing {
          buttonOrObstacle -> Opening;
          reachBottom -> Closed;
      }
      Closed { buttonOrObstacle -> Opening; }
      Opening {
          buttonOrObstacle -> HalfOpen;
          reachTop -> Open;
      }
      HalfOpen { buttonOrObstacle -> Opening; }
  }
}
      

Load the above code into UmpleOnline

 

Garage Door Example with Actions

// This is a more fully-featured state machine for
// a garage door corresponding to the diagram
// above
class Garage {
  Boolean entranceClear=true;
  GarageDoor { 
    Closed {
      entry/{stopMotor();}  
      entry/{triggerEnergySaveMode();}
      exit/ {triggerNormalEnergyMode();}
      pressButton -> /{turnLightOn();} Opening; 
    }
    Opening {
      entry/{runMotorForward();}
      openingCompleted -> Open;
    }
    Open {
      entry/{stopMotor();}
      // do {wait(60000); turnLightOff();}
      pressButton [getEntranceClear()] -> Closing;
    }
    Closing {
      entry/{runMotorInReverse();}
      closingCompleted -> Closed;
      pressButton -> /{flashLightOn();} Opening; 
    }
  }
  
  boolean runMotorInReverse() Java {
     System.out.println(
       "Running motor in reverse");
    return true;
  }

  boolean runMotorInReverse() Python {
    print("Running motor in reverse")
    return True
  }
  
  boolean flashLightOn() Java {
     System.out.println("Flashing light on");
    return true;
  }

  boolean flashLightOn() Python {
    print("Flashing light on")
    return True;
  }

  boolean turnLightOn() Java {
     System.out.println("Turning light on");
    return true;
  }

  boolean turnLightOn() Python {
    print("Turning light on")
    return True
  }  
  
   boolean turnLightOff() Java {
     System.out.println(
       "Turning light off");
    return true;
  }

   boolean turnLightOff() Python {
    print("Turning light off")
    return True
  }  
  
  boolean runMotorForward() Java {
     System.out.println(
       "Running motor forwards");
    return true;
  }

  boolean runMotorForward() Python {
    print("Running motor forwards")
    return True
  }  

  boolean triggerEnergySaveMode() Java {
     System.out.println(
       "Triggering Energy Saving Mode");
    return true;
  }

  boolean triggerEnergySaveMode() Python {
    print("Triggering Energy Saving Mode")
    return True
  }

  boolean stopMotor() Java {
     System.out.println("Stopping motor");
    return true;
  }

  boolean stopMotor() Python {
    print("Stopping motor")
    return True
  }  

  boolean triggerNormalEnergyMode() Java {
     System.out.println(
       "Triggering Normal Energy Mode");
         return true;
  }

  boolean triggerNormalEnergyMode() Python {
    print("Triggering Normal Energy Mode")
    return True
  }  
  
  boolean waitawhile() Java {
    System.out.println("Waiting");
    return true;
  }

  boolean waitawhile() Python {
    print("Waiting")
    return True
  }  
  
  boolean test() Java {
          System.out.println("Testing");
         return true;
  }

  boolean test() Python {
    print("Testing")
    return True
  }  
}
// @@@skipcppcompile

      

Load the above code into UmpleOnline

 

YouTube Video with Additional Explanation

 
 

Syntax


stateMachine : [[enum]]
    | [[inlineStateMachine]]
    | [[referencedStateMachine]]
    | [[activeDefinition]]

//Issue 148
inlineStateMachine : [=queued]? [=pooled]? [~name] {
  ( [[comment]]
    | [[state]]
    | [[trace]]
    | [[mixsetDefinition]]
    | [=||]
    | [[standAloneTransition]]
  )* }

// An enum is a state machine that has no events
// stateName is prefixed with ~ to match alphanumeric names only.
// This is needed to solve issue 399, which is cause when a terminating } is parsed as part of the statename.
enum : [~name:key] { [~stateName]? (, [~stateName])* }

state : [=final]? [stateName] { [[stateInternal]]* }

stateEntity- : [=||]
    | [[mixsetDefinition]]
    | [[entryOrExitAction]]
    | [[autoTransition]]
    | [[transition]]
    | [[activity]]
    | [[state]]
    | [[displayColor]]
    | [[trace]]
    | ;

autoTransition : [[activity]]? [[autoTransitionBlock]]

// Autotransitions have no event. The transition is immediately taken
// or taken after the do activity ends[[guard]]? -> [[action]]?
// The action can come before or after the arrow
autoTransitionBlock- : [[guard]]?
  ( [[action]] -> | -> [[action]] | ->
  ) [stateName] ;

// A transition guard can come before or after the arrow
// The order of guard and event definition can also be interchanged
transition :
  ( [[eventDefinition]] [[guard]]
    | [[guard]] [[eventDefinition]]
    | [=unspecified]? [[guard]]
    | [[eventDefinition]]
  )?
  ( [[action]] ->
    | -> [[action]]
    | ->
  ) [stateName] ;

eventDefinition- : [[afterEveryEvent]] | [[afterEvent]] | [~event]
  ( [[parameterList]]
  )?

// The timer in a timed event can be an number, variable, function() or function(num)
afterEveryEvent- : afterEvery ( [!timer:[+*/a-zA-Z0-9_\.-]+(\([0-9\.]*\))?] )

afterEvent- : after ( [!timer:[+*/a-zA-Z0-9_\.-]+(\([0-9\.]*\))?] )

// An action can be executed on a transition, or on entry or exit
action : / [[moreCode]]+

entryOrExitAction : [=type:entry|exit] [[guardCode]]? / [[moreCode]]+

// A do activity is long-lasting and can be interrupted
activity : do [[moreCode]]+

guard : [ [[constraint]] ]