Donnerstag, 28. Februar 2013


There is an interesting interface called ServiceFactory. Citing the documentation (link at end), it

Allows services to provide customized service objects in the OSGi environment.

When registering a service, a ServiceFactory object can be used instead of a service object, so that the bundle developer can gain control of the specific service object granted to a bundle that is using the service.

So what does that mean?

  1. The service object can be created when the consuming bundle asks for it.
    In the normal scenario a service object is created and then registered when the bundle is started. With the ServiceFactory, the consuming bundle asks for the service and then the provider bundle creates the service object. (You don't need to register the newly created service object; the registration was already done with the ServiceFactory instance.)
  2. The ServiceFactory can return service objects which are different for each requesting bundle.
    In the normal scenario a service object is created and used by whichever bundle wants it. Now for each bundle which requests the service, the method ServiceFactory.getService is called and allows to return a new instance.
  3. The ServiceFactory can customize service objects before making them available.
    For instane the ServiceFactory instance can inspect the Bundle which requests the service object (like looking at certain entries in the MANIFEST). Depending on that inspection it can return different types of service objects or service objects with different configurations.

There are some interesting runtime details too:

  1. Service objects are cached by the framework.
    When a bundle requests a service, it gets delivered a service object. The next request call will deliver the same service object (unless it has been released in between). When the consuming bundle calls ungetService to tell that it doesn't need the service object anymore, the method ServiceFactory.ungetService is called by the framework. (Actually ungetService must be called as many times as getService, the framework maintains a use count.)

However, for a second bundle, the service objects of the first bundle are not reused by the framework. If two bundles retrieve a service and thus use the ServiceFactory, its getService method gets called for each of the bundles.

Samples in osgisnippets Project

The project osgisnippets contains a set of bundles with the name starting with set3. set3fac provides services using the ServiceFactory. set3cons1 and set3cons2 are two almost identical bundles, which consume the service. They create a window with a get and an unget button. The ServiceFactory provides a unique ID for each service object. The ID of the service object is shown by the consuming bundles in their window.


Error: type ServiceReference does not take parameters

When developing for an OSGi environment and especially when using Apache Felix derived projects, one may run into a strange error. It is strange, because inside Eclipse no errors are shown, but when using the Java compiler (javac), it complains like so:

[javac] .../ error: type ServiceRegistration does not take parameters [javac] ServiceRegistration svcReg;

A couple of circumstances need to exist to trigger this error:

  • JDK7 is used
  • Apache Felix 4.0.2 or 4.0.3 is used
  • javac is used to compile the project

OSGi code is compiled with the -jsr14 option and that leads to problems with the JDK7 compiler. The Eclipse JDT compiler compiles it well, and therefore there is no error when building only in Eclipse.

There are updated OSGi jars available now which fix this problem (and one doesn't need to recompile). These are org.osgi.core-4.3.1.jar and org.osgi.compendium-4.3.1.jar. They are on OSGi's site or on the maven sites. (See below)

My fix for an earlier project was to build the OSGi sources (org.osgi.* packages) with JDK7 and put them before the Felix jars in the classpath. This makes the new OSGi class files being used instead of the ones which are packaged with the Felix jars.