Manual
implementation of coordination contracts, or tools such as the CDE,
require an underlying micro-architecture (design pattern). Apart
from the general benefits of using design patterns, such an
architecture, accompanied with implementation guidelines, is
necessary for three additional reasons. Firstly, it acts as a
blueprint for the implementations of coordination contracts.
Secondly, it ensures that such implementations obey the intended
semantics. Thirdly, it provides an abstract description of tool
generated contract-based code.
In
what follows, we present the basic requirements for such a
micro-architecture, together with the basic assumptions that apply.
Finally, we describe and analyse the architecture on which the CDE
generated implementation of contracts is based. We conclude this
document by discussing some implementation issues based on our
experience in implementing the pattern in Java and C++.
We
must stress the fact that the micro-architecture presented herein is
only one among several possible alternatives for implementing
coordination contracts. There may well be other solutions, possibly
even simpler or more flexible. Therefore, proposals for a different
architecture or different implementation of contracts are welcome as
long as they adhere to the general principles of contracts as
discussed in the Concepts
and Methodology section and summarised in the following
paragraph. If you would like to make alternative suggestions that
fit these requirements, we promise to make them publicly available
at http://www.atxsoftware.com/CDE/patterns.
Send your proposals to cde@atxsoftware.com
The main requirements of the pattern can be divided into two
categories: general architecture requirements and “low-level"
design requirements. The former refer to the general pattern
architecture while the latter are more related to code design issues
that draw from the scope and semantics of contracts.
In
this context, the general architecture requirements are the
following:
- As
already explained, the aim of contracts is to provide the
ability to coordinate the behaviour of software components. This
is achieved by having contracts “intercepting" calls to
components and superposing forms of behaviour that reflect the
business rules that apply in the current state. In addition,
contracts can react to state changes (events) occurring in the
state of the participants by superposing the same kind of
reaction. Therefore, two distinct requirements of the pattern
are implied. Firstly, the pattern must provide a means of
delegating to contracts the requests made on the components,
while ensuring isolation between the components and the
coordination part (contracts), i.e none of the components can be
aware that coordination is taking place. Secondly, the pattern
must either explicitly allow or not prevent (during
implementation) contracts to be able to detect conditions or
events on components and take react accordingly.
- The
proposed architectural solution must provide the required
functionality by minimising the number of required changes to
the original components. In other words, ideally, no changes to
the components would be necessary but, if this is not feasible,
changes should be limited to aspects not related to the
implementation of the component interfaces, thus allowing easier
reengineering of existing applications by not
"breaking" existing interactions.
- The scope
and goals of coordination contracts require the pattern to
provide the ability to add and delete contracts in a “plug and
play" mode.
- The pattern
should allow for contracts to be able to effectively coordinate
components that are not “stand-alone" i.e that are
subclasses of other components or, generally, participate in
inheritance hierarchies.
The
“lower-level" design requirements are the following:
- Satisfy
the semantics of contracts. This implies that the pattern and
its implementation must allow for the correct instantiation of
contracts (invariant satisfaction) and for the correct sequence
of execution of the synchronisation set. Moreover, it is
necessary to implement a contract exception handling mechanism,
throwing and handling exceptions when an action involved in the
contract fails or a constraint under “with" is not valid.
- Optimise
performance. The pattern should introduce the minimum possible
number of additional calls and its implementation should be
intelligent enough to minimise a negative impact on performance.
The basic
concepts of coordination contracts make it necessary to state some
assumptions that make development easier and ensure a better
understanding of the pattern’s intended functionality. Firstly,
because contracts are used for controlling the communication between
components, they need not coordinate the participants’ internal
operations. Therefore, the pattern will not deal with internal
operations of the components. Secondly, the components are of a form
that allows them to be coordinated as described. For instance, the
preconditions of their operations are not “hard-wired" inside
the code. This implies that the components’ implementations
provide computation features only. If this is not the case, there
will be limitations to the range of different contracts that can be
superposed and a re-engineering phase that results in components of
a suitable form is required.
The
Coordination Contract Design Pattern consists of two parts: The
component part and the coordination part. The former consists of the
features that have to be provided for each component so that it can
become coordinated by a contract. The latter concerns the mechanisms
that allow for the coordination of a given component through the
contracts that are in place for it. The classes that participate in
the proposed pattern are shown in the Figure below.

The
detailed functionality of the various classes is as follows:
Component
Part
- SubjectInterface.
It is an abstract class (type) that defines the operations under
potential coordination. In fact, it is the common interface of
services provided by SubjectToProxyAdapter
and ISubjectProxy.
- Subject.
This is the real component, candidate for coordination, that
provides the concrete implementation of the various services and
inherits from SubjectToProxyAdapter.
- SubjectToProxyAdapter.
Defines the ability to, alternatively, use a proxy or
internal methods for the implementation of a given Subject
interface. It is a concrete class that allows, at run time, and
using the polymorphic entity proxy, for delegating received
requests to ISubjectProxy
in the case in which Subject is under coordination. Such
requests are then delegated to ISubjectPartner
that links the subject to the contracts that coordinate it.
If no contract is involved, SubjectToProxyAdapter
may forward requests directly to Subject.
In order to achieve this, two actions are necessary. Firstly, Subject
inherits from SubjectToProxyAdapter.
Secondly, the operations of Subject
are renamed in such a way that the operations with the initial
names are moved to SubjectToProxyAdapter
as concrete operations, and the new operations occurring in
SubjectToProxyAdapter are abstract operations. For instance,
operation( ) of Subject
exists now as operation()
in SubjectToProxyAdapter
and as _operation( )
in Subject. Moreover,
_operation() is also
declared as an abstract operation in SubjectToProxyAdapter.
Requests for operation()
are made to Subject.
However, due to renaming, the operation does not, in fact, exist
in Subject but in SubjectToProxyAdapter
from which Subject inherits. In the case that there
is no contract (no proxy) involved, operation()
in SubjectToProxyAdapter forwards
the request to the corresponding real
implementation,
_operation(), in
Subject. Otherwise, as already stated above, it delegates
the request to ISubjectProxy.
- ISubjectProxy.
It represents an object with the capability of implementing the Subject
interface. It is an abstract class that defines the common
interface of Subject and
ISubjectPartner. The
interface is inherited from SubjectInterface
to guarantee that all these classes offer the same interface as Subject
with which real subject clients have to interact.
Coordination
Part
- ISubjectPartner.
Defines the general
abilities of a
concept to be under coordination. It maintains the connection
between the real object (Subject)
and the contracts in place for it. The class is responsible for
delegating received requests to CtSubjectConnectors
according to a chain
of responsibility. The class contains operations for
managing the chain of responsibility. Alternatively, the
required management operations can be included in an abstract
class, ContractPartner,
from which ISubjectPartner
inherits. However, this is rather a “low-level” design
issue and therefore such a class is not presented in the
pattern.
- Ct_i_SubjectConnector.
A partner that represents the specificities of Subject
coordination for a given contract in which Subject is a
participant. For each pair contract-partcipant there is exactly
one Ct_i_SubjectConnector.
The class implementation may be responsible for the execution of
the rules defined in the coordination part of the contract and
for ensuring satisfaction of the contract semantics.
- Contract-i.
A coordination object that defines the rules that will be
superimposed on Subject.
It
should be noted that, naturally, in cases of inheritance
between objects that are under coordination, some additional classes
and some new associations may exist that are not presented in the
previous general architecture. In what follows, we discuss some
“lessons learned" from our experience in implementing the
architecture in Java and C++.
Clearly,
a variety of different “low-level" design decisions can be
made when implementing the general architecture outlined above.
However, such decisions should always take into account the
requirements presented in the beginning of this section. In this
context, there are four issues we wish to discuss:
- The first
issue that should be considered is related to the implementation
of Subject in Java.
As explained above, Subject
inherits from SubjectToProxyAdapter.
The question is, what if Subject
has to inherit from another class, for instance SuperSubject,
given that Java does not support multiple inheritance? In that
case, a good solution is for Subject
and SubjectToProxyAdapter
to be merged into a single class, Subject,
that provides the functionality of both the previous classes. It
should be noted that having SubjectToProxyAdapter
as a Java
interface would not provide a solution because the dynamics of
the pattern rely on call delegations that are defined in the
method implementations of SubjectToProxyAdapter.
In contrast, multiple inheritance is supported in C++ and,
therefore, a C++ implementation is not concerned with such
issues.
- Contracts
should be independently and explicitly created so that they can
be added and deleted in a “plug and play" mode. A good
solution is to explicitly create each contract parameterising
its constructor with the contract’s participants (Subjects).
The contract is then responsible for creating its CtSubjectConnector
passing as argument itself and the participant to which the CtSubjectConnector
is associated. The CtSubjectConnector
simply checks whether it is the first partner in the chain
of delegation. If it is the first partner it sets the subject
proxy to point to itself, otherwise it adds itself as the last
partner.
- In cases of
inheritance, implementations of the pattern maintaining a single
chain of responsibility will encounter the problem of having a
“non-uniform" chain of responsibility. By “non
uniform" we mean the fact that the chain can contain a
mixed sequence of the different connectors of the base and the
subclasses objects. The chain of delegation management should be
responsible for dealing with this situation by retrieving and
delivering partners that comply with the corresponding Subject
interface for the trigger being processed.
- Correctly
retrieving the contracts’ rules and executing the
contracts’ synchronisation set
are additional issues that have to be considered when
implementing the pattern. There are different strategies that
can be adopted to deal with such issues. For instance, having a
more centralised management of the execution of the contracts
rules versus managing the execution in ISubjectPartner.
©
Copyright 2001 ATX Software SA. All rights reserved.