Apache
Home » Documentation » Apache Felix Subproject Documentation

Apache Felix Service Component Runtime (SCR)

The Apache Felix Service Component Runtime described by the OSGi Declarative 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. But the good news is, you usually don't have to worry about XML as you can simply use annotations which are processed at build time. The build tool will create the XML files and headers for you.

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

The Apache Felix Declarative Services implementation is the reference implementation for the OSGi Declarative Services Specification Version 1.3 (R6) and therefore passes the OSGi CT.

Example

To help you get a head start, here is an example of using Declarative Services "by hand". Instead of using annotations, the XML is created by hand. We discourage doing so, but this is just to give you an idea how it really works. 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:

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 OSGI-INF/sample.xml file:

<?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:

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

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:

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 examples of these strategies we will first use the lookup strategy to access an OSGi HttpService and then we will use the event strategy to access an OSGi LogService (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:

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

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

protected void activate(ComponentContext context)
{
    HttpService http = ( HttpService ) context.locateService( "http" );
}

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:

<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:

private LogService log;

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

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

protected void unbindLog(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.

Maven SCR Plugin

To simplify the tasks of generating the SCR Desriptor and adding the Service-Component header to the bundle manifest, the Apache Felix Maven SCR Plugin may be used. This helps keeping the descriptor and the code in sync especially during development.

Configuration

The Apache Felix Declarative Services implementation can be configured with Framework properties which are read on startup of the implementation bundle and Configuration Admin Service configuraiton which is provided by the Configuration Admin Service to the service PID org.apache.felix.scr.ScrService.

The following properties are supported:

Property Default Value Description
ds.loglevel 1 Defines a logging level at which messages are logged. This configuration property is converted to an int number used as the OSGi Log Service logging level.
ds.showtrace false sets the log level to debug if set to true and the ds.loglevel cannot be converted to a value log level
ds.showerrors true Disables logging completely if set to false and the ds.loglevel cannot be converted to a value log level and the ds.showtrace is not set to true
ds.factory.enabled false Enables Component Factory functionality not compliant with the Declarative Services 1.1 specification if set to true. Only set this if you really know you need this. See the Non-Standard Component Factory Behaviour section below for more details.
ds.ctworkaround false Enables workaround functionality to pass the OSGi CT. Generally this property should not be set to true because it enables behaviour which is not compliant with the Declarative Services 1.1 specification. See FELIX-2526 for details.
ds.delayed.keepInstances false Whether or not to keep instances of delayed components once they are not referred to any more. The Declarative Services specifications suggests that instances of delayed components are disposed off if there is not used any longer. Setting this flag causes the components to not be disposed off and thus prevent them from being constantly recreated if often used. Examples of such components may be EventHandler services. The default is to dispose off unused components. See FELIX-3039 for details.

The ds.loglevel property is treated as follows:

This configuration mechanism is implemented in the ScrConfiguration and its helper classes.

Non-Standard Component Factory Behaviour

If you don't know what this section is about, just ignore it and leave the ds.factory.enabled configuration property unconfigured.

Versions of the Apache Felix Declarative Services implementation prior to 1.2.0 supported handling of Component Factory components which is not specification compliant.

This behaviour assumes the component name of the Component Factory component to be Service Factory PID and each configuration with this Service Factory PID causes the service component runtime to actually create and activate an instance of the Component Factory component automatically. This is not foreseen by the specification which defines instantiation of Component Factory components as being purely application controled and not configuration induced.

To have components instantiated with factory configurations, regular components should be used. This case each factory configuration instance will create a component instance.

If you know that you are using Component Factory components depending on this non-standard behaviour you may set the ds.factory.enabled configuration property to true (the default of this property is false thus disabling this functionality for specification compliance).

For details also refer to FELIX-1416

Administration

The OSGi Compendium specification defines no administrative API for Declarative Services. As of version 0.9.0-20071123.131249-8 a simple administrative API is provided the Apache Felix implementation. The bundle itself also has a Felix Shell Command providing easy commands to introspect the states of the registered components.

The Apache Felix Web Console has built-in support for Declarative Services administration based on this API.

Shell Command

The management API is made available to the Felix Shell as the scr command with a short list of subcommands:

Synopsis Description
scr help [ <subcommand> ]() Show help of the specific <subcommand> or list all known subcommands
scr list [ <bundleId> ]() List registered components of the bundle specified by <bundleId> or list all components. Each component is listed with its component ID, the state and the name. <bundleId> man be either the ID of a bundle or the symbolic name of a bundle.
scr info <componentId> Show a complete information dump of the given component. This dump includes the name, status, provided services and information on the service references. <componentId> may be either the ID of a component or the component's name. The component name must be used for disabled components.
scr enable <componentId> Enable the given component if not already enabled. If the component is already destroyed or enabled, this command has no effect. <componentId> may be either the ID of a component or the component's name. The component name must be used for disabled components.
scr disable <componentId> Disable the given component if not already disabled. If the component is already destroyed or disabled, this command has no effect. <componentId> may be either the ID of a component or the component's name. The component name must be used for disabled components.

The administrative API commands are also available in the Gogo shell where the subcommand names must be prefixed with the name space scr. Thus the list command corresponds to scr:list in the Gogo shell.

API Use

The API consists of the main interface org.apache.felix.scr.ScrService and two helper interfaces org.apache.felix.scr.Component describing a registered component and org.apache.felix.scr.Reference describing a single reference of a registered component. To access the management API, client applications just ask for the ScrService as usual:

....
ServiceReference scrServiceRef = bundleContext.getServiceReference( ScrService.class.getName() );
ScrService scrService = (ScrService) bundleContext.getService(scrServiceRef);
....

Alternatively, you may of course use the ServiceTracker or if you are using the ScrService in a component, you may have the ScrService bound according to the component declaration.

The ScrService allows access to all registered components, to a specific component by component ID or to all registered components of a specific bundle.

Summary

This tutorial just listed some very basic information on Declarative Service. To get more information, for example on how 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 !

Rev. 1741809 by cziegeler on Sat, 30 Apr 2016 20:20:56 +0000
Apache Felix, Felix, Apache, the Apache feather logo, and the Apache Felix project logo are trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners.