Jump to: navigation, search

Difference between revisions of "SMILA/Documentation/Declarative Services"

(Overview)
(Component-Class)
(One intermediate revision by one other user not shown)
Line 53: Line 53:
 
  }
 
  }
 
</source>
 
</source>
 +
 +
{{Note|If you do not need access to the ComponentContext in order to activate/deactivate your component, you can ommit the ComponentContext parameter. e.g.:
 +
<source lang="java">
 +
protected void activate()
 +
</source>
 +
}}
  
 
== Component-Description ==
 
== Component-Description ==

Revision as of 08:54, 28 August 2012

Overview

SMILA makes heavy usage of a OSGi feature named "Declarative Service" (DS). On this page we describe some practices that we found useful when working with Declarative Services.

A DS component provides and requires services. These services will be described declarative. The so called service component runtime will only activate a service component, if all required services are available in the system. The services that are provided by a service component may be activated retarded, i.e. they are only then created, when a using bundle accesses these services. A service component consists of an implementing class (component-class) and an xml-document (component-description).

Service Component Runtime

The Service Component Runtime is responsible for the creation of Service Components and for the administration of their life cycles. It will be provided by the implementation of the Declarative-Service-Specification. The Service Component Runtime checks with the installation of a Bundle whether this contains one or more component descriptions. Is this the case, the Service Component Runtime tries to solve the dependencies of a component to other services. The Runtime examines whether all required services are present in the system. If all required services are available, an instance of the components will be produced and activated. However if a necessary service is not available, then the instantiation and activation of the component are retarded so for a long time, till all required services are available up to a later time. Components may be parameterised by Component Properties. These properties may be declared in the component description. Alternative the properties may be set by Component Factories at Runtime, too.

The usage of Declarative Services offers a number of significant advantages:

  • Delayed activation of services: Services will be retarded activated if they are provided by component. That means the provided service is registered at the service registry with the start of the implementing bundle. But the service instance will be first created and activated with the first access.
  • Resolving of service references: References for required services are resolved by the Service Component Runtime. Only if all necessary services are available in the system, the component will be instantiated and activated. Thus the handling of potential dynamic of services will be dramatically simplified in the component-class.


Component-Class

The component-class is a simple java class, that optional may define callback-methods. With these methods you have the ability to run several actions at the activation or deactivation of a service component. A component-class may define a method activate(ComponentContext). This method will be invoked by the Service Component Runtime, if the corresponding component instance is activated.

Sample activate()-method:

protected void activate(ComponentContext)

The method deactivate(ComponentContext) will be invoked, if the corresponding component instance is deactivated.

Sample deactivate()-method:

protected void deactivate(ComponentContext)

Keep in mind that the component class have not to implement a special interface. It is enough when both methods exist on the component class. Both methods will be assigned an object from type org.osgi.service.component.ComponentContext by a parameter. With the component context you may access properties of a component or you may query the bundle context of the defined bundle and some things more. See below:

package org.osgi.service.component;
 
 public interface ComponentContext {
 
    public Dictionary getProperties();
    public Object locateService(String name);
    public Object locateService(String name, ServiceReference reference);
    public Object[] locateServices(String name);
    public BundleContext getBundleContext();
    public Bundle getUsingBundle();
    public ComponentInstance getComponentInstance();
    public void enableComponent(String name);
    public void disableComponent(String name);
    public ServiceReference getServiceReference();
 
 }
Note.png
If you do not need access to the ComponentContext in order to activate/deactivate your component, you can ommit the ComponentContext parameter. e.g.:
protected void activate()


Component-Description

The component description describes a component, if necessary with dependencies to other services. This happens in form of an xml-document. Additional you may declare, if a component provides itself a service at over the service registry. The name of the xml file has to be defined as the manifest header Service-Component.

Sample Service-Component manifest header:

Service-Component: OSGI-INF/component-description.xml

The root element of a component-description is the xml-element component. It offers the listed attributes:

name constraint description
name required The global explicit name of a component.
enabled optional Defines, whether the component starts the bundle and whether the component is activated or not. Default: true
factory optional When the described component is a factory component then this attribute has to include the name of the factory.
immediate optional Defines, whether a component, that defines own services, should activated delayed or not.

The implementing class of a component is specified by the child element implementation. It has a single attribute class.

name constraint description
class required The full qualified name of the implementing java class.

Sample component description:

<component name="simpleComponent">
  <implementation class="org.eclipse.smila.simplecomponent.SimpleComponent" />
</component>


Provide services

The instance of a component may be registered itself as an OSGI-service at the service registry. This also happens declarative with the xml-element service in the component description. This element has the attribute serviceFactory.

name constraint description
serviceFactory optional Defines, whether the service should be identical to all using bundles (true) or whether an instance of the component should be created for each using bundle by a ServiceFactory. Default: false

The specification of the service-interfaces takes place via the child element provide. This element has the attribute interface.

name constraint description
interface required The full qualified name of the class, under which the component instance should be announced at the service registry.

Sample component description:

<component name="simpleComponent">
  <implementation class="org.eclipse.smila.simplecomponent.SimpleComponent" />
  <service>
    <provide interface="org.eclipse.smila.simplecomponent.SimpleService" />
  </service>
</component>

Use Services

Components may use services that were registered by other bundles or components at the service registry. The specification of service dependencies takes place via the xml-element reference. This element has the following attributes:

name constraint description
name required The local explicit name of the reference.
interface required The full qualified name of the interface, under which the service is applied to the service registry.
cardinality optional Defines, whether a reference is optional how many service may be bounded by this reference.
policy optional Defines, how to interact with changes at the initial bounded services.
target optional A filter that describes the referenced service more near.
bind optional The name of the method, under which a service may be placed to the component.
unbind optional The name of the method, under which a service may be deleted from the component.

In principal two different strategies are available for the specification of references to services:

Event-Strategy

Whit the use of the Event-Strategy you have to implement a bind- and an unbind-Method for the referenced service in the component-class. You may choose the name of these methods, but the methods have to be public or protected and have to have the return value void. The type of the single parameter may be either a ServiceReference or the type of the service (normally the service interface). If the referenced service is available, it will be set with the bind-Method by the service component runtime at the component instance. If the referenced service is deleted from the system, the service component runtime will call up the unbind-Method.

Sample Event-Strategy

component-class

package org.eclipse.smila.simplecomponent
 
import org.osgi.service.component.ComponentContext; 
import org.eclipse.smila.service.SmilaService;
 
public class SimpleComponent implements SimpleService {
 
   private SmilaService smilaService;
 
   // bind-Method
   protected void setSmilaService(SmilaService smilaService) {
      this.smilaService = smilaService;
   }
 
   // unbind-Method
   protected void unsetSmilaService(SmilaService smilaService) {
      this.smilaService = null;
   }
}

component-description

<component name="simpleComponent">
  <implementation class="org.eclipse.smila.simplecomponent.SimpleComponent" />
  <service>
    <provide interface="org.eclipse.smila.simplecomponent.SimpleService" />
  </service>
  <reference name="smilaService"
             interface="org.eclipse.smila.service.SmilaService"
             bind="setSmilaService"
             unbind="unsetSmilaService"
             />
</component>


Lookup-Strategy

With the use of the Lookup-Strategy the referenced service aren´t set directly to the component by the service component runtime, but it have to be polled over the component context via the method locateService(). The implementation of appropriate bind- and unbind-Methods is not necessary.

Sample Lookup-Strategy

component-class

package org.eclipse.smila.simplecomponent;
 
// [...]
 
public class SimpleComponent implements SimpleService {
 
  private ComponentContext componentContext;
 
  protected void activate(ComponentContext context) {
    componentContext = context;
  }
 
  protected void deactivate(ComponentContext context) {
    componentContext = null;
  }
 
  private SmilaService getSmilaService() {
    if (this.componentContext != null) {
     return (SmilaService) this.componenContext.locateService("smilaService"); 
   }
 
   return null;
  }
}

component-description

<component name="simpleComponent">
  <implementation class="org.eclipse.smila.simplecomponent.SimpleComponent" />
  <service>
    <provide interface="org.eclipse.smila.simplecomponent.SimpleService" />
  </service>
  <reference name="smilaService"
             interface="org.eclipse.smila.service.SmilaService" />
</component>

Cardinality of a reference

The cardinality of a reference describes the following properties:

Optionality

The optionality of a reference declares, whether the referenced service is compelling needed by the component or whether it may work without the referenced service. E.g. a component that references a logging service may work meaningful, when the logging service is not available. Only the output of the log message would not be possible in this case.

Multiplicity

The multiplicity of a reference defines whether a component is interested in exactly one instance of the referenced service or whether it is able to deal with multi service instances.

The cardinality of a reference is arranged by the attribute cardinality that is available at the element reference. The following values may be set:

name description
0..1 - optional and unary The referenced service is optional and only one instance of the referenced service may be assigned to the component.
1..1 - mandatory and unary The referenced service is mandatory and only one instance of the referenced service may be assigned to the component. That is the default attitude, if the cardinality-attribute is not set.
0..n - optional and multiple The referenced service is optional and all available instances of the referenced service are assigned to the component.
1..n - mandatory and multiple The referenced service is mandatory and all available instances of the referenced service are assigned to the component.

Sample with 0..1 cardinality

component-description

<component name="simpleComponent">
  [...]
  <reference name="smilaService"
             interface="org.eclipse.smila.service.SmilaService"
             bind="setSmilaService"
             unbind="unsetSmilaService"
             cardinality="0..1"
             />
</component>

Policy of a reference

The service component runtime ensures that a service component will only be instanced and started if all required services for a component are available at the system. The referencing services will be bound to the component by activating. Now the OSGI service platform has the feature that services may be registered and unregistered in the system at runtime. E. g. a service that is bound to a component may be unregistered after activation from the service registry. After that all object references to the corresponding service object expire. Therefore a component has to define how it should interact with changes at bound services. For it a component may specify the attribute policy of the element reference. This attribute may accept the following values:

Static

With the use of the static-policy the services that are bound by activating of the component won´t be modified. If a bound service is deactivated by the service registry the referenced component will also be deactivated. If an alternative service that complies with the dependencies of the component is registered to the service registry then the component will directly be (re-)activated with the new bound service. The static-policy is the default policy. It is used if the policy-attribute is not set.

Dynamic

With the use the dynamic-policy a component won´t be deactivated, if a bound service is deregistered, while all service references may be further fulfilled. The implementation of the component must be able to react therefore to changes concerning the bound services. If a reference uses the event-strategy to access to service, then the component will be informed about changes of the bound services by the corresponding bind- and unbind-Methods.

Sample with policy=dynamic

component-description

<component name="simpleComponent">
  [...]
  <reference name="smilaService"
             interface="org.eclipse.smila.service.SmilaService"
             bind="setSmilaService"
             unbind="unsetSmilaService"
             cardinality="0..1"
             policy="dynamic"
             />
</component>

The life cycle of a component

General components may be activated, when they are in the condition enabled. Normally components will be set automatically to this condition by the service component runtime as soon as the defining bundle is started. If the defining bundle is stopped, the service component runtime sets the contained components into the condition disabled. With the component-attribute enabled it is possible to specify that a component is not set into the condition enabled when starting the defining bundle. With the methods ComponentContext.enableComponent(String name) and ComponentContext.disableComponent(String name) components may set programmatically over their logical name into the condition enabled or disabled.

Immediate and delayed components

The declarative service specification differentiates two different kinds of components:

Immediate Components

Immediate components are components that are activated directly, when all necessary references are fulfilled, i.e. the referencing services are available in the system.

Life cycle of immediate components

Immediate component are activated, if all required services of a component are available in the system, i.e. all necessary references may be fulfilled. The possibly implemented method activate() of the component instance is called during the activation of a component. An active component will be deactivated, if the required services are not longer available, the component instance is set into the condition disabled via the method ComponentContext.disableComponent() or the defined bundle is stopped.


Delayed Components

Delayed components are components that provide one or more services. They are only then activated, if the services made available by the component are queried at the service registry.

Life cycle of delayed components

Service components, that make services available, are delayed components by default. I.e. they will be only then activated, if a service made available by the component is queried by the service registry. If a delayed component is set into the condition enabled, the service component runtime tries to solve the service dependencies that are defined by the component. If this is successful the service component runtime will register a proxy-object, which represents the service, to the service registry. Only if the service is queried by the service registry, the service component runtime will activate the service component and delegates the call to the real service. This happens for the user of the service completely transparency. If a service reference sets the attribute servicefactory="true", then a new instance of the component will be instantiated and activated for every querying bundle. Alternatively only one common component instance is available for all bundles.