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
- updated(String pid, Dictionary dictionary) invoked when a new or updated configuration dictionary is sent to the ConfigurationAdmin service; the service factory is asked to create/update the service pid using the specified configuration
- deleted(String pid): the service factory is asked to delete the pid service
- getName returns the name of the service factory
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);
}
}
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.

Hi Filippo,
Just my 2 cents…
Very nice article, i just already know the Managed Service Factory paradigm because i started to look at it for my project, because as you described i have the requirement to create multiple instances of the same services.
BTW at the end i’ve still prefer to use DS component factories, because the services that i need to create on demand are “complex” beacuse they still depends on other services and provide services and so one, and the ManagedServiceFactory seems to be a bit limitated in this.
On the other side with DS i finally manage my ComponentFactories and then use it to create, update delete my complex services.
Unfortunately i’ve not found a way to use the ConfigAdmin with DS component factories… so i finally write a very simple service that polls a directory and provide to use component factories…
Cheers
Andrea