Difference between revisions of "APAM/Composite"

From Wiki Adele Team
Jump to: navigation, search
(Action grant)
 
Line 1: Line 1:
 +
<div style="color:red;text-align:center;font-size:35px;background-color:#F2F2F2;height:100%;line-height: 2em;">This APAM Wiki is no longer maintained. Please switch to the following github Wiki for newest APAM information: <br/> http://github.com/AdeleResearchGroup/ApAM/wiki </div>
 +
<br/>
 +
<br/>
 
Composites come in two flavors: composite type which contain implementations, and which are special case of implementation; an composite instances, which contain instances, and  which are special case of instances.
 
Composites come in two flavors: composite type which contain implementations, and which are special case of implementation; an composite instances, which contain instances, and  which are special case of instances.
 
The simplest composite definition is as follows :
 
The simplest composite definition is as follows :

Latest revision as of 12:24, 10 January 2013

This APAM Wiki is no longer maintained. Please switch to the following github Wiki for newest APAM information:
http://github.com/AdeleResearchGroup/ApAM/wiki



Composites come in two flavors: composite type which contain implementations, and which are special case of implementation; an composite instances, which contain instances, and which are special case of instances. The simplest composite definition is as follows :


<apam xmlns="fr.imag.adele.apam">
   <composite name="S2Compo" mainComponent="S2Impl"/>
</apam>

With respect to implementations, key word "composite" is used, there is no class but a mandatory main component "mainImplem"; which can be an implementation, as in this exemple, or a specification. The main component must provide at least the same resources as the composite.

Composite dependencies

A composite is an implementation, and as such it provides resources. In the following, it is said that the composite "S2Compo" provides specification "S2" and additionaly produces messages of type "example.TypeS2".

A composite does not contains Java code but implementations and instances; at least its main implementation and main instance. Let "C" be a composite type containing implementation "I" and "c" a composite instance of "C" containing instance "i". Suppose that "i" asks for a resolution toward resource "R". If the resolution consists of implementation "I2" and instance "i2", "I2" will pertain to "C" (except if "I2" can be borrowed by "C"); and "i2" will pertain to "c" (except if "i2" can be borrowed by "c" and is sharable). Therefore, resolutions are performed with respect to embedding composites, and except when borrowed, the new implementations and instances will pertain to the embedding composite type and composite instance.

A composite may have dependencies. If composite “C” has a dependency toward resource “R”, then the resolution of “i” dependency toward “R”, is considered to be a dependency of “C” toward “R”, and therefore will be performed in the scope of the composites in which “C” and “c” pertain. In the example, composite type “S2Compo” has dependencies toward interface “S2”, messages of type ”example.DataType2", and specifications “SX”. In the example, the resolution will create a wire from "i" to "i2", and a wire from "c" to "i2", and a relationship "uses" from "S2Compo" to "I2".

Composite dependencies are very similar to specification dependencies; it is not possible to indicate cadinality, not to define composite dependencies. At execution, the effective composite dependency toward resoure R of composite "c" will be the union of the dependencies of its instances toward R. These dependencies must all satisfy the constraints defined in the "c" specification, in "C", and in the client implementation.


<apam xmlns="fr.imag.adele.apam">
   <composite name="S2Compo" specification="S2" mainComponent="S2Impl" messages="example.TypeS2">
  	 <dependency interface="S2" />
         <dependency message=”example.DataType2"/>
         <dependency specification="SX"/>
   </composite>
</apam>

Visibility control

A composite, being an implementation, can set its own properties. In the example below, the composite itself is sharable and visible by all ("properties shared="true" visible="global""). But a composite can also control it content; it can be a white box (showing its content), a block box (hiding its content), or in between. This is specified using attributes "internal", and overloading the scope and visibilities of its components. In the following example, it is declared that the composite can use implementations made visible by other composites "implementations internal="false"". "Internal=true" means that the implementations used by the composite must be specifically deployed for that composite (from the associated repository, see dynamic deployment) and will pertain to that composite.

"instances internal="true"" means that this composite will not use any instance pertaining to other composites, but will create its own instances for its own use.

A composite can also control the scope and visibilities of the objects it contains, by overloading the attribute "visible" of its implementations, and the attribute "scope" of its instances. In the example below, the implementation of specification "S2" will have "visible=local" (i.e. the composite main implementation will not be visible outside the composite). Note that an implementation can pertain to various composite types, and therefore may have different visibilities depending on the composite.

In the example, the instances of specifications "S3" will have "scope=local" and therefore cannot be used by other ocmposites; "S4" and any instance whose specification matches the regular expression "S.*" will have "scope=appli". The values set by the composite can only reduce the scope or visibility as directly set by the instance or implementation; by default scope and visibility are assumed to be "global".

<apam xmlns="fr.imag.adele.apam">
   <composite name="S2Compo" specification="S2"  mainComponent="S2Impl">
      <properties>
         <property shared="true" />
         <property borrowImplementation="true"/>
         <property localImplementation="(specName=S2)"/>
         <property borrowInstance="false"/> 
         <property localInstance="(specName=S3)"/> 
         <property appliInstance="(||(specName=S4)( specName=S.*)"/>
      <properties>
      <dependency specification="SX"/>
      <dependency specification="SY"/>
   </composite>
</apam>

Being an implementation, a composite also can define the constraints and preferences for its dependencies. In this case, the effective constraints and preferences will be the union of the composite one, plus those of the promoted implementation.

<apam xmlns="fr.imag.adele.apam">
   <composite name="S2Compo" specification="S2"  mainComponent="S2Impl" >
      <properties>
         <property shared="false"/>
         <property MyProperty="yes" type="string" />
      </properties>
      <dependency specification="SX">
          <constraints>
             <implementation filter="(status=validated)">   
          </constraints>
          <preferences>
             <implementation filter="(distributed=true)">                       
             <implementation filter="(owner=jacky)">                       
          </preferences>
       </dependency>
   </composite>
</apam>

In this example, the constraint applied to the implementation resolution of "SX" is "(status=validated)" plus those imposed by the implementations selected as promotion toward "SX". Additionaly, if possible, the implementation resolution of "SX" should satisfy first "(distributed=true)" and second (owner=jacky).

Component ownership and instances

An example scenario

In order to illustrate, let us assume the following declarations:

<specification name="heaterControl" interface="HeaterControl">
	<properties>
		<property exclusive="true"/>
	</property>
</specification>
<specification name="thermometer" interface="Thermometer" />
 
<specification name="energyControl" interface="EnergyControl">
   <dependency specification="heaterControl" />
   <dependency specification="thermometer" id="temp">
       <constraints>
            <instance filter="(location != oven)" />
       </constraints>
    </dependency >
</specification>
 
<implementation name="energyImpl" specification="energyControl"   
      className="energyMain">
	<dependency specification="heaterControl" field="heater">
	<dependency specification="thermometer" field="thermometers">
</implementation>

The Owns primitive

An instance is created in Apam either because a) it "appears"(a device is discovered or it is created by a third party), or b) it is created by Apam to resolve a dependency. In case b), the new instance is owned by the composite containing the source of the resolved dependency. In case a), the instance that appears in the system has no owner; it is created in the special "unused" composite and nothing else occurs. An unused instance is visible by everyone, and may be solution of a future resolution; in which case it is moved into the composite containing the client. The ready policies indicate which action can be undertaking when a new instance appears. The "owns" primitive allows to define which composite will be the owner of a service that appears.

Components are identified as follows : “Component” means either implementation or specification. Let us declare the following syntax fragments (bold italic are literals):

depSource  == specification="xx" | implementation="xx" | component="xx"
<owns depSource/>
<owns depSource>
    constraints
</owns>

The first sentence expresses that if an instance appears, which is resolution of component (either specification or implementation) with name "xx", its implementation is placed inside the current composite type, and the instance is placed inside the current composite instance, without client. The second sentence expresses the same, but the appearing instance must also satisfy the constraints. The constraints only apply on component "xx" properties. The system tries to check that a single "owns" clause in the whole system can be true at any point in time (ownership should never be ambiguous). This property can be statically checked only if the constraints are simple expressions over values of the same enumerated attributes defined in the component. For example, if the composite Comfort must be sure it will contain the Thermometers, it should indicate:

<owns component="Thermometer"/>

It means that Comfort will own all the thermometers. A composite Kitchen can indicate:

<owns component="Thermometer"> 
   <constraints>
      <constraint filter="(location=oven)" />
   </constraints>
</owns>

This example expresses that the Kitchen composite must own the oven thermometer. In this example, the system will check the owns clauses and detects that the Thermometer ownership conflicts between Comfort and Kitchen composites (the oven thermometer cannot pertain to both the Comfort and the kitchen composites). If both the comfort and the kitchen composites are in composite Home, this error is detected when building Home, otherwise it will be detected when deploying the Comfort or the kitchen composite, and the deployment fails. The ownership of a device allows the owner composite to define the visibility, sharing and access conflict resolution related to that service. The "owns" primitive is executed before any start, since visibility depends on the composite owner. Note that the owns primitive is applied only on instances that appear, not on those instances created by Apam during a dependency resolution. Better say, owns is applied on devices and on those services that are instantiated by third parties.

Action instance

<instance depSource [name="ii"]/> 
<instance depSource [name="ii"]> 
     [targetDef] [properties] [dependencies] <! Condition for creation -->
</instance>

This is an extension of the instance tag. It asks for the creation of an instance called ii of depSource. If targetDef is missing, the instance creation is performed as soon as the composite containing this action is started; otherwise the instance is created as soon as a visible instance satisfying targetDef is created. If the instance action is defined in an implementation, depSource is resolved as a root composite, otherwise depSource is resolved in the scope of the composite type which defined this model, and inside one (arbitrarily selected if more than one) of its composite instances. An instance of component is immediately created and therefore may be solution of subsequent resolutions. If the component implements the ApamComponent interface, the created instance gets the control immediately. If no “own” primitive exists for that instance, it will be created in the root composite and will become the main instance of a default composite instance. The system does not make any hypothesis about the relationship between the instance targetDef and the instance created. In particular, the ownership of the instance that appeared, and its future availability are not granted.

<instance component="energyControl" /> 
<instance component="energyControl">
   <specification name="Thermometer" >
      <constraints>
	   <constraint filter="(location=living)" />
      </constraints>
   </specification>
</instance>

In the first example, an instance of component energyControl is created as soon as the component containing that sentence is started. In the second case, the energyControl is launched as soon as an instance of specification Thermometer satisfying location=living is discovered.

Controling Dependency properties

A composite can overload the dependency properties defined in the implementation definition, and described in (see Components). From a composite, a dependency is referenced by the component name and the dependency id:

dependency == specification="xx" id="ddd" | implementation="xx" id="ddd"| component="xx" id="ddd"

Property wait

When a resolution fails, the dependency is said to be “frozen” and the current thread and all subsequent thread using this dependency will be halted and queued. When an instance that satisfies the dependency appears, the dependency is resolved and the blocked threads are resumed. Note that the dependency only is frozen, any thread entering the component object without using the frozen dependency will perform as usual. An implementation with a wait (and delete) dependency is visible for a client only if all its wait dependencies can be resolved for that client.

<wait dependency />

<wait specification="energyControler" id="temp">

If all the temp dependencies are removed (no thermometer is available), the system will halt all threads making use of the Thermometer dependency, and will resume them after at least one Thermometer dependency has been established (at least one thermometer is available). The energyControler cannot be instantiated if no thermometers are available.

Property delete

<delete dependency />

When a dependency disappears (the provider disappeared, and no alternative provider could be found; for example, the last thermometer disappeared), the client instance must be deleted. All the wires toward the deleted instance are removed . Deleting an instance x is interpreted by the system as “instance x disappeared”. Note that Apam turns to “null” or the empty set all the variables related to the deleted dependencies (variable heater in our example), but if the program contains copies of these variables, the Java VM will not remove the corresponding Java objects, and errors may occur if using these variables. If a thread was inside instance x at the time it is deleted, the thread continues its execution, until it leaves x normally, or it makes an exception. No other thread can enter a deleted object since wires have been removed. An implementation with a delete dependency D is invisible from a client C if dependency D cannot be satisfied for C .

<delete specification="energyControl" id="heaterControl">

The energyControl instance has to be deleted if the heaterControl dependency disappears. As long as heaterControl cannot be resolved, no energyControl instance can be created.

Property mandatory

<mandatory dependency />

By default, a resolution is lazy, and may fail, leaving the variable with a “null” value or an empty Collection which requires the programmer to test the variable before any use. Many components can perform their job only if some dependencies are available; it makes no sense starting a component without these dependencies. We call such a dependency mandatory; a component with a mandatory dependency is called a coupled component, and the provider of a mandatory dependency is called a coupled provider. The life cycle of a coupled component is completely linked (coupled) with the life cycle of its coupled providers. A coupled component is created with its coupled providers, and deleted if at least one of its mandatory dependencies cannot be satisfied (at least one of its coupled providers disappeared and could not be replaced). Note that a chain of coupled components is created atomically, but chains are not statically defined, since each mandatory dependency is resolved independently; the selected component is not statically known (in general); it depends on the current context and can be itself a coupled component or not. A mandatory dependency is a delete dependency. Therefore, if a coupled provider disappears, Apam tries to satisfy the mandatory dependency with another service, but if no alternative solution is found, the coupled client is deleted. The coupled provider is not visible as long as at least one of its delete dependencies cannot be satisfied. This algorithm ensures that the resolution process will not loop, and will be optimized. If the deleted client is itself a coupled provider, the same process is repeated one “client backward”, until an alternative resolution is found or there are no more mandatory dependencies. Therefore coupled chains are deleted only after having tried all the alternative solutions at each level of the chain. The resolution mechanism is such that the coupled component instances that cannot be created (some coupled providers are missing) are simply ignored . For example, a component with a mandatory dependency toward a device will be ignored as long as this device is missing, and automatically becomes selectable as soon as the coupled device appears.

<mandatory specification="energyControler" id="temp"/>

It means that the component energyControler can be started only if its dependency called temp can be immediately satisfied, i.e. if at least a thermometer (except oven) is available, and will be deleted as soon as all thermometers disappear.

Access conflict resolution

Policy change and composite state When a client has established a wire towards a provider, this wire is “permanent” until the provider disappears; however in some cases, there is a need to change or delete an existing wire. Composites, specification as well as instance, can declare a state, which is a special property with name “state” and with enumerated values. For example:

<specification name="energyControl" interface="EnergyControl">
   <composite>
      <states values="[Ok, vacation, emergency, night]" default="normal"/>

Actions grant and release must be defined with respect to the state of the current composite .

Action grant

<grant dependency when />
when == when="state" | when="( {state ,} )"
 
<grant specification="emergencyControl" id="heaterControl" when="emergency"/>

The component emergencyControl preempts the service matching heaterControl dependency if the composite state instance is emergency AND if the emergencyControl and heaterControl instances are “owned” by the current composite instance. It means that if a wire exists toward heaterControl, it is removed and recreated from emergencyControl. In orther words, emergencyControl takes the control of the heater in case of emergency. The client on which the wire is deleted is automatically placed in the “wait” status for that dependency. As soon as the when condition is no longer satisfied (the current composite instance state changed), the granted wire is removed; and the waiting component, if any can be resumed.

The system checks that at most one grant condition can be true on the same instance. If we also have

<grant specification="energyControler" id="HeaterControl"
	when="{Ok, vacation, night}" />

Because of the emergencyControler “ grant” expression, the energyControler loses the door control in case of emergency and waits, but regains that control as soon as (state=Ok). The energyControler and emergencyControler will get the heater control depending on the state value.

Action release

When a client has established a wire towards a provider, this wire is “permanent”; only the client termination, or a “grant” clause can remove the wire. When the provider is an exclusive or limited resource, it may be wise to release the provider as soon as possible. This is what performs the “release” clause.

<release dependency when />

when == when="state"| when="( {state ,} )"

Example :

<release specification="emergencyControl" id="HeaterControl"
	when="{Ok, vacation, night}"/>

It is possible to change the binding explicitly.