Skip to main content
Jump to: navigation, search

Papyrus/Designer/connector-container

Connector and container pattern

The connector pattern is based on the idea of Garlan and Shaw that a realization of an interaction must be a first class citizen of the application model. It must be possible that an interaction - like an application component - has multiple realizations and can be configured. The idea of connectors has been formalized in the context of UML in Robert et. al 2005

The interaction component is typically defined in a model library in form of a template. This is required, since the interaction component must be able to adapt to the context in which it is used. For instance, in case of an operation call of a component, the interaction component must provide the same operation as the component. In most cases, the formal parameter of the template is either an interface or a data-type. The implementation of the interaction component must be adapted as well, in order to correspond to the interface. The implementation body is thus provided in a form a a template of a typical model-to-text (M2T) language, in our case Acceleo.

The container pattern may be used to modify the way a component interacts with its environment. This pattern has been identified by existing middleware solutions, such as CCM and Fractal. The container encapsulates an object (component) and can provide additional service and observer or manipulate the interactions with the component. In order to enhance flexibility (and readability) of the application model, it is preferable to add information about the container (in form of rules) to the model, but not the container itself. Thus, a transformation step adds the container to the model.

[[Img:Papyrus_Qompass_container-connector.png] Connector reification and container expansion

The right side of the Figure above shows this principle: a component "C" is enriched with rules to apply. This information is evaluated by a transformation that creates the container and adds the elements that are associated with the rule. The component becomes an executor, i.e the business code behind a component. It is possible to distinguish two different types of elements within the container: the interceptor and the extensions. The interceptor is placed on a delegation connection between a port of the container and the executor. The extension is an additional element which can be connected with external ports of the container.

[[Img:Papyrus_Qompass_statemachine-rule.png] Container rule for a state machine

The current container libraries offer for instance the production of execution traces or the realization of mutual access. An interesting feature is the support for state-machines. Its realization requires three elements within the container: the state-machine itself, an event pool and an interceptor which feeds the pool (e.g. each time an operation is called, an associated call event is produced). These elements are captured by the rule shown in the Figure above.

In a similar way as the FIFO interaction component, the state machine and the interceptor are defined in a package template. The model of the state machine is defined for a component (class). The implementation of the state machines depends on the formal parameter which is instantiated with a class. The message interceptor is typed with an interface, since it primarily captures call-events.

The following code fragment describes the template of an operation which manages the execution of a state-machine. The code, here using the C++ language, is modeled by an UML opaque behavior. The access to the model element is embedded between [ and /], i.e. [name/] allows to access the name of a UML element. This excerpt shows the power to adapt the behavior of embedded components via the container to add new functionality that is well separated of the business code.

[for (sm : StateMachine | ownedBehavior->select(oclIsKindOf(StateMachine)))]
switch(m_currentState)
{
    [for (state : State | sm.region.subvertex->select(oclIsKindOf(State)))]
    case [clazz.name/]_[state.name/]:
    ...
    [/for] ...

The instantiation of the template with a fictive class "A" is shown in the next code fragment. This class contains a state machine with the state "state1", which appears in the code's "switch" statement. In each state, the events defined as triggers for transitions are compared with the event read from the pool (in which a timer or interceptor write).

switch(m_currentState) 
{
    case A_state1:
    ...

Back to the top