Both contracts we saw up to now only had a rule with a guard but no body, i.e., the behavior was not changed, they only restricted the conditions under which withdrawals are allowed. In this section we introduce a contract that changes the withdrawal operation to be performed.
If a customer tries to overdraw an account, and there is a Traditional contract in effect between that customer and that account, an exception is raised. A different policy might be to allow the customer to withdraw less money than s/he asked for, instead of prohibiting the operation. The LimitedTraditional contract implements this policy: withdrawals are always allowed (there is no guard), but the amount to withdraw is the smaller of two quantities: the amount asked for, and the current balance. Hence, at most the current balance can be withdrawn, not more, and thus the account doesn't become negative. Of course, if the account is already negative before the withdrawal, an exception is raised, because this contract will attempt to withdraw a negative amount.
Add the contract to the project using the same process as for the previous ones:
Select Project->Add Contract. Choose the LimitedTraditional.ctr file in the source directory.
Right-click on the new contract node in the project pane and choose Edit Textual to visualize the contract definition.
Click on the generation button in the tool bar.
Now let us look more closely at the contract. Notice that the Java code in the rule body calls a method _withdraw,
with a leading underscore. The reason for this is both technical and conceptual.
If the "normal" withdraw operation would be called, the same contract
would re-intercept again the call, leading to an infinite loop, because the rule
body calls exactly the same operation for which the rule is defined! The leading
underscore instructs the CDE runtime to call the original operation, i.e., the
one defined by the programmer in the original class, not the coordinated
operation in the class generated by CDE. Calling the original operation will
bypass any contracts and therefore no infinite loop can arise. This technical
explanation is easier to understand if we think about the conceptual motivation.
The rationale is to make a separation between events and services, between
triggers and reactions, between messages and methods (in OO parlance). A
contract rule is activated by the event/trigger/message given after the when
keyword, and superposes the service/reaction/method in the rule body. Java
doesn't distinguish syntactically between the message and the method, and hence
it is necessary for you to take great care when writing a contract rule body. If
the reaction to the message in the when clause is to execute the
actual method, precede it with an underscore; if the reaction is to raise new
events that may be subject to (the same or other) contracts, then don't use the
underscore.
At first sight, the need to use the underscore might seem as a technical nuisance to avoid trivial infinite loops. In fact, it forces us to think more clearly about the distinction between messages (which coordinate the interactions between components) and methods (which implement the actual computations). Coordination contracts are not just a programming construct, they are a modelling primitive with an associated methodology to think about software systems and how they can be developed and evolved. In that sense, the underscore is just the syntactical manifestation of the deep semantic issue of coordination vs. computation.
The contract also contains a new keyword: before. When the
trigger corresponds to the call for an operation (like withdraw), three types of actions may be
superposed on the execution of the operation: before (to be performed before the operation),
do
(to be performed
instead of the operation), and after (to be performed after the operation).
In
the case in which an object participates in multiple contracts with the same
trigger, the sequence of execution is the following: first, all the before
actions are performed, then one replace, and finally all the after
actions. It should be noted that
the semantics of contracts allow for only one replace clause to be
executed, thus preventing the undesirable situation of having two alternative
actions for the same trigger. This will become clearer when we will later animate contract and component
instances.
Top CDE Documentation Home Next