Is BoUML's State Machine Generator right when it's calling doActivity just before exit from a state of StateMachine?

Viewed 132

Consider a simple StateMachine:

enter image description here

Below is a fragment of C++ code generated by BoUML from it:

 // to manage the event create
 void Sample::Sample_State::State1_State::create(Sample & stm) {
         _doentry(stm);
 }

 // perform the 'entry behavior'
 void Sample::Sample_State::State1_State::_doentry(Sample & stm) {
   stm.enter_state1();
 }

 // perform the 'exit behavior'
 void Sample::Sample_State::State1_State::_doexit(Sample & stm) {
   stm.exit_state1();
 }

 // perform the 'do activity'
 void Sample::Sample_State::State1_State::_do(Sample & stm) {
   stm.do_state1();
 }

 // to manage the event exit_state1
 void Sample::Sample_State::State1_State::exit_state1(Sample & stm) {
     _do(stm);
     {
       stm._sample_state._state1_state._doexit(stm);
       stm._set_currentState(stm._sample_state);
       stm._final();
     }
 }

Note that _do(stm) is called by Sample::Sample_State::State1_State::exit_state1(Sample & stm), i.e. on the exit from State 1, just before the call of the exit behavior stm._sample_state._state1_state._doexit(stm);

The UML Specification tells us:

14.2.3.4.3 State entry, exit, and doActivity Behaviors

. . .

A State may also have an associated doActivity Behavior. This Behavior commences execution when the State is entered (but only after the State entry Behavior has completed) and executes concurrently with any other Behaviors that may be associated with the State, until:

  • it completes (in which case a completion event is generated) or
  • the State is exited, in which case execution of the doActivity Behavior is aborted.

The execution of a doActivity Behavior of a State is not affected by the firing of an internal transition of that State.

Wouldn't it be more aligned with UML specification to call _do(stm) from Sample::Sample_State::State1_State::create(), right after _doentry(stm);?

1 Answers

In fact it is worst, I exchanged the management of the do behavior between the entry and exit cases. Considering that state machine (the transitions from a state to itself are internal) : enter image description here

and the main

int main()
{
  MM mm;
  
  mm.create();

  cout << endl << "fire taa" << endl;
  mm.taa();

  cout << endl << "fire tab" << endl;
  mm.tab();

  cout << endl << "fire tbb" << endl;
  mm.tbb();

  cout << endl << "fire tba" << endl;
  mm.tba();

  cout << endl << "fire tdone" << endl;
  mm.tdone();
}

Compilation (without defining VERBOSE_STATE_MACHINE) and execution :

pi@raspberrypi:~/sm/src $ g++ -Wall -g MM.cpp mmain.cpp 
pi@raspberrypi:~/sm/src $ ./a.out
a entry

fire taa
a do
taa

fire tab
a do
a exit
tab expr
b entry

fire tbb
b do
tbb

fire tba
b do
b exit
tba expr
a entry

fire tdone
a do
a exit
tdone
pi@raspberrypi:~/sm/src $ 

So the do behavior is executed for an internal transition, wrongly when exiting a state, and is missing when entering in a state.

Note the state machine generator is the plug-out and its definition is part of BoUML delivery through the project sm_generator, it is implemented in C++ (not in Java). So you can load the project sm_generator, save-as it where you have the write permission, correct it, generate the C++ code, compile it and replace the official generator with your new version or declare your new plug-out and associate it to the state machine to have it in the menus.


I modified my state machine generator, the previous time was in 2011!

The do behavior is not anymore executed when exiting the state including through a self external transition, it is now executed after the possible do entry. I also do it after the possible transition behavior of a self internal transition, rather than before, that avoid two consecutive executions without nothing between in case the transition has a behavior.

Note it was already possible to execute the possible do behavior of the current state through the operation doActivity defined on the class associated to the machine. That allows to do it between transition firings.

With the previous state machine a little modified to add a self external transition :

enter image description here

and that main

#include "MM.h"
#include <iostream>
using namespace std;

int main()
{
  MM mm;
  
  mm.create();

  cout << endl << "fire taa" << endl;
  mm.taa();

  cout << endl << "fire ta_a" << endl;
  mm.ta_a();

  cout << endl << "fire tab" << endl;
  mm.tab();

  cout << endl << "fire tbb" << endl;
  mm.tbb();

  cout << endl << "fire tba" << endl;
  mm.tba();

  cout << endl << "fire tdone" << endl;
  mm.tdone();
}

Compilation (without defining VERBOSE_STATE_MACHINE) and execution :

pi@raspberrypi:~/sm/src $ g++ -Wall MM.cpp mmain.cpp 
pi@raspberrypi:~/sm/src $ ./a.out
a entry
a do

fire taa
taa expr
a do

fire ta_a
a exit
ta_a expr
a entry
a do

fire tab
a exit
tab expr
b entry
b do

fire tbb
tbb expr
b do

fire tba
b exit
tba expr
a entry
a do

fire tdone
a exit
tdone expr
pi@raspberrypi:~/sm/src $ 

BoUML 7.10 is available and fix the problem

Related