Sunday 19 December 2010

OSGi and service binding

If you, like me, are trying to "embed" some OSGi framework inside your own application, you might have encountered a few problems. One of the biggest hurdles when dealing with OSGi is the dynamism, listening to services and of course listing them. The OSGi community have a multitude of solutions to these problems such as ServiceTrackers, Service Activator Toolkit, iPOJO and of course Declarative Services.

All these have their respective pros and cons. Service tracking with only ServiceTrackers is not only hard (with more than a few services), it also requires alot of boilerplate code. First you need to list all the currently available services, and then you need to start a tracker to stay informed about new services being added, removed or modified. With only a few services, this will quickly build up and become a whole bunch of seemingly unnecessary classes, taking up a fair amount of lines.

As for the others, they are either somewhat big or they have performance impacts when the number of bundles and services rises. Declarative Services is a great tool and I use it alot in my bundles but... As I said, I've embedded OSGi (Felix) inside my own application which means that some (most) of my classes are not OSGi aware, meaning that they don't come from a bundle. I can't use DS to bind with these classes (not in an easy way at least).

So, what do we do? The good news is DynamicJava.org's ServiceBinding framework. Just put a jar on your classpath and use the (very trimmed down) binding framework as in

    OsgiServiceBinder serviceBinder = new OsgiServiceBinder(context);
    serviceBinder.bind(this, "addActionListeners",
        ServiceFilter.forInterface(ActionListener.class.getName()));

This will
  1. Search for all available services that has registered in to OSGi that they provide the service ActionListener. 
  2. Call addActionListeners with the services it found.
  3. Continue to call addActionListeners every time a service is added or removed.
Note that if addActionListeners is a method that takes an array of ActionListener as its argument, the OsgiServiceBinder will, on each call, give you all the registered services. If addActionListeners takes only a single ActionListener, OsgiServiceBinder will give you the one with the highest ranking. So, if you want to be notified when a service is unregistered, you will still need to do some "store previous value, compare with previous value". For simple service binding though, where you do not want to type in the 50 or so lines of code needed to work with a ServiceTracker - this is a great, simple API.

As a final comment: Do not use OSGi to register ActionListeners. At least, think hard before doing so. First of all, the framework will not care much for event dispatch thread rules and secondly, the service registry is a very hectic place. Don't make it more so with unnecessary service registrations.