The Object Constraint Language: Getting Your Models Ready for MDA (2nd Edition)
In UML statecharts, OCL expressions may be used in a number of ways. In all cases, the contextual type is the class to which the statechart belongs, and the contextual instance is the instance for which a transition in the statechart fires. The example in this section is a simple process-control system in a factory that produces bottles with certain liquid contents. The classes used are depicted in Figure 3-7. The process is as follows : A line object takes a new bottle object from its stock, and triggers a filler object to fill this bottle. The bottle monitors its contents and messages the filler when it is full. The filler then triggers the line to move the bottle to the capper, which caps the bottle. Figure 3-8 contains the statechart for class Filler , and Figure 3-9 contains the statechart for class Bottle . Figure 3-7. Class diagram for the bottle-filling system
Figure 3-8. Filler statechart
Figure 3-9. Bottle statechart with change event
3.5.1 Guards
OCL expressions can be used to express guards in statecharts. A guard is a condition on a transition in a statechart. A guard is often included in the statechart diagram itself. In that case, it is written between square brackets ([ and ]) after the event that triggers the transition. In Figure 3-8, you can find a guard on the transition from the state stopped to the state filling . In this case, the Filler object will change state only if it contains enough liquid. 3.5.2 Target of Actions
An action in a statechart represents either an operation call or the sending of an event. Actions may be coupled to transitions or states in a statechart. When coupled to a transition, the action is executed if and when the transaction fires, and is targeted at a specific object or set of objects. When coupled to a state, the action is executed when the state is entered; when a state is left; or when an indicated event occurs. In the last case, usually the target is the self object. To identify the target of an action, whether coupled to a transition or a state, an OCL expression can be used. For example, the action theLine.move(b) in Figure 3-8 has as its target the Line object linked to the contextual instance of Filler, and the action myFiller.stop() in Figure 3-9 has as its target the Filler object linked to the contextual instance of Bottle . 3.5.3 Actual Parameter Values
Because actions represent operation calls or the sending of events, and both can have parameters, actions in statecharts can have parameters. Like the parameters to messages in an interaction diagram, these are actual values, not the formal parameters of the corresponding operation or sent event. The value of such a parameter can be specified using an OCL expression, in which case the context of the expression is the transition or state to which the action is coupled. In Figure 3-8, both actions have an actual value as parameter. 3.5.4 Change Events
A change event is an event that is generated when one or more attributes or associations change value. The event occurs whenever the value indicated by the expression changes from false to true. A change event is denoted by the keyword when , parameterized with an OCL expression. For example, in the state transition diagram of the Bottle class in Figure 3-9, a change event is attached to the transition from state partiallyFilled to state full . The transition takes place as soon as the condition contents = capacity becomes true. No externally generated event is needed. Note that a change event is different from a guard condition. A guard condition is evaluated once when its event fires. If the guard is false, the transition does not occur, and when no other transition for the same event is specified, the event is lost. When a change event occurs, a guard can still block any transition that would otherwise be triggered by that change. 3.5.5 Restrictions on States
Usually, there are restrictions on values of links and attributes when an object is in a certain state. These should be specified explicitly. For instance, for the class Bottle , the following invariants should hold: context Bottle inv : (self.oclInState(capped) or self.oclInState(full)) implies contents = capacity inv : (self.oclInState(empty) implies contents = 0 inv : self.oclInState(capped) implies myCap->notEmpty() inv : self.oclInState(partiallyFilled) implies myFiller->notEmpty() |