Factory pattern on steroids: the ManagedServiceFactory

A few months ago we explored the OSGi Configuration Admin Service, and the ManagedService interface in particular, to see how it is possible to create dynamically configurable services with OSGi.

The second important interface exposed by the Configuration Admin Service is the ManagedServiceFactory; as the name suggests, its purpose is to create multiple, dynamically configurable, implementations of the same service.

      Read also:
Configuration Admin Service explained: the ManagedService interface

Let’s see how we can use it with an example.

Let’s suppose we have written a service RetrieveFile that retrieves a file from a specified URL every t (configurable) seconds. The interface of this service will be something like:

public interface RetrieveFile
{
    public void setURL(String url);
    public void setInterval(Long time);
    public void start();
    public void stop();
}

The requirement is to be able to create new instances of this service on the fly, during the application execution. We want also to be able to modify existing instances and delete them when they’re not needed anymore.

The first step is obviously to create the RetrieveFileFactory, implementing the ManagedServiceFactory interface.

public class RetrieveFileFactory implements ManagedServiceFactory
{
    Map existingServices = new HashMap(); 

    public void updated(String pid, Dictionary dictionary) throws ConfigurationException
    {
        //updating the configuration of the pid service
        if (existingServices.containsKey(pid))
        {
            RetrieveFile service = (RetrieveFile) existingServices.get(pid);
            service.stop();    //stop the service before reconfiguring it
            service.setURL( (String) dictionary.get("url") );
            service.setInterval( (Long) dictionary.get("interval") );
            service.start();
        }
        else //new configuration
        {
            RetrieveFile service = new RetrieveFileImplementation();
            service.setURL( (String) dictionary.get("url") );
            service.setInterval( (Long) dictionary.get("interval") );
            service.start();
            existingServices.put(pid, service);
        }
    } 

    public void deleted(String pid)
    {
        // stop and remove the pid service
        RetrieveFile service = (RetrieveFile) existingServices.remove(pid);
        service.stop();
    } 

    public String getName()
    {
        return "com.acme.factory.retrieveservice";
    }
}

As the example shows, three methods must be implemented

The second step is to register our RetrieveFileFactory as a ManagedServiceFactory; that’s easily achievable doing a regular service registration inside the bundle activator:

public class Activator implements BundleActivator
{
   private ServiceRegistration factoryService; 

   public void start(BundleContext context)
   {
     Dictionary props = new Hashtable();
     props.put("service.pid", "com.acme.factory.retrieveservice");
     factoryService = context.registerService(ManagedServiceFactory.class.getName(),  new RetrieveFileFactory(), props);
   } 

   public void stop(BundleContext context)
   {
      if (factoryService != null)
      {
        factoryService.unregister();
        factoryService = null;
      }
   }
}

That’s all the code you need to setup the ManagedServiceFactory.

Now to create new instances of the RetrieveFile service, all you need to do is to invoke the OSGi ConfigurationAdmin service sending a Dictionary object containing a url and interval parameter. There are several ways and tools to do that; you can of course do that also programmatically using the following code:

    private List configurationList = new ArrayList();   

    public void createNewService(String url, Long interval) throws Exception
    {
        ServiceReference configurationAdminReference =
            bundleContext.getServiceReference( ConfigurationAdmin.class.getName() );

        ConfigurationAdmin confAdmin = (ConfigurationAdmin) bundleContext.getService( configurationAdminReference );   

        Configuration configuration = confAdmin.createFactoryConfiguration( "com.acme.factory.retrieveservice", null );
        Dictionary properties = new HashTable();
        properties.put("url", url);
        properties.put("interval", interval);
        configuration.update(properties);   

        //Store in the configurationList the configuration object, so you can modify it later
        configurationList.add(configuration);
    }
}
osgi, tutorial

If you enjoyed this post, please consider to leave a comment or subscribe to the feed and get future articles delivered to your feed reader.

Comments

One Response to “Factory pattern on steroids: the ManagedServiceFactory”

Leave Comment

(required)

(required)