Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The Apache Felix Service Component Runtime described by the OSGi Desclarative Services Specification is implemented by the org.apache.felix.scr bundle. As specified, the components must be declared in XML-formatted descriptor files which in turn must be listed in the Service-Component header of the declaring bundle.

The component declarations are read when the declaring bundle is started and the respective components are verified and activated depending on their declaration.

Example

To help you get a head start, here is an example of using Declarative Services. You will find more examples in the trunk/examples folder of the Apache Felix Project.

Component

First of all the component must be implemented in a simple Java class. The Declarative Services Specification basically places no restrictions on the contents of this class. If you make use of advanced functionality such as providing an activate() or deactivate() method or using service loopup by event strategy (see 112.3.1 Accessing Services) you will of course have to provide the respective methods.

For the sake of example, lets define a very simple class, which implements a java.util.Comparator service:

Code Block
titlesample/SampleComparator.java

package sample;
import java.util.Comparator;
public class SampleComparator implements Comparator
{
    public int compare( Object o1, Object o2 )
    {
        // TODO: calculate the result
        return o1.equals( o2 ) ? 0 : -1;
    }
}

This is of course a very simple and not very intelligently implemented comparator...

Declaration

The next step consists of writing the declaration. I usually put these files in the OSGI-INF folder of the bundle, but the files may be placed anywhere within the bundle or any of the bundle's fragments as long as its path is listed in the Service-Component bundle manifest header.

So here we go with the file:

Code Block
titleOSGI-INF/sample.xml

<?xml version="1.0" encoding="UTF-8"?>
<component name="sample.component" immediate="true">
  <implementation class="sample.SampleComparator" />
  <property name="service.description" value="Sample Comparator Service" />
  <property name="service.vendor" value="Apache Software Foundation" />
  <service>
    <provide interface="java.util.Comparator" />
  </service>
</component>

There are some noteworthy settings in this descriptor already:

  • name - Uniquely identifies this component and is also used to retrieve optional configuration from the Configuration Admin Service (if available).
  • immediate - Defines whether the component is to be instantiated immediately (true) or on-demand (false).
  • implementation.class - The fully qualified name of the class implementing the component. This class must be public and have a public default constructor for it to be usable by the Service Component Runtime. This class is not required to be exported and may as well be private to the bundle. In fact, you will generally not export the component implementation class.
  • property - These elements define configuration properties to the component. These properties are available through the ComponentContext which is presented to the component in the activate method (see below).
  • service - If the component is to be registered as a service, the service names are listed in provide elements inside the service element. These names will generally be interfaces and must be visible to other bundles for the service to be usable. In this sample, the service is the Java java.util.Comparator class, which is always visible.

To finalize this declaration, add the following header to the bundle manifest:

Code Block

Service-Component = OSGI-INF/sample.xml

Activation

It may well be that the component needs to be notified, when it is activated and deactivated. For this, the component may implement an activate method and a deactivate method. Both methods must be public or protected and take a single argument, the org.osgi.service.ComponentContext. It is recommended for this method to the protected as it is only used by the Service Component Runtime and should of course not be part of the public API of the component.

Here is the initial class extended with activation and deactivation methods:

Code Block
titlesample/SampleComparator.java

package sample;
import java.util.Comparator;
import org.osgi.service.component.ComponentContext;
public class SampleComparator implements Comparator
{
    public int compare( Object o1, Object o2 )
    {
        // TODO: calculate the result
        return o1.equals( o2 ) ? 0 : -1;
    }

    protected void activate(ComponentContext context)
    {
        // TODO: Do something on activation
    }
    
    protected void deactivate(ComponentContext context)
    {
        // TODO: Do something on deactivation
    }
}

Nothing more needs to be done as the Service Component Runtime automatically recognizes and calls these methods.

Service Binding

The next step would probably be to do some service binding. This is somewhat more overhead, as the referred to services must be declared. On the other hand, you do not have to care to listen for these services. As an example, we will refer to the OSGi LogService. First we will use the lookup strategy and second we will use the event strategy (I personally prefer the event strategy, but your mileage may vary).

Looking up the Service

To use the service, the reference must be declared in the service declaration in an reference element. Here is the respective declaration for a log service to lookup:

Code Block
titleLogService Reference

<component...>
   ...
   <reference name="log"
         interface="org.osgi.service.log.LogService"
         cardinality="1..1"
         policy="static"
   />
   ...
</component>

To use this service you call the ComponentContext.getService(String) method, for example in the activate method:

Code Block

protected void activate(ComponentContext context)
{
    LogService log = (LogService) context.locateService( "log" );
    log.log(LogService.LOG_INFO, "Hello Components!");
}

Receiving the Service

The event strategy works by declaring bind and unbind methods in the component descriptor. These methods take a single parameter of the type defined in the reference.interface attribute and must be declared public or protected. As with the activate and deactive it is recommended for the bind and unbind methods to be declared protected as they are generally not part of the public API of the component.

When using the event strategy, you will want to store the service in a private field of the component for later use.

First here is the reference declaration:

Code Block
titleLogService Reference

<component...>
   ...
   <reference name="log"
         interface="org.osgi.service.log.LogService"
         cardinality="1..1"
         policy="static"
         bind="bindLog"
         unbind="unbindLog"
   />
   ...
</component>

And here is some code:

Code Block

private LogService log;

protected void activate(ComponentContext context)
{
    log.log(LogService.LOG_INFO, "Hello Components!");
}

protected void bind(LogService log)
{
    this.log = log;
}

protected void unbind(LogService log)
{
    this.log = null;
}

Note, that you may refer to the log field in the activate method as we declared the reference as required. In this case the reference is provided to the component in the bind method before the activate method is called.

Summary

This tutorial just listed some very basic information on Declarative Service. To get more information, for example on hoe the Configuration Admin Service may be used to configure components, refer to the Declarative Services Sepecification in the OSGi Service Platform Service Compendium book.

Have Fun !

This page is out of date!

The Apache Felix Service Component Runtime provides an Activator implementation for you. Simply use the following as your Activator:

...