## Components

Several interfaces are typically used together in the scope of a software sub-system where some of them are exposed to clients and the sub-system itself is a client for other sub-systems via their interfaces. In such a scope, interfaces may have interdependencies manifested as constraints on the allowed order of their events. As a trivial example consider a car that first has to be started (by pressing the 'start' button) and only after that the driver can operate the car entertainment touch screen. The actions of starting the car and starting the MP3 player may logically belong to different interfaces still obeying some cross-interface rules. The rules for using several interfaces together need to be explicitly given similarly to the rules for a single interface.

In the CommaSuite framework, this need is addressed in component models. A component is an abstraction where several interfaces are used together and specifies how these interfaces interact with each other. Furthermore, a component may impose restrictions on the interaction among possibly multiple clients of the same interface. The name 'component' may clash with the same name used to denote a unit in a software/system logical or physical architecture. In this respect, a CommaSuite component does not necessarily correspond to an architectural or implementation construct that might also be named 'component'.

### Syntax of Component Models

Component models are stored in files with extension 'component'. A component has number of ports, each port associated to a CommaSuite interface. Ports are connection points of the component and are classified as provided or required. A provided port is used by the clients of the component to communicate with it following the port’s interface protocol. A required port is used by the component to communicate with its environment (in the role of a client), again following the corresponding interface protocol. All ports are named. It is possible to have two ports associated to the same interface. In the general case, we assume that multiple clients can connect to a provided port and a component instance can connect to multiple servers via a required port.

The dependencies among the interfaces of the ports in the component are defined in component functional constraints. Furthermore, components may have time and data constraints expressed in the same syntax as the ones for interfaces. The general syntax of component models is given below:

    import "interface1.interface"
    import "interface2.interface"
    //... or alternatively use namespace imports
    // import a.b.c.interface1
    // import x.y.z.interface2

    component componentName

    provided port IInterface1 port1 //port interface and port name
    required port IInterface2 port2
    //... other ports

functional constraints

Optional functional constraints

timing constraints

Optional timing constraints

data constraints

Optional data constraints

The important new construct here is functional constraint. It will be explained on the basis of a simple example.

### Example

The example uses a hypothetical component that is capturing micro images of materials in a controlled environment with required temperature and presence of vacuum. Each of the three aspects of image capturing, setting the temperature and the vacuum is controlled via a separate interface: IImaging, ITemperature and IVacuum respectively.

IImaging defines commands for preparing and creating images. IVacuum defines commands for enabling/disabling vacuum (vacuum On and Off). ITemperature defines commands for setting the temperature at certain level and resetting the temperature level. All interfaces send notifications as an indication of successful execution.

The following table gives the state machines of these interfaces:

ITemperature | IVacuum | IImaging
--- | --- | ---

The component satisfies the following requirements regarding the interaction among the three interfaces:

- Creating an image is possible only if the vacuum is present and the requested temperature is reached

- Setting the temperature is possible only if the vacuum is present

These two requirements will be expressed as component functional constraints. The goal of a functional constraint is to capture only an aspect of the total behavior of the component. Component models are not expected to define the complete component behavior in terms of reactions to all possible commands in different states. In other words, component models are not design specifications that are used to derive an implementation. An implementation of a component is expected to satisfy all the functional constraints defined in a component model along with the time and data constraints.

    import "IImaging.interface"
    import "ITemperature.interface"
    import "IVacuum.interface"

    component Imaging

    provided port IImaging iImagPort
    provided port ITemperature iTempPort
    provided port IVacuum iVacPort

    functional constraints
    ...

One example functional constraint is explained in the next section.

### Functional Constraints

We distinguish between state-based and predicate functional constraints. The first kind is a state-based specification of behavior using a subset of the union of all events that can be observed on all the component ports. The second kind is a Boolean expression that has to be true every time the component receives or sends a message.

Every sent or received message is associated to a component port which in turn is associated to an interface. This means that when the message is observed the current state of the interface at the given port is known. This allows component functional constraints to refer to the port states. Examples are shown shortly.

#### State-based Functional Constraints

The example below is a state-based functional constraint that implements the first requirement: imaging is possible only if the vacuum is present and a target temperature is set. We also temporarily assume that the ports have a single client.

    ImagingConstraint {
        use events
        command iImagPort::CreateImage
        iImagPort::reply to command CreateImage

        initial state Status {
            command iImagPort::CreateImage where iVacPort in Vacuum and iTempPort in TemperatureSet
            iImagPort::reply(Result::Ok) to command CreateImage
            next state: Status

            command iImagPort::CreateImage where not iVacPort in Vacuum or not iTempPort in TemperatureSet
            iImagPort::reply(Result::NotAvailable) to command CreateImage
            next state: Status
        }
    }

The constraint named 'ImagingConstraint' first declares which events will be used (clause 'use events'). In the example we are interested in two events only: command CreateImage and its reply. As can be seen all events are prefixed with the ports at which they are observed. This is needed for name disambiguation because an interface can be associated to more than one port. Events that are not declared in this clause cannot be used in the constraint.

Generally a state-based constraint is given as a state machine with exactly one initial state. Transitions are sequences of actions where the first action is an event reception: an indication that an event is expected to be observed. In the example we have only one state with two transitions. The intention behind the specification is that if the command CreateImage is received under the correct conditions the reply gives the value OK (the first transition). Otherwise the reply returns value NotAvailable (second transition).

An event reception may have an optional boolean expression as a condition after the keyword where. The reception is successful if the event is observed and the condition is true. The example condition shows how functional constraints use information about the state of the interface at a given port. The general syntax is portName in stateName. State Vacuum indicates that the vacuum is properly set, state TemperatureSet indicates the desired temperature is established. This access to interface state information is extremely handy. Without it, the functional constraint needs to replicate the sequence of the events in the other two interfaces that lead to the indicated states, an information already present in the interface specs. This way, code duplication is avoided and the size of the constraint is reduced.

Informally, a state-based functional constraint determines a set of traces that conform to it. A trace in this set is such that (i) for every port, the projection of the trace on this port (i.e. the trace obtained by keeping only the messages on this port) conforms to the port interface; (ii) the trace obtained by eliminating all the events not listed in the 'use events' declaration conforms to the constraint state machine. Here 'conforms' means that starting from the initial state and the first event in the trace, there is at least one transition traversal path that accepts the trace.

Each transition may accept a fragment of the trace by executing the actions in its body. Recall that a transition always starts with an event reception. When an event reception action is executed it has to match the current observed event and the condition must be true (if present) in case of match. If the head event reception of a transition matches the event, then the transition is taken. It is possible that more than one transition can be taken for an event in a given state. In this case, all these transitions will be used thus giving the possibility to have more than one traversal path that accepts the trace. If a transition is taken then all the executed event reception actions in its body must succeed on the subsequently observed events until the move to the next state is done. If an event reception fails after the transition is selected then the whole transition fails and is discarded. The trace is accepted if there is at least one path with transitions that match the events in the trace.

The full details on the syntax of use events clause, event receptions, and the allowed actions in the transition bodies are given in the subsequent appendix.

#### Predicate Functional Constraints

As an example of predicate functional constraint we will give a different interpretation and implementation of the same requirement as before. We will require that if port iImagPort is in state Imaging then iTempPort is in state TemperatureSet and iVacPort is in state Vacuum.

    ImagingConstraint_Predicate
        always
        not iImagPort in Imaging or
        (iTempPort in TemperatureSet and iVacPort in Vacuum)

The meaning of this functional constraint is that whenever an event is observed at any component port, the boolean expression after 'always' must evaluate to true.

Please note that the two example constraints are not equivalent in terms of the set of traces that conform to them. The first constraint strictly requires reply(OK) to command CreateImage if the temperature and vacuum ports are in the required states whereas the second constraint allows reply(NotAvailable) to be sent under the same conditions. If however, iImagPort enters state Imaging (which is only possible if reply(OK) is observed) then the temperature and vacuum ports must be in the required states.

Another important subtlety is how the state of a port is determined. In this example we assumed a single client per port meaning that a single interface instance will be created per port thus the port states are uniquely determined. However, the general case is multiple connections per port leading to possibly different states per connection on the same port. Next section explains the language constructs that give fine grained access to port connection states.

### Identification and Quantification over Port Connections

As already mentioned, we generally assume that multiple communication parties can be connected to a port. For a provided port these are the clients of the component. For a required port these are the servers used by the component. A given event observed at a given port is always associated to a communication party. It is possible to capture the identity of this party in a variable and to use it in expressions. An instance of the port’s interface is created for every connection to or from the port. This gives the possibility to obtain the current interface state at a given port for a given connection. Based on this information, the CommaSuite component language provides a number of expressions that quantify over the connections at a given port stating, for example, that all or some connections are in a given interface state. We will illustrate these expressions on the basis of an example.

As an example, consider a component that provides a hypothetical resource to its clients via an interface IResource. Multiple clients can request control over the resource. The component is responsible for implementing a policy for sharing the resource among multiple clients. In our example, the component will allow at most one client at a time to be in control of the resource. The following is the definition of the IResource interface:

    interface IResource

    machine Main {
        initial state Idle {
            transition trigger: getControl
                do: reply(true)
                next state: InControl
            OR
                do: reply(false)
                next state: Idle
        }

        state InControl {
            //... do something with the resource
            transition do: controlLost
                next state: Idle
        }
    }

Here is a snippet of the component definition with two functional constraints that use constructs for identification and quantification of connections.

    component ResourceControl

    provided port IResource resPort
    //other ports
    //...

    functional constraints

    FC1 {
        use events
        resPort::reply to command getControl
        notification resPort::controlLost

        variables
        id c
        id c1

        initial state ResourceFree {
            <c> resPort::reply(true) to command getControl
            next state: ResourceTaken

            resPort::reply(false) to command getControl
            next state: ResourceFree
        }

        state ResourceTaken {
            notification <c1>resPort::controlLost where c == c1
            next state: ResourceFree

            resPort::reply(false) to command getControl
            next state: ResourceTaken
        }
    }

    FC2
    always [0-1] connections at portRes in InControl

Functional constraint FC1 is state-based. If in the initial state ResourceFree a reply to command getControl with argument true is observed then the identifier of the client who receives the reply is bound to the variable c. Note the type of the variable: id. This is a predefined primitive type used only in component definitions. It allows only identity comparison operations.

If a client receives a positive reply to the getControl request the state ResourceTaken becomes the current state of the FC1 machine. In this state no more positive replies to control requests are allowed. The control over the resource can be released only if the component decides to sent notification controlLost to the client which currently has the control. Observe the usage of the variable c1 that captures the identity of the receiver of the notification. It is used in the condition that ensures that the client which is currently in control receives the notification.

The logic in FC1 can be expressed more compactly as a predicate constraint. The requirement is that at most one client is in the interface state InControl. Constraint FC2 shows the corresponding expression. It uses a quantifier over the port connections (zero or one connection satisfies a condition). The syntax of the possible quantifiers is given in the appendix.

It should be noted that this example shows how component functional constraints can restrict the order of events over the connections of a single port. In contrast, the first example (about imaging, vacuum and temperature) involves multiple ports and interfaces.

### Time and Data Constraints

Similarly to interface specifications, component models may have time and data constraints. The main difference is that events belonging to different interfaces or observed at different ports can be used. For example, a time constraint may specify that receiving a request at a provided port is followed within a certain interval by an outgoing request at a required port.

The syntax of the constraints remains the same as in interface specifications with two exceptions:

- all events must be prefixed with their ports

- events cannot be assigned with states in which they are expected to occur. Note: in case of interface specification, states refer to interface states. In component models, there are no component states. The possibility to refer to the port states is under investigation and may be included in a future version of the CommaSuite framework.

### Appendix: Functional Constraints Syntax

The syntax of state-based functional constraints has the following general structure:

    constraintName {
       use events
       one or more event patterns

       variables
       optionally, declaration of variables

       init
       optionally, initialization of variables

       initial state S{
          //transition
          eventReception //first action
          ...other actions
          next state: stateName

          //... other transitions
       }

       //other states (optional)
       state P{
          //... transitions
       }

The syntax of predicate functional constraint is:

    constraintName
    always boolean_expression

#### Use Events Patterns

List of event patterns. Every pattern denotes a non-empty set of events. Patterns are one of:

- Single event: (command | signal | notification) portName::eventName

- Reply on a given port. Can denote replies to multiple commands: portName::reply

- Reply to a concrete command: portName::reply to command commandName

- Wildcard for events per kind: any portName::(command | signal | notification)

- Wildcard that denotes all events: any portName::event

#### Event Receptions and Actions

Event receptions indicate that an event is expected to be observed subject of an optional condition. The syntax is:

EventPattern (where booleanExpression)?

Event pattern is one of:

- (command | signal | notification) (<var>)? portName::eventName(expr1, expr2, …​). The number and type of expressions must match the parameters in the event definition given in the interface signature. If an expression is a variable and the observed event matches the pattern then the actual observed parameter value is assigned to the variable and can be used later, for example, in the condition. If the expression is not a variable, it is evaluated and the value must match the observed value ('*' is allowed as a value like in interface specifications).

- (<var>)? portName::reply(expr1, expr2, …​) (to command commandName)?

- any (<var>)? portName::(command | signal | notification)

- any (<var>)? portName::event

The check if an observed event matches the pattern is similar to the matching in time and data constraints. The port, event kind and name have to be the same. Parameter values must match with the exception of variables (explained earlier). In case of successful match the variables in the pattern are assigned with the observed value. The optional condition is evaluated after a successful match.

The allowed actions in transitions are a subset of the ones used in interface specifications plus event reception:

- event reception (explained above)

- assignment, including assignment of record fields

- if-then-else with the limitation that event receptions cannot be used inside it

Note that the any order construct is not allowed in functional constraints. It can possibly be included in a future version of the CommaSuite framework.

#### Quantifiers over Port Connections

- var at port in (state | {states, …​}). Evaluates to true if the value of var denotes an existing communication party that is connected to the given port and this connection is in the given state (or in one of the given states). Remark: if the port is a provided port of singleton interface then the result is the same for all existing communication parties since all connections share the same instance of the interface (thus all are in the same state).

- all at port in (state | {states, …​}). Evaluates to true if all the connections at the given port are in one of the given states. Note that if no connections exist at the time of evaluation the value is vacuously true.

- some at port in (state | {states, …​}). Evaluates to true if at least one connection at the given port is in one of the given states.

- one at port in (state | {states, …​}). Evaluates to true if exactly one connection at the given port is in one of the given states.

- [m-n] connections at port in (state | {states, …​}). Evaluates to true if between m and n connections at the given port are in one of the given states.

- port in state. Evaluates as follows:

  - if there is already at least one connection established over the port, the expression is an abbreviation of all at port in state

  - if no connections are present yet on the port, the expression evaluates to true if the state is an initial state of a machine in the port’s interface