Executing an Executable Model
Figure 1 showed the static structure of an executable UML model, but a language is not meaningful unless there are well-defined execution semantics. Executable UML has specific, unambiguous rules regarding dynamic behaviorthat is, rules about how the language executes at run time. The semantics are stated in terms of a set of communicating state machines, the only active elements in an executable UML program.
Each object and class (potentially) has a state machine that captures the behavior over time of each object and class. Every state machine is in exactly one state at a time, and all state machines execute concurrently with respect to one another. (Note that the single state chart describing the behavior of the typical object generates one state machine, each in its own state, for each object currently in existence.)
The set of actions triggered by a state transition execute concurrently with respect to one another unless otherwise constrained by data or control flow, and these actions may access data of other objects. It is the proper task of the modeler to specify the correct sequencing and to ensure object data consistency by synchronizing the state machines.
A state machine synchronizes its behavior with another by sending a signal that is interpreted by the receiver's state machine as an event. On receipt of a signal, a state machine fires a transition and executes a set of actions that must run to completion before the next event is processed.
Coding vs. Actions
Why use an action model rather than just write code?
The semantics of actions are defined so that data structures can be changed at translation time without affecting the definition of the computationa critical requirement for translatability. Therefore, the action semantics allows you to specify behavior without relying on knowledge of the implementation. For example, a common approach to finding the total amount of the last ten transactions is to loop through the data structure creating a sum as we go. This inextricably links the computation to the data structure, but what if it changes? The action semantics casts this example problem instead as: Get the last ten transaction amounts, then sum them. The consequence of this small change in view is that it is possible to change the storage scheme without affecting the algorithm that merely sums values.
And the result of that is an executable UML model can be translated to any target.
State machines communicate only by signals, and signal order is preserved between sender and receiver instance pairs. The rule simply states the desired sequence of activities. When the event causes a transition in the receiver, the procedure in the destination state of the receiver executes after the action that sent the signal. This captures desired cause and effect in the system's behavior. It is a wholly separate problem to guarantee that signals do not get out of order, links fail, etc., just as it is separate problem to ensure sequential execution of instructions in a parallel machine.
An arbitrary model therefore contains the details necessary to support its execution, verification, and validation, independent of implementation. No design details or code need be developed or added for model execution, so formal test cases can be executed against the model to verify that requirements have been properly addressed. This form of verification can be carried out on each executable model, independently of the other models.
Them's the rules, but what is really going on is that executable UML is a concurrent specification language. Rules about synchronization and object data consistency are simply rules for that language, just as in C++ we execute one statement after another and data is accessed one statement at a time. We specify in such a concurrent language so that we may translate it onto concurrent, distributed platforms, as well as onto fully synchronous, single tasking environments.