IoC with Felix Dependency Manager

Some explainations of the Xenotron Service Manager (XSM)

The Xenotron Service Manager has been suggested for contribution by Marcel Offermans and Xenotron to the Felix project in Apache and is now part of the Felix project as the Felix Dependency Manager.Original source and documentation

Andreas Ronge, Anders Janmyr and SCAN COIN have made some adaptions and extensions to it, namely

  1. Introduction of ConfigurationDependencies
  2. Ability to monitor the progress of the service assembly via the ServiceMonitor
  3. Converted to Java 1.4 (to be continued to Foundation 1.0)

resulting in the com.xenotron.osgi.zip, which has been donated to the Apache Felix project as well. You can also find the source code in the OPS4J subversion repository at

svn co [https://scm.ops4j.org/repos/ops4j/laboratory/users/andreas/com.xenotron.osgiThe] 

felix code is available at

svn co https://svn.apache.org/repos/asf/incubator/felix/trunk/org.apache.felix.dependencymanager/

Configuration lifecycle specification in XSM

Adding a service with Xenotron Dependency Management

public class Activator extends DependencyActivatorBase //1
{
 public void init( BundleContext iBundleContext, DependencyManager iManager )
 throws Exception
{           
Dictionary serviceProperties = new HashTable();         
serviceProperties.put("cn", "MySpecialDeviceManager");        
 iManager.add( createDependentServiceController() //2                 
.setInterface(IDeviceManager.class.getName(), serviceProperties ) //3                 
.setImplementation(DeviceManager.class) //4                 
.add(createServiceDependency().setService(IEventService.class).setRequired(true)) //5, 6                 
.add(createServiceDependency().setService(IDevice.class, "(cn=CustomerPrinter)").setRequired(true)) //5, 7                 
.add(createServiceDependency().setService(IDevice.class, "(cn=ServicePrinter)").setRequired(true)) //5, 7                 .add(createConfigurationDependency("devicemanager.conf").setRequired(true))); //8     }
 public void destroy( BundleContext iArg0, DependencyManager iArg1 )
 throws Exception
 {

 }
}

An Xenotron Activator should extend DependencyActivatorBase. It is a convenience class that:

  • Creates a DependencyManager
  • Provides convenience methods createDependentServiceController, createServiceDependency and createConfigurationDependency(ConfPid)
  • Calls init(BundleContext, DependencyManager) and destroy(BundleContext, DependencyManager) instead of OSGI start and stop
    • Add a service controller to the manager, the service controller is created with createDependentServiceController. It is a wrapper for your own service.
    • Set the optional interface for your service.
  • The interface is set by name and may have service properties (a Dictionary) associated with it.
  • The service properties may be used to differentiate between services with the same interface.
    • Set the mandatory implementation for your DependentServiceController.
    • Add as many dependencies as you like to the service with add(createServiceDependecy() and add(createConfigurationDependecy(confPid)
    • Set the interface for the dependency and set it to required.
    • If multiple dependencies exists for the same interface they may be differentiated by an LDAP filter string.
  • The filter works on the service properties provided when the service is registered.
  • Examples LDAP uses Reverse Polish Notation:
    • (cn=Babs Jensen) - common name is Babs Jensen
    • (!(cn=Tim Howes)) - common name is not Tim Howes
    • (&(objectClass=Person)(|(sn=Jensen)(cn=Babs J*))) - A person whose surname is Jensen or whose common name starts with Babs J
  • A ConfigurationDependency takes a configurationId as a parameter.

    What happens during instantiation of a service?

  1. When an implementation is set on the DependentServiceController with createDependentServiceController().setImplementation()
    • The service is instantiated.
    • Instance fields of the following classes are set, through reflection, if they exist:
      • BundleContext - The OSGI context
      • ServiceRegistration - The OSGI ServiceRegistration
      • DependentServiceController - The controller wrapping my service may be used to register new dependencies dynamically.
  2. When a DependentServiceController is added to the DependencyManager it calls start() on the DependentServiceController.
  3. start() starts tracking the required dependencies.
  4. setConfiguration is called on our service when the ConfigurationDependency is satisfied.
    • This is guaranteed to happen before the init() method is called on our service.
    • If setConfiguration() throws a ConfigurationException it will prevent the service from starting, the service will not be registered in OSGi.
    • If the configuration is not valid, the ConfigurationException should be thrown.
  5. When all required dependecies are satisfied our service is activated.
    • init() is called.
    • For each dependency:
      • Instance fields are set, through reflection, if they exist.
      • Callbacks are called if they exist.
    • starting() is called on all ServiceStateListeners.
    • Tracking of optional dependencies are started.
    • start() is called.
    • The service is registered with OSGI.
    • started() is called on all ServiceStateListeners.
      What happens with optional dependencies?

For optional ConfigurationDependencys setConfiguration may be called after start. Initially, the service will have to wotk without a configuration. setConfigurationmay also be called multiple times and it is up to the service to decide what to do in this case, especially in the case of an invalid configuration.

Optional ServiceDependencys that are not satisfied initially may be proxied by Null Objects and the service must function properly without them, hence optional (smile)

What happens when a higher ranking Service appears for dependencies?

When ServiceDependencies ranking changes during the life of a started service consumer, the instance field may be updated to point to a reference of the new highest ranking service for the satisfaction of the ServiceDependency in question.

When a started service gets a new configuration

If the new configuration is not valid, a ConfigurationException should be thrown and the service should continue running with the old (valid) configuration.