You are on page 1of 45

Getting started with OSGi

Table of Contents
Preface................................................................................................................................. 2
Part 1 : Your first bundle........................................................................................................ 3
Part 2 : Interacting with the Framework.................................................................................... 5
Part 3 : Dependencies between Bundles................................................................................... 8
Part 4 : Registering a Service................................................................................................ 12
Part 5 : Consuming a Service................................................................................................ 15
Part 6 : Dynamic Service Tracking......................................................................................... 19
Part 7 : Introducing Declarative Services................................................................................ 24
Part 8 : Declarative Services and Dependencies...................................................................... 27
A Comparison of Eclipse Extensions and OSGi Services............................................................ 32
Structure of the article..................................................................................................... 32
The Eclipse Extension Registry.......................................................................................... 32
OSGi Services................................................................................................................. 35
Declarative Services......................................................................................................... 38
Composing Services......................................................................................................... 40
Making a Choice.............................................................................................................. 40
Common Misconceptions.................................................................................................. 42
Comparison Matrix....................................................................................................... 43
Conclusion...................................................................................................................... 44
References................................................................................................................. 44
Acknowledgements...................................................................................................... 45
Preface
The original tutorial was provided originally by Neil Bartlett on the web and consists of 8 lessons.
Unfortunately, the website was taken down. Actually, the individual articles are still accessible at
eclipseZone. The current document consists of the digested content of all published articles
including an add-on information about OSGi.
Part 1 : Your first bundle
Actually this first part will be a little longer than the others, because we need to set up a very basic
working environment. Before getting started, we need an OSGi framework to run on. There are three
open source implementations to choose from: Apache Felix , Knopflerfish , and Equinox . The code
we're going to write will be identical no matter which one you choose, but the instructions for
running it will be a little different. Since this is EclipseZone, we will use Equinox, the runtime that
Eclipse itself is built on. You can pull a copy of it right out of your existing Eclipse installation: just
find the file org.eclipse.osgi_3.2.1.R32x_v20060919.jar and copy it to an empty directory (NB the
version string might be a little different depending on what version of Eclipse you have). If you don't
have a copy of Eclipse anywhere, then you can download just that Jar file from
http://download.eclipse.org/eclipse/equinox/ .

To keep the commands short, let's rename the Jar file to equinox.jar . Now bring up a
Command Prompt in our development directory and run the command

> java -jar equinox.jar -console

In a few seconds, the osgi> prompt should appear. Congratulations, you are now running OSGi !

The osgi> prompt gives us access to commands in Equinox to control the framework. If you like,
type help to see a list of commands, and have a play with them. Done that? Now type ss . This is
the most frequently used command; it stands for "short status" and it shows us the list of bundles
that are installed, and what their current status is. (A "bundle" is a module in OSGi terminology. Or
if you are an Eclipse developer, you may know them as plug-ins; bundles and plug-ins are basically
the same things.)
Equinox should print out the following :

Framework is launched.

Id State Bundle
0 ACTIVEsystem.bundle_3.2.1.R32x_v20060919

This tells us that there is one bundle installed and active, and it is the System Bundle. This is a
special bundle in OSGi that is always present, and it represents the framework itself.

Now, we're going to write our own bundle. In the same directory as before, create a file called
HelloActivator.java and copy the following code into it :

import org.osgi.framework.*;

public class HelloActivator implements BundleActivator {


public void start(BundleContext context) {
System.out.println("Hello EclipseZone Readers!");
}

public void stop(BundleContext context) {


System.out.println("Goodbye EclipseZone Readers!");
}
}
A bundle also needs a manifest file that declares various metadata about the bundle, e.g. its name,
version, etc. So create a file called HelloWorld.mf and copy the following text into it. Make very
sure that this file ends with a blank line, otherwise the jar command line tool will truncate the file.

Manifest-Version: 1.0
Bundle-Name: HelloWorld
Bundle-Activator: HelloActivator
Bundle-SymbolicName: HelloWorld
Bundle-Version: 1.0.0
Import-Package: org.osgi.framework

Now open a new Command Prompt (because we want to leave OSGi running) and build the Jar with
the following commands :

> javac -classpath equinox.jar HelloActivator.java


> jar -cfm HelloWorld.jar HelloWorld.mf HelloActivator.class

Going back into the OSGi console, type install file:HelloWorld.jar . The reply should be
"Bundle id is 1" . Type ss again and you will see the following :

Framework is launched.

Id State Bundle
0 ACTIVE system.bundle_3.2.1.R32x_v20060919
1 INSTALLED HelloWorld_1.0.0

Our HelloWorld bundle is installed... but it's not yet active. We'll look into what these states mean
in a later post, but for now we just need to start the bundle by typing start 1 . The "1" is the ID
of the bundle from the first column. When you do this you should see the message "Hello
EclipseZone Readers!". Now type stop 1 and you will see "Goodbye EclipseZone Readers!".
Repeat this until you get bored. Don't forget to do ss occasionally to see the state of the bundle
changing.

What's happening here? Our code implements the BundleActivator interface, allowing the
framework to notify us of important lifecycle events. When the bundle is started, the framework
calls the start method, and when the bundle is stopped, the framework calls the stop method.
The other thing going on here is the line in the manifest file "Bundle-Activator:
HelloActivator" , which tells the framework which class in our bundle is the activator.
Normally the name we give is a fully-qualified class name, but we were lazy and used the default
package.

And that concludes our first installment.


Part 2 : Interacting with the
Framework
Last time we looked at a simple Hello World bundle that printed a message when starting and
stopping. It did that by implementing the BundleActivator interface and providing start and
stop methods. Take another look at the code now, in particular the method signature of start
and stop , and you'll notice that we were passed a parameter, the BundleContext . In this
installment of the tutorial we will be looking at BundleContext and what we can do with it.

BundleContext is a magic ticket that the OSGi framework passes to our bundle. When code
needs to interact with the framework in any way, you will use the BundleContext . In fact this is
the only way to interact with the OSGi API, and the framework issues one of these tickets to each
bundle through its BundleActivator when the bundle is started.

If you still have Equinox running from last time then you don't need to restart it. If it's not running,
then remember the command to start it is

> java -jar equinox.jar -console

Type ss at the prompt and you should see that the Hello World bundle from last time is still
installed. That's the case even if you have shut down and restarted Equinox since then, because the
OSGi framework persists its state between runs.

For this exercise we will write a bundle that searches out and uninstalls Hello World. We could do
this easily from the console using the uninstall command, but we want to see how it can be
done programmatically using the OSGi API. So, create a new file called
HelloWorldKiller.java and copy in the following code :

import org.osgi.framework.*;

public class HelloWorldKiller implements BundleActivator


{
public void start(BundleContext context)
{
System.out.println("HelloWorldKiller searching...");
Bundle[] bundles = context.getBundles();
for(int i=0; i<bundles.length; i++)
{
if("HelloWorld".equals(bundles[i].getSymbolicName()))
{
try
{
System.out.println("Hello World found, " + "destroying!");
bundles[i].uninstall();
return;
} catch (BundleException e) {
System.err.println("Failed: " + e.getMessage());
}
}
}
System.out.println("Hello World bundle not found");
}
public void stop(BundleContext context)
{
System.out.println("HelloWorldKiller shutting down");
}
}

Now create the manifest. Again, remember the blank line at the end is very important. Copy the
following into HelloWorldKiller.mf :

Manifest-Version: 1.0
Bundle-Name: HelloWorldKiller
Bundle-Activator: HelloWorldKiller
Bundle-SymbolicName: HelloWorldKiller
Bundle-Version: 1.0.0
Import-Package: org.osgi.framework

Now compile and build the Jar :

> javac -classpath equinox.jar HelloWorldKiller.java


> jar -cfm HelloWorldKiller.jar HelloWorldKiller.mf HelloWorldKiller.class

Back at the OSGi console, install the new bundle using

install file:HelloWorldKiller.jar

and then type ss . The status listing should now look like this :

id State Bundle
0 ACTIVE system.bundle_3.2.1.R32x_v20060919
1 ACTIVE HelloWorld_1.0.0
2 INSTALLED HelloWorldKiller_1.0.0

Let's run the Hello World Killer by typing start 2 . You should see the following output :

HelloWorldKiller searching...
Hello World found, destroying!
Goodbye EclipseZone Readers!

Notice that the last line of output comes from our original Hello World bundle. Because it was in
the active state before we ran the Killer, it had to be stopped before being uninstalled, and that
caused the stop method of its BundleActivator to run.

Taking another look at the output of ss , Hello World has disappeared :

id State Bundle
0 ACTIVEsystem.bundle_3.2.1.R32x_v20060919
2 ACTIVEHelloWorldKiller_1.0.0

You might wonder if there is a security problem here. It appears that any bundle can uninstall any
other bundle! Fortunately OSGi has a comprehensive security layer which gives fine-grained control
over all interaction with the framework, so for example you could limit the right to uninstall bundles
to a particular "management" bundle. However, getting security working is mostly a configuration
issue, and in this series we're going to focus on the code.
That's it for this installment. Until next time, why not take a look at the BundleContext interface
and see what else you can do with it ? For example, you could try programmatically installing a new
bundle using the installBundle method. Or you could get a list of all the currently installed
bundles and print out the time and date they were last modified. To help you get started, check out
the Javadocs for the OSGi Release 4 APIs .
Part 3 : Dependencies between
Bundles
In our previous tutorial installments, we looked at how bundles can be started and stopped, and
how they can interact with the framework and each other's lifecycle. But what are bundles really
for ?

Bundles are modules. They allow us to split apart our monolithic projects into manageable pieces
which can be loaded individually into an OSGi runtime. The problem is, whether we like it or not,
modules nearly always have dependencies on other modules. In plain old Jar files, there was never a
reliable way to specify the dependencies on other Jars (no, the Class-Path entry in the manifest
was not a reliable way of doing this). Therefore you never really knew for sure if the code in a Jar
would work, or would throw ClassNotFoundException s at runtime.

OSGi fixed this problem very elegantly. But it's better to show you than tell you... so let's hurry up
and get to the code. Unfortunately up until now we have been using the default package, but this
won't work any more; we will need to start working with proper packages. So lets start off with a very
simple JavaBean-style class, which you should copy into the file osgitut/movies/Movie.java
:

package osgitut.movies;

public class Movie


{
private final String title;
private final String director;

public Movie(String title, String director)


{
this.title = title;
this.director = director;
}

public String getTitle()


{
return title;
}

public String getDirector()


{
return director;
}
}

Now we will create an interface in the same package. Create the file
osgitut/movies/MovieFinder.java and copy in :

package osgitut.movies;

public interface MovieFinder {


Movie[] findAll();
}
Now lets get these two classes into a bundle. Yes, our bundle will be ridiculously small and almost
useless, but that's okay for now. As before we need to create a manifest file, so open up
MoviesInterface.mf and copy in the following :

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Movies Interface
Bundle-SymbolicName: MoviesInterface
Bundle-Version: 1.0.0
Export-Package: osgitut.movies;version="1.0.0"

There's a new line in here that we haven't seen before: Export-Package . This simply says that
the package osgitut.movies is exported from the bundle. This may seem a little odd at first,
because in plain old Java Jars, everything is exported. But haven't you ever wanted to put some
code in a package which was only visible internally withing your Jar? Sure, you can make some
classes private or protected, but then they're not visible to other packages within your Jar. So OSGi
effectively has introduced a new code protection level: if a package in your bundle is not listed on
the Export-Package header, then it is only accessible within your module.

You'll also notice that we attached a version number to the package. This is important as we will see
later. It's not absolutely necessary to supply a version, by the way, but if you don't then OSGi will
automatically assign the version "0.0.0" to your package. I think it's good practice to always add a
version explicitly.

Now let's build this bundle:

> javac osgitut/movies/Movie.java osgitut/movies/MovieFinder.java


> jar -cfm MoviesInterface.jar MoviesInterface.mf osgitut/movies/*.class

We're not going to go right ahead and install that bundle into the runtime. First we're going to build
another bundle that depends on it. We want to create a concrete implementation of the MovieFinder
interface, so copy the following into osgitut/movies/impl/BasicMovieFinderImpl.java :

package osgitut.movies.impl;

import osgitut.movies.*;

public class BasicMovieFinderImpl implements MovieFinder {


private static final Movie[] MOVIES = new Movie[] {
new Movie("The Godfather", "Francis Ford Coppola"),
new Movie("Spirited Away", "Hayao Miyazaki")
};

public Movie[] findAll() { return MOVIES; }


}

Now we need a manifest file, so create BasicMovieFinder.mf :

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Basic Movie Finder
Bundle-SymbolicName: BasicMovieFinder
Bundle-Version: 1.0.0
Import-Package: osgitut.movies;version="[1.0.0,2.0.0)"

Notice that we are importing the package osgitut.movies which was exported by the other
bundle. We have also this time added a version range on the import. The framework uses the range
at runtime to match up the import with an appropriate export. OSGi uses a syntax for version ranges
that will be familiar to most mathematicians : the square bracket means "inclusive" and the round
bracket means "exclusive". Effectively we have specified the version "1.x".

Again, adding the version constraint on the import wasn't particularly necessary in this case, it's just
a good habit to adopt.

Now lets compile and build our second bundle of the day as follows:

> javac -classpath MoviesInterface.jar osgitut/movies/impl/BasicMovieFinderImpl.java


> jar -cfm BasicMovieFinder.jar BasicMovieFinder.mf osgitut/movies/impl/*.class

Finally we're ready to try these bundles out in Equinox. I'm not going to give full instructions this
time, as I think you should be getting the hang of it. Firstly install the BasicMovieFinder
bundle, and run ss . You will find that the bundle is in INSTALLED state :

id State Bundle
0 ACTIVE org.eclipse.osgi_3.3.0.v20070208
4INSTALLED BasicMovieFinder_1.0.0

(NB your bundle list may be starting to look a little different from mine, in particular the bundle ID
will depend on how many times you installed and uninstalled the HelloWorld bundle from last time.
You'll have to mentally translate the bundle IDs that follow).

INSTALLED just means that framework has got the bundle, but has not yet resolved its
dependencies. One way to try to force Equinox to resolve our bundle is with the refresh
command. So type refresh 4 and then ss and you should see this :

id State Bundle
0 ACTIVE org.eclipse.osgi_3.3.0.v20070208
4 INSTALLED BasicMovieFinder_1.0.0

The bundle still isn't resolved! Of course, we need to install the "interface" bundle which contains
the Movie class and the MovieFinder interface. To confirm that this is the problem, type diag
4 to get diagnostic information :

file:BasicMovieFinder.jar [4]
Missing imported package osgitut.movies_[1.0.0,2.0.0).

Yes, that was the problem: we can't import the package osgitut.movies because no bundle is
currently exporting it. So now install the MoviesInterface.jar bundle and run ss . The listing
will look like this :

id State Bundle
0 ACTIVE org.eclipse.osgi_3.3.0.v20070208
4 INSTALLED BasicMovieFinder_1.0.0
5 INSTALLED MoviesInterface_1.0.0

The final step is to ask Equinox to try again to resolve the BasicMovieFinder bundle, by running
refresh 4 . The output from ss will now show :

id State Bundle
0 ACTIVE org.eclipse.osgi_3.3.0.v20070208
4 RESOLVED BasicMovieFinder_1.0.0
5 RESOLVED MoviesInterface_1.0.0

The BasicMovieFinder bundle is now RESOLVED ! This is an essential step, because until the
bundle is RESOLVED it cannot be started, and it cannot supply dependencies to any other bundle.

Note that usually it's not necessary to do manual resolution like this. Normally bundles are
automatically resolved when they are needed -- for example, notice that the MoviesInterface
bundle is now RESOLVED even though we didn't explicitly refresh it.

That's it for now. For more fun things you can do with the Equinox console, take a look at Chris
Aniszczyk's excellent article on IBM developerWorks . Stay tuned for the next installment, where we
start to delve into OSGi services.
Part 4 : Registering a Service
Finally, we're ready to get on to services. In my opinion, the service layer is the most exciting part of
OSGi, so these next few installments should be fun.

Last time we looked at the example of a MovieFinder interface, which we said would be used by
a MovieLister to search for movies. In fact you may recognize this example -- it is from Martin
Fowler's famous paper on "Dependency Injection", also known as "Inversion of Control" or IoC.

Recall the problem that IoC tries to solve. A MovieLister doesn't particularly care where the raw
movie data comes from, so we use the MovieFinder interface to hide such details from it. The
idea is we can then substitute alternative implementations of MovieFinder , such as one that
goes to a database or even one that calls an Amazon Web Service, since MovieLister only
depends on the interface, not any particular implementation.

So far so good, but at some point we have to actually give a concrete implementation of
MovieFinder to MovieLister . We do this by having an external container "push" a suitable
object into it, rather than letting MovieLister go out and call a lookup method. Hence the term
"Inversion of Control". Many such containers have been developed, for example PicoContainer,
HiveMind, Spring, and even EJB 3.0. However there is one limiting factor of all these containers to
date: they are mostly static. Once a MovieFinder is given to a MovieLister , it tends to be
associated for the lifetime of the JVM.

OSGi also allows us to implement the IoC pattern, but in a dynamic way. It should be possible to
dynamically supply implementations of MovieFinder to MovieLister and later remove them.
Then we can hot-swap from an application that looks up movies in a flat text file to an application
that looks them up with Amazon Web Services.

It is the Service Layer that helps us do this. Quite simply, we register a MovieFinder as a Service
in the Service Registry. Later the MovieLister can be supplied with that MovieFinder
Service. A Service therefore is nothing more than a Java object -- a POJO, if you will -- and it is
registered under the name of a Java interface (a POJI?).

This time around, we will just look at registering the service with the registry. Later we will look at
how to get the service out of the registry and supplied to a MovieLister .

We're going to add the BasicMovieFinder bundle that we built last time. We don't need to
modify any existing classes, we just need to add a bundle activator. So copy this into
osgitut/movies/impl/BasicMovieFinderActivator.java :

package osgitut.movies.impl;

import org.osgi.framework.*;

import osgitut.movies.*;
import java.util.Properties;
import java.util.Dictionary;

public class BasicMovieFinderActivator implements BundleActivator


{
private ServiceRegistration registration;
public void start(BundleContext context)
{
MovieFinder finder = new BasicMovieFinderImpl();

Dictionary props = new Properties();


props.put("category", "misc");

registration =
context.registerService(MovieFinder.class.getName(), finder, props);
}

public void stop(BundleContext context)


{
registration.unregister();
}
}

Now replace the content of BasicMovieFinder.mf :

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Basic Movie Finder
Bundle-SymbolicName: BasicMovieFinder
Bundle-Version: 1.0.0
Bundle-Activator: osgitut.movies.impl.BasicMovieFinderActivator
Import-Package: org.osgi.framework,
osgitut.movies;version="[1.0.0,2.0.0)"

There are two things added to this manifest since last time. First is the Bundle-Activator line,
which tells the framework about the new activator for our bundle -- we didn't need one last time.
Also I have added org.osgi.framework to the imported packages. As our previous version of
the bundle didn't interact with the framework, it didn't need to import the OSGi API packages.

Now you can rebuild BasicMovieFinder.jar :

> javac -classpath equinox.jar:MoviesInterface.jar osgitut/movies/impl/*.java


> jar cfm BasicMovieFinder.jar BasicMovieFinder.mf osgitut/movies/impl/*.class

Back in the OSGi console, you should still have BasicMovieFinder.jar installed from last
time. So you just need to tell OSGi to update the bundle, by typing update N , where N is the
numeric ID of the bundle (which you have found using ss ). Now start the bundle with the
command start N and you should see... very little happen.

Actually we've just registered our first service with the OSGi service registry, but unfortunately
there's nobody on the "other end", so the registration doesn't produce any visible effect. If we want
to reassure ourselves that our code has actually done something, we're going to have to go digging,
and we do that with the following command :

services (objectClass=*MovieFinder)

We should see the following output :

{osgitut.movies.MovieFinder}={category=misc, service.id=22}
Registered by bundle: file:BasicMovieFinder.jar [4]
No bundles using service.

Great, our service is registered! And I'd love to go on and tell you how to lookup that service and use
it in another bundle, but that will have to wait until another day. In the meantime, see what you can
do with the services command. For starters try typing services without the expression in
parentheses afterwards -- that was actually a filter which reduced the number of services displayed
to just the one we were interested in. Without the filter you will see all of the registered services.
There are a surprisingly large number of them !
Part 5 : Consuming a Service
In our last part we looked at how to register a service. Now we need to work out how to lookup and
use that service from another bundle.

We will put the problem in the context of our requirements, which as before are inspired by Martin
Fowler's paper on dependency injection. We have built a MovieFinder as a service and registered
it with the service registry. Now we want to build a MovieLister that uses the MovieFinder to
search for movies directed by a specific director. Our assumption is that the MovieLister itself
will be a service to be consumed by some other bundle, e.g. a GUI application. The trouble is, OSGi
services are dynamic... they come and they go. That means sometimes we want to call the
MovieFinder service but it just isn't available !

So, what should the MovieLister do if the MovieFinder service is not present? Clearly the
call to the MovieFinder is a critical part of the work done by MovieLister , so there only a
few choices available to us :

1. Produce an error, e.g. return null or throw an exception.


2. Wait.
3. Don't be there in the first place.

In this article we're going to look at the first two options, as they are quite simple. The third option
may not even make any sense to you yet, but hopefully it will after we look at some of the
implications of the first two.

The first thing we need to do is define the interface for the MovieLister service. Copy the
following into osgitut/movies/MovieLister.java :

package osgitut.movies;

import java.util.List;

public interface MovieLister {


List listByDirector(String name);
}

Now create the file osgitut/movies/impl/MovieListerImpl.java :

package osgitut.movies.impl;

import java.util.*;
import osgitut.movies.*;
import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;

public class MovieListerImpl implements MovieLister {


private final ServiceTracker finderTrack;

public MovieListerImpl(ServiceTracker finderTrack) {


this.finderTrack = finderTrack;
}

public List listByDirector(String name) {


MovieFinder finder = (MovieFinder) finderTrack.getService();
if(finder == null) {
return null;
} else {
return doSearch(name, finder);
}
}

private List doSearch(String name, MovieFinder finder) {


Movie[] movies = finder.findAll();
List result = new LinkedList();
for (int i = 0; i < movies.length; i++) {
if(movies[i].getDirector().indexOf(name) > -1) {
result.add(movies[i]);
}
}

return result;
}
}

This is probably our longest code sample so far! So what's going on here? Firstly you notice that the
logic of actually searching for movies is separated into a doSearch(String,MovieFinder)
method, to help us isolate the OSGi-specific code. Incidentally, the way we're performing the search
is pretty stupid and inefficient, but that's not really important for the purposes of the tutorial. We
only have two movies in our database anyway !

The interesting part is in the listByDirector(String name) method, which uses a


ServiceTracker object to obtain a MovieFinder from the service registry. ServiceTracker
is a very useful class which abstracts away a lot of unpleasant detail in the lowest levels of the OSGi
API. However we still have to check whether the service was actually present. We assume that the
ServiceTracker will be passed to us in our constructor.

Note that you may have seen elsewhere code that retrieves a service from the registry without using
ServiceTracker . For example, it is possible to use the getServiceReference and
getService calls on BundleContext . However the code you have to write is quite complex
and it has to be careful to clear up after itself. In my opinion, there is very little benefit in dropping
down to the low level API, and lots of problems with it. It's better to use ServiceTracker almost
exclusively.

A good place to create a ServiceTracker is in the bundle activator. Copy this code into
osgitut/movies/impl/MovieListerActivator.java :

package osgitut.movies.impl;

import java.util.*;
import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;
import osgitut.movies.*;

public class MovieListerActivator implements BundleActivator


{
private ServiceTracker finderTracker;
private ServiceRegistration listerReg;

public void start(BundleContext context) throws Exception


{
// Create and open the MovieFinder ServiceTracker
finderTracker = new ServiceTracker(context,
MovieFinder.class.getName(), null);
finderTracker.open();

// Create the MovieLister and register as a service


MovieLister lister = new MovieListerImpl(finderTracker);
listerReg = context.registerService(MovieLister.class.getName(),
lister, null);

// Execute the sample search


doSampleSearch(lister);
}

public void stop(BundleContext context) throws Exception {


// Unregister the MovieLister service
listerReg.unregister();

// Close the MovieFinder ServiceTracker


finderTracker.close();
}

private void doSampleSearch(MovieLister lister)


{
List movies = lister.listByDirector("Miyazaki");
if(movies == null)
{
System.err.println("Could not retrieve movie list");
} else {
for (Iterator it = movies.iterator(); it.hasNext();)
{
Movie movie = (Movie) it.next();
System.out.println("Title: " + movie.getTitle());
}
}
}
}

Now this activator is starting to look interesting. Firstly in the start method it creates a
ServiceTracker object, which is used by the MovieLister we just wrote. It then "opens" the
ServiceTracker which tells it to start tracking instances of the MovieFinder service in the
registry. Then it creates our MovieListerImpl object and registers it in the service registry under
the interface name "MovieLister" . Finally, just for the sake of being able to see something
interesting when we start the bundle, the activator runs a simple search against the MovieLister
and prints the result.

We need to build and install this bundle. I'm not going to give full instructions this time -- you
should be able to refer back to the previous installments and work it out. Remember you also need
to create a manifest file, and it has to refer to the
osgitut.movies.impl.MovieListerActivator class as its Bundle-Activator . Also
your Import-Package line needs to include the three packages that we're importing from other
bundles, namely org.osgi.framework , org.osgi.util.tracker and osgitut.movies
.
Once you have installed MovieLister.jar into the Equinox runtime, you can start it. At that
point you will see one of two messages, depending on whether the BasicMovieFinder bundle is
still running from last time. If it's not running you will see :

osgi> start 2
Could not retrieve movie list

However if it is running you will see following :

osgi> start 2
Title: Spirited Away

By stopping and starting each bundle, you should be able to get either message to appear at will.
And that is almost all for this installment, except remember I said that one of the things you can do
when a service is not available is to wait for it? With the code we already have, this is actually
trivial: simply change line 16 of MovieListerImpl to call waitForService(5000) on the
ServiceTracker instead of getService() , and add a try/catch block for the
InterruptedException .

This will cause the listByDirector() method to hang for up to 5000 milliseconds waiting for
the MovieFinder service to appear. If a MovieFinder service is installed in that time -- or, of
course, if it was already there -- then we will immediately get it an be able to use it.

Generally though I would advise against suspending threads like this. Particularly in this case, it
could be dangerous because the listByDirector() method is actually called from the start
method of our bundle activator, which was called from a framework thread. Activators are meant to
return quickly, because a number of other things need to happen when a bundle is activated. In fact
in the worst case we could cause a deadlock, because we are effectively entering a synchronized
block on an object owned by the framework, which might already by locked by something else. The
general guideline is never perform any long-running or blocking operations in a bundle activator
start method, or in any code called directly from the framework.

In the next installment we will take a look at the mysterious third option for dealing with absent
dependencies: "Don't exist in the first place". Stay tuned !
Part 6 : Dynamic Service
Tracking
Last time we looked at how to consume a service, using a scenario inspired by Martin Fowler: a
MovieLister depends on a MovieFinder to search for movies directed by a specified director.
We looked also at strategies for dealing with the dynamic nature of OSGi services, in particular what
MovieLister should do if it cannot find an instance of MovieFinder .

There is another possibility that we didn't consider last time: what if there is more than one
MovieFinder available? After all, any bundle can register a service under the MovieFinder
interface, and all bundles are equal in the eyes of the registry.

We could simply ignore the problem, and in fact that's what our code last time did. By calling the
getService() method on a ServiceTracker , we receive an arbitrary single instance of
MovieFinder chosen by the service registry. There are various ways to influence the decision (for
example a SERVICE_RANKING property that can be specified with the service registration), but as
a consumer we will never have full control over this decision. And in fact it's a good thing not to
have too much control -- after all, we really should be able to use any instance of MovieFinder .
This is somewhat the point of using interfaces in the first place.

Alternatively, it might be useful sometimes to be aware of and use multiple service instances. For
example, if there are multiple MovieFinder services available, it probably means that there are
multiple sources of movie data that the MovieLister could take advantage of. By using all of
them when performing a movie search, we are able to cast the net wider and produce better search
results for the user.

Another change we would like to make goes back to the problem discussed from last time: what is
the correct thing to do when there is no MovieFinder service available at all? We took the simple
route of returning null whenever the listByDirector method was called, and the
MovieFinder was unavailable. But what if we made it impossible for methods on MovieLister
to be called when the MovieFinder isn't present ?

MovieLister is a service, just like MovieFinder . If the MovieFinder service disappears,


how about making MovieLister disappear as well? In other words, we want the MovieLister
service to have a one-to-many dependency on MovieFinder . In the last part of the tutorial, we
had a zero-to-one dependency.

Let's make some changes to the MovieListerImpl class. Replace it with the following :

package osgitut.movies.impl;

import java.util.*;
import osgitut.movies.*;

public class MovieListerImpl implements MovieLister {

private Collection finders = Collections.synchronizedCollection(new


ArrayList());

protected void bindFinder(MovieFinder finder) {


finders.add(finder);
System.out.println("MovieLister: added a finder");
}

protected void unbindFinder(MovieFinder finder) {


finders.remove(finder);
System.out.println("MovieLister: removed a finder");
}

public List listByDirector(String director) {


MovieFinder[] finderArray = (MovieFinder[]) finders.toArray(new
MovieFinder[finders.size()]);
List result = new LinkedList();
for(int j=0; j<finderArray.length; j++) {
Movie[] all = finderArray[j].findAll();
for(int i=0; i<all.length; i++) {
if(director.equals(all[i].getDirector())) {
result.add(all[i]);
}
}
}
return result;
}
}

We've actually removed all OSGi dependencies from MovieListerImpl -- it is now a pure POJO.
However it requires somebody or something to track the MovieFinder services and supply them
to it through the bindFinder method, so to do this we create a new file called
osgitut/movies/impl/MovieFinderTracker.java as follows :

package osgitut.movies.impl;

import org.osgi.framework.*;
import org.osgi.util.tracker.*;

import osgitut.movies.*;

public class MovieFinderTracker extends ServiceTracker {

private final MovieListerImpl lister = new MovieListerImpl();


private int finderCount = 0;
private ServiceRegistration registration = null;

public MovieFinderTracker(BundleContext context) {


super(context, MovieFinder.class.getName(), null);
}

private boolean registering = false;

public Object addingService(ServiceReference reference) {


MovieFinder finder = (MovieFinder) context.getService(reference);
lister.bindFinder(finder);

synchronized(this) {
finderCount ++;
if (registering)
return finder;
registering = (finderCount == 1);
if (!registering)
return finder;
}

ServiceRegistration reg = context.registerService(


MovieLister.class.getName(), lister, null);

synchronized(this) {
registering = false;
registration = reg;
}

return finder;
}

public void removedService(ServiceReference reference, Object service) {


MovieFinder finder = (MovieFinder) service;
lister.unbindFinder(finder);
context.ungetService(reference);

ServiceRegistration needsUnregistration = null;


synchronized(this) {
finderCount--;
if (finderCount == 0) {
needsUnregistration = registration;
registration = null;
}
}

if(needsUnregistration != null) {
needsUnregistration.unregister();
}
}
}

This class overrides the ServiceTracker class that we talked about last time, and customizes
the way the ServiceTracker behaves when services come and go. Specifically, the
addingService method is called when a MovieFinder service is added, and the
removedService is called when a MovieFinder is removed. There is also a
modifiedService method that we could override, but we don't need it here.

It's worth taking a close look at the code in these two methods. First, in addingService we see
that the parameter passed to us is a ServiceReference rather than the actual service
implementation object. ServiceReference is a lightweight handle that can be passed freely
around as a parameter, and it can be used to obtain the properties of the service, i.e. those that
were supplied along with the service registration. Crucially, obtaining a ServiceReference
object does not cause the OSGi framework to increment the usage count for the target service. You
could therefore think of this as similar to the WeakReference class in the Java Reflection APIs.

The first thing we do with the ServiceReference in our example is to obtain the real
MovieFinder service object from it. To do this we need the BundleContext again -- remember,
all interaction with the OSGi framework is done through the BundleContext interface. Handily
our superclass ServiceTracker keeps the BundleContext reference in a protected member
field called context that we can use directly.
Next we bind the finder into our MovieListerImpl using the bindFinder method we defined
above, and then we register the MovieListerImpl as a service itself, under the MovieLister
interface. Note that we are careful only to register the service if it was not already registered,
because in this scenario we want to have a single MovieLister that tracks multiple
MovieFinder services.

Finally, we return from the method. There's another interesting point here -- the return type of
addingService is simply Object, so what should we return? In fact, the ServiceTracker
doesn't care, we can return whatever we like. However, the object we return from addingService
will be given back to us when modifiedService and/or removedService are called. So if you
look at the first line of our removedService method, you see that we immediately cast the
Object to a MovieFinder so that it can be unbound from the lister. Then we unregister the
MovieLister service if the number of tracked finders has dropped to zero.

Generally, whatever we do in addingService has to be undone in the removedService


method. Therefore we should return from the addingService method whatever will help us find
whatever it was we did. This could be a key in a HashMap , or it could be a
ServiceRegistration object, or (as in this case) it could be the actual service object.

As a final step in removedService , we have to "unget" the service that we previous "got". This is
very important because it causes the service registry to decrement the service usage counter, which
allows the service to be freed when the counter drops to zero.

Now we need an activator, osgitut/movies/impl/TrackingMovieListerActivator.java


:
package osgitut.movies.impl;

import org.osgi.framework.*;

public class TrackingMovieListerActivator implements BundleActivator {

private MovieFinderTracker tracker;

public void start(BundleContext context) {


tracker = new MovieFinderTracker(context);
tracker.open();
}

public void stop(BundleContext context) {


tracker.close();
}
}

And a manifest, TrackingMovieLister.mf :

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Tracking Movie Lister
Bundle-SymbolicName: TrackingMovieLister
Bundle-Version: 1.0.0
Bundle-Activator: osgitut.movies.impl.TrackingMovieListerActivator
Import-Package: org.osgi.framework,
org.osgi.util.tracker,
osgitut.movies;version="[1.0.0,2.0.0)"
And I will leave it to you as an exercise to build and deploy this bundle to Equinox. Once this is
done, try the following sequence of steps to see that everything is working :

1. Start the BasicMovieFinder and start the TrackingMovieLister. Check that the message
"MovieLister: added a finder" appears.
2. Type the services command and check that there is a MovieLister service registered.
3. Stop the BasicMovieFinder and check that the message "MovieLister: removed a finder"
appears.
4. Type the services command again and check that there is no MovieLister service
registered.

What we have done here has sown the seeds of a very powerful technique. We have tied the lifecycle
of one service to the lifecycle of another service -- in fact, multiple other services. Taking this
technique further, we could have another service that is tied to the MovieLister , and yet
another service that depends on that one, and so on. We end up constructing a graph of
interdependent services, but unlike the graphs of beans constructed by some static IOC containers,
our graph is robust, self-healing, and able to adjust to a changing world.

On the other hand, there are some problems with the code we've written. The
MovieFinderTracker and TrackingMovieListerActivator classes are really just a load
of boilerplate, and if we do start expanding this system then we're going to get pretty tired of writing
the same code over and over, with just slight modifications each time. Therefore in the next
installment we will look at a way for all of that code to be replaced by just a couple of lines of XML !

Also in the next installment we will stop building everything with command line tools in a single
directory. My aim when starting this tutorial was to show that OSGi is a simple yet powerful
framework, and that you don't need a powerful, heavyweight IDE like Eclipse to develop OSGi
bundles. When something appears to be "too easy" there is always the suspicion that the IDE has
performed some black magic on our behalf. I hope I have shown that that is not the case, OSGi
does not require black magic. On the other hand, if the directory where you have been putting this
code looks anything like mine, you're starting to yearn for a proper development environment. So am
I. This isn't a problem with OSGi, of course -- any Java project would rapidly get out of control like
this if using just the standard tools.
Part 7 : Introducing Declarative
Services
Welcome to the next installment of the "Getting Started with OSGi" series. This installment is quite
exciting, because we're going to start experimenting with Declarative Services.

The Declarative Services (or "DS") specification is one of the newest parts of OSGi, and it came
about as a result of some of the issues with wiring together service across bundles. It's not that this
task is difficult – as I hope my previous tutorials showed – but it does require a fair amount of
boilerplate code. It also requires you to be cautious about threading issues, which means you can
easily shoot yourself in the foot.

An early attempt to resolve this problem was a tool called Service Binder, developed by Humberto
Cervantes and Richard Hall . Service Binder introduced automated service dependency
management , allowing developers to focus on the job of writing their services. The wiring between
services was handled declaratively, and the declarations were made in XML.

The Declarative Services specification evolved from Service Binder, and it is now a standard part of
OSGi versions 4.0 and above. So, lets see what it can do for us.

As I mentioned in the previous installment of the tutorial, I'm tired of doing everything on the
command line: from this point onwards, we will use the Eclipse SDK. Please remember though that
none of what I'm introducing really depends on Eclipse. Although Eclipse helps a lot with what
we're about to do, there's no black magic going on, so anything you see here is perfectly possible in
NetBeans, IntelliJ or even good old vi.

The first thing we need to do is download the Equinox implementation of Declarative Services.
Assuming you're using the current stable version of Eclipse, which is 3.2.2 at time of writing, the
direct link is here . If you're using a different version, you need to find that version from the top-
level Equinox download page here and get the file
org.eclipse.equinox.ds_x.x.x_xxxxx.jar . Once it's downloaded, drop it into the
plugins directory of your Eclipse installation, and restart Eclipse. Actually if you know a little
about Eclipse plug-in development already, you should put this JAR into your Target Platform folder.
If you don't know what a "Target Platform" is, then don't worry about it, just drop the JAR into the
plugins folder.

Now we'll create a new bundle. To do this, we create a project in Eclipse using the Plug-in Project
wizard :

1. From the main menu, select File -> New -> Project.
2. Select Plug-in Project and hit Next.
3. Enter the name of the project, SampleExporter .
4. At the bottom, below the text "This plug-in is targeted to run with", select "an OSGi
framework" and then select "standard" from the drop-down. This step isn't absolutely
essential, it just prevents us from accidentally using features that are not available out-of-
the-box on other OSGi framework implementations.
5. Click Next. On the following page of the wizard, deselect "Generate an activator...", if it is
checked. Then click Finish.

We now have an empty bundle project, so we need to add some code. To keep things as simple as
possible, we're going to offer a service using an interface that's already available on every Java
runtime: java.lang.Runnable . Using a handy little Eclipse shortcut, just copy the following
code from your browser, and then select the src folder inside the SampleExporter project and
hit Edit -> Paste. Eclipse will create the package and source file for you.

package org.example.ds;

public class SampleRunnable implements Runnable {

public void run() {


System.out.println("Hello from SampleRunnable");
}
}

So far we haven't seen anything new, but here's where it gets interesting: we're going to create an
XML file to declare SampleRunnable as a service. Create a folder at the top level of the project
called OSGI-INF and copy the following into a file in that folder called samplerunnable.xml :

<?xml version="1.0"?>
<component name="samplerunnable">
<implementation class="org.example.ds.SampleRunnable"/>
<service>
<provide interface="java.lang.Runnable"/>
</service>
</component>

This is one of the simpler declarations we will see with DS. It says that there is a component called
"samplerunnable" which provides a service to the OSGI Service Registry under the interface
java.lang.Runnable , and the component is implemented by the class
org.example.ds.SampleRunnable .

The final step is to tell the Declarative Services runtime about the existence of this XML file. We do
this by adding a field to the MANIFEST.MF for the bundle. So, open the manifest (try right-clicking
on the project and selecting PDE Tools -> Open Manifest) and in the editor, skip to the tab labeled
"MANIFEST.MF", as this allows us to edit the text contents of the manifest directly. Add the
following line:

Service-Component: OSGI-INF/samplerunnable.xml

Then save the file. As in previous installments, the blank line at the end of the manifest is VERY
important, but unlike previously, you will now get an error message from Eclipse if you forget.

Before going any further, lets run Equinox to check that this works. Go to the Run menu and select
"Run...". When the dialog opens, select "Equinox OSGi Framework" in the tree on the left, and then
hit the New button. If you're an experienced Eclipse user but have not done OSGi development, this
launcher dialog might look a little bit strange. The first tab, labeled Bundles, allows us to choose
which bundles should be included in the launch configuration, and whether they should be initially
started or not. To get the minimal set, click Deselect All and then place a tick next to the following
bundles only :

• SampleExporter (underneath Workspace)


• org.eclipse.equinox.ds (underneath Target Platform)

These are the bundles we are interested in, but they do have dependencies, so click Add Required
Bundles to add those dependencies back in. Also it's a good idea to select "Validate bundles
automatically prior to launching". Finally, click Run, and in a few moments the osgi> prompt
should appear in the Eclipse console. The OSGi framework is running, and you can interact with it
using the same commands you learned previously.

So is our service registered? We can check by typing the command services . Somewhere in the
list of services – probably the bottom – you should see the following :

{java.lang.Runnable}={component.name=samplerunnable, component.id=1,
service.id=22}
Registered by bundle: initial@reference:file:..../SampleExporter/ [5]
No bundles using service.

Yes, it's registered! And notice one important thing: it appears to have been registered by our
bundle, not by the Declarative Services bundle. In fact DS has registered it on behalf of our bundle.
We'll look at how it does that a little later on, but for the purposes of this lesson, it's enough to note
that consumers of our service don't need to do anything special, in fact they need not even know
that we are using Declarative Services. Those consumers can use Declarative Services as well if they
wish to, but they can also use straightforward OSGi code.

Another thing to note is that in our bundle, there is no OSGi-specific Java code. In other words, the
class we wrote is a POJO, and this is a major feature of Declarative Services.

That's enough for this installment, and I'm sorry that this lesson is a little basic. Next time we'll
look at how to consume services in various ways with DS, which should really start to show the
power and convenience that it offers.
Part 8 : Declarative Services and
Dependencies
Last time we took our first look at Declarative Services. This time we will look at the service
consumer side of Declarative Services. Remember that previously we registered a service under the
java.lang.Runnable interface; now we will create a component that depends on that service.

As discussed, the Declarative Services specification is all about letting you focus on the application
logic of your code, rather than the OSGi "glue" code that had to be written in previous lessons. With
that in mind, we're simply going to dive into the code, but before we do that we need to create a
project. Follow the same steps as in the last lesson, but use the project name "SampleImporter".

Now copy the following code from your browser and paste it into the src folder inside the newly
created Eclipse project :

package org.example.ds;

import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;

public class SampleCommandProvider1 implements CommandProvider {

private Runnable runnable;

public synchronized void setRunnable(Runnable r) {


runnable = r;
}

public synchronized void unsetRunnable(Runnable r) {


runnable = null;
}

public synchronized void _run(CommandInterpreter ci) {


if(runnable != null) {
runnable.run();
} else {
ci.println("Error, no Runnable available");
}
}

public String getHelp() {


return "\trun - execute a Runnable service";
}
}

This class implements the CommandProvider interface, which is used to extend the set of
commands available at the "osgi>" prompt when you run Equinox. The reason for writing a
CommandProvider is that it provides a convenient way to test our code interactively. There is a
more detailed discussion of command providers in Chris Aniszczyk's article on IBM developerWorks.

Notice that we don't call any OSGi APIs in this class, in fact we don't even need to import anything
from the org.osgi.* packages. The service that we depend on – in this case, an instance of
java.lang.Runnable – is provided to us through the setRunnable method, and it is taken
away using the unsetRunnable method. We can consider this a form of dependency injection .

The other two methods, getHelp and _run are the implementation methods for the command
provider. Yes, "_run" is a funny name with its leading underscore, but that is just an odd feature of
the Equinox console API, and nothing to do with OSGi or Declarative Services. Methods using the
leading-underscore pattern become commands on the Equinox console, so by providing a method
called _run we have added a "run" command. Another thing to notice about this class is that we're
being careful to ensure that the runnable field is updated and accessed in a thread-safe way. Thread
safety is particularly important in OSGi since it is intrinsically multithreaded, but frankly we should
always write our code to be thread-safe.

As before, we have to provide an XML file containing the DS declarations to get this to work. Copy
the following into OSGI-INF/commandprovider1.xml in your plug-in project :

<?xml version="1.0"?>
<component name="commandprovider1">
<implementation class="org.example.ds.SampleCommandProvider1"/>
<service>
<provide
interface="org.eclipse.osgi.framework.console.CommandProvider"/>
</service>
<reference name="RUNNABLE"
interface="java.lang.Runnable"
bind="setRunnable"
unbind="unsetRunnable"
cardinality="0..1"
policy="dynamic"/>
</component>

There's another important step which I neglected to mention last time. (Thanks to Seamus Venasse
for pointing it out .) You need to edit the build.properties file in your plug-in project, and
check the box next to the OSGI-INF folder. This is necessary to ensure the folder is included when
the bundle is exported using Eclipse's export wizard, or built using PDE Build.

Also we need to add the following line to the bundle manifest :

Service-Component: OSGI-INF/commandprovider1.xml

This declaration has two of the same elements that we saw before, the implementation and
service nodes. The implementation node provides the name of the class which implements
the component, and the service node tells DS to register the component as a service. In this
case we are registering under the CommandProvider interface, which is how we let the Equinox
console know about the existence of our command provider.

The next element called reference is something we haven't seen before – it declares to DS that
our component has a dependency on a service. The name attribute is simply an arbitrary string
which names the dependency (we don't need to worry yet about what this is used for) and the
interface attribute specifies the name of the interface we depend on. The bind attribute is the
name of a method in the implementation class that will be called by DS when a service becomes
available, or in other words, when a Runnable service is registered with the Service Registry, DS will
obtain a reference to the new service object and supply it to our component using the specified
method. Likewise the unbind attribute is the name of a method that will be called by DS when a
service we were using becomes unavailable.
The cardinality attribute reveals the real power of DS. This attribute controls whether the
dependency is optional or mandatory, and whether it is singular or multiple. The possible values
are :
• 0..1: optional and singular, "zero or one"
• 1..1: mandatory and singular, "exactly one"
• 0..n: optional and multiple, "zero to many"
• 1..n: mandatory and multiple, "one to many" or "at least one"

In this example we chose optional and singular, which means our command provider can cope with
the dependent service being unavailable. Looking back at the code for the _run method, you can
see it was necessary to do a null check to handle such a situation.

Let's see what happens if we run this bundle. If you still have your SampleExporter bundle from last
time, then you should see the following response when you type the run command at the osgi>
prompt :

Hello from SampleRunnable

Great ! This confirms that we have successfully imported the Runnable service that we wrote in the
last lesson. Now try using the stop command to turn off the SampleExporter bundle. When you
type the "run" command again you should see:

Error, no Runnable available

Which means that DS noticed the Runnable service going away, and called our unsetRunnable
method to let us know.

Looking again at the cardinality attribute, what do you think will happen if we change to
"1..1", i.e. switch from an optional to a mandatory dependency? Try making that change and
restarting Equinox. If the SampleExporter bundle is active when we type "run" then we will see the
same message as before: "Hello from SampleRunnable". However, if SampleExporter is inactive then
we will see a very different error message than before. In fact, we will see Equinox's console help
message, which is its standard response to an unrecognized command. This indicates that our
command provider itself has been unregistered by DS! Since the component has a mandatory
dependency which cannot be satisfied, DS is forced to deactivate the component and unregister any
services it was providing. That in turn means that the Equinox console forgets about the "run"
command.

The ease with which we can make changes like this is one of the best reasons to use Declarative
Services. Remember that with ServiceTracker we would have had to rewrite a fairly substantial
piece of code.

You might be wondering about the policy attribute, since I haven't mentioned it yet. The value of
this can be either "static" or "dynamic", and it states whether the component implementation is able
to cope with having services dynamically switched. If it is not, then it is necessary for DS to
deactivate the component and create a new instance each time the target service changes. As you
might expect, this is quite a heavyweight approach, and it's best to code your component classes to
support dynamic switching whenever possible. Unfortunately the default value is static, so you have
to remember to set it to dynamic explicitly.

So, we've seen optional singular and mandatory singular, but what about multiple dependencies?
There may be more than one Runnable registered in the Service Registry, and if we only bind to one
of them then the choice of which one we get is arbitrary. Perhaps instead we would like to
implement a "runall" command that runs all of the currently registered Runnables.

What would happen if we just changed the cardinality to "0..n"? In a way, that would almost work:
instead of calling the setRunnable method just one time, DS will call setRunnable once for
each instance of Runnable in the registry. The problem is that the class we wrote will get confused.
Instead of setting a single Runnable field, we need to accumulate the Runnables into a collection.
Here's the slightly modified version of the class, which you can again copy and paste directly into
the src folder of your project :

package org.example.ds;

import java.util.*;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;

public class SampleCommandProvider2 implements CommandProvider


{

private List<Runnable> runnables = Collections.synchronizedList(new


ArrayList<Runnable>());

public void addRunnable(Runnable r)


{
runnables.add(r);
}

public void removeRunnable(Runnable r)


{
runnables.remove(r);
}

public void _runall(CommandInterpreter ci)


{
synchronized(runnables)
{
for(Runnable r : runnables)
{
r.run();
}
}
}

public String getHelp()


{
return "\trunall - Run all registered Runnables";
}
}

Now create OSGI-INF/commandprovider2.xml and copy in the following contents :

<?xml version="1.0"?>
<component name="commandprovider2">
<implementation class="org.example.ds.SampleCommandProvider2"/>
<service>
<provide
interface="org.eclipse.osgi.framework.console.CommandProvider"/>
</service>
<reference name="RUNNABLE"
interface="java.lang.Runnable"
bind="addRunnable"
unbind="removeRunnable"
cardinality="0..n"
policy="dynamic"/>
</component>

... and finally add this file to the Service-Component header of the manifest, so that it looks
like this :

Service-Component: OSGI-INF/commandprovider1.xml,
OSGI-INF/commandprovider2.xml

This declaration essentially the same as before, except we have renamed the bind and unbind
methods, and changed the cardinality to "0..n". As an exercise, try registering a few additional
Runnable services and check that the "runall" command executes all of them. Next, what do you
think will happen if we change the cardinality to "1..n"? Try verifying it does what you expect.

That's all for this lesson.


A Comparison of Eclipse
Extensions and OSGi Services
Since Eclipse adopted the OSGi runtime in version 3.0, there has been some tension between the
Extension Registry, which has been a feature of Eclipse from its beginning, and the Service Layer,
which came from OSGi and pre- existed the involvement of Eclipse. The cause of the tension is that
these two models overlap somewhat, and because they are both intended to solve very similar
problems. However “the Devil is in the details”, and these two models are different enough to make
it impractical for them to be merged. Therefore developers of Eclipse plugins and RCP applications
need to make a choice between the two.

Until very recently, the choice for Eclipse developers has been very clear: the Extension Registry is
still used in almost all plugins and RCP applications, to the exclusion of OSGi Services. This is
reinforced by the tooling that is available in Eclipse PDE, which provides lots of support for
extensions and none for services.

However, recent developments in OSGi have further blurred the boundaries between the two models,
and the tools are evolving too. This leads to the inevitable question: “which one is best”?

Structure of the article


This article is intended primarily for Eclipse developers who are reasonably familiar with the
“Eclipse Way” of plug-in development with extension points and extensions, but do not have much
experience of OSGi services. As such, there is not a lot of discussion of how extensions work or why
they exist. The section that follows is just a brief overview.

After that, we discuss OSGi services in a little more depth, including some example code. We talk
about the issues that Eclipse developers might come across when getting to grips with services. We
will also discuss some of the newer facilities available in OSGi which may help to overcome those
issues.

Finally we wrap up with a comparison grid and a conclusion with some recommendations and
further reading.

The Eclipse Extension Registry


The Extension Registry is a place where extension points are matched up with extensions. An
extension point is a declaration made by a plug-in to say that it is open to being extended with new
functionality in a particular way. It is found in the plugin.xml file for the plug-in, and it consists
of :

• An extension point ID, which consists of a “namespace” and suffix. The namespace is
usually the ID of the plugin in which the extension point is defined, but it need not be. This
is different from an “XML namespace”.
• A human-readable name.
• An XML schema document, which defines the structure of the meta-data that extensions are
required to supply.
An extension is the flip-side of the coin. It is a declaration by a plug-in to say that it
provides functionality to extend another plug-in. It is also found in the plugin.xml
and it specifies :

• The ID of the extension point.


• An XML node, which must comply with the schema specified by the extension point.

After a plug-in is installed and enters the RESOLVED state, Eclipse queries it for contributions to
the extension registry. A plug-in can contribute either extensions or extension points, or both. The
result of the scan is cached between runs of Eclipse, so the only time that all of the plug-ins are
scanned is when Eclipse is started for the first time, or when your run it with the -clean command
line switch.

At this point, Eclipse has done very little work. You could think of the registry as being just like a
pair of HashMaps, that allow Eclipse to lookup either extensions or extension points by their ID. So
far, we have simply dropped a few items into the HashMaps.

Some time later, a plug-in may decide to query the registry. Usually this is done by the definer of an
extension point. Essentially that plug-in asks “who has declared that they have extensions for me?”
The registry API provides the plug-in with a snapshot of all the currently installed extensions for the
ID that was queried, as an array of data structures that closely resemble the actual XML nodes given
by the extension. And that is (almost) the whole story for the extension registry: it enables plug-ins
to search for meta-data declared by plug-ins. The key thing to notice here is that no Java classes in
the extension plug-in have yet been loaded. We have merely loaded some XML data; this takes far
less time and memory than creating a ClassLoader and using it to load code.

Of course Java code has to be loaded at some point. When does that happen? It depends on the
definer of the extension point. So far it has queried the extension registry and obtained meta-data,
but that meta-data often contains the name of a Java class. In order to make use of that class, the
plug-in asks the extension registry to load and instantiate the class.

So it is up to the definer of the extension point to decide when the code in the extensions is loaded.
It’s perfectly possible to immediately load all of the classes; however this usually isn’t necessary.
Typically the meta-data is sufficient to create some kind of placeholder, and then the actual class is
only loaded when the user expresses some interest in it.

For example, the org.eclipse.ui.actionSets extension point can be used to add buttons to
the application toolbar. Clicking a button executes a task of some kind, which is implemented as
Java code. However, until the button is clicked it consists solely of an icon and a label. Therefore
the meta-data for the extension point includes the text for the label and the resource path of the
icon. No code is loaded until the user has expressed an interest in the button, i.e. by actually
clicking on it.

Figure 1 shows a UML-style sequence diagram of how extension point definers and extension
providers interact with the extension registry.
Figure 1: Extensions

Another interesting aspect of extensions is that they needn’t result in any code being loaded at all.
It is entirely up to the definer of the extension point. There are many extension points in the core
RCP plug-ins that do not require a class attribute. For example, all of the Help documentation in
Eclipse is contributed through extensions, and there is no Java code involved — just HTML files.

The points to take away from this are :

• extensions are declarations

• plug-ins consult extensions to create placeholders for functionality

• the functionality behind the placeholder is realized when the extension point definer
chooses, which enables lazy loading and smaller memory usage

• extensions need not be associated with executable Java code


OSGi Services
By contrast, an OSGi Service is a Java object (or, if you prefer, a POJO). It is registered in the
Service Registry under the name of a Java interface.

Unlike extensions, which are scanned and registered during start-up, services are not automatically
registered. To register a service, a bundle must first create an object, and then it must make a call
to the OSGi API to register the object as a service. For example suppose we have a service that is
defined by the interface org.example.ICustomerLookup and a class that implements it called
DbCustomerLookup. We could register it as follows :

public void start(BundleContext context) {


// Create the service object
DbCustomerLookup lookup = new
DbCustomerLookup("jdbc:mysql:localhost/customers");

// Create the properties to register with the service


Dictionary properties = new Hashtable();
properties.put("dbname", "local");

// Register the service


context.registerService(ICustomerLookup.class.getName(), lookup,
properties);
}

There are a number of ways for a bundle to lookup and use a service from another bundle. This is
slightly harder because the service layer in OSGi is implicitly dynamic — we have to be prepared for
the fact that services can come and go at any time. Therefore the familiar technique of looking up a
dependency once and caching it will not work in OSGi. One solution is to lookup the service every
time we need to access it, but as the following code shows this can quickly become cumbersome :

public void start(BundleContext context) {


this.context = context;
}

public String getCustomerName(long id) {


ServiceReference ref =
context.getServiceReference(ICustomerLookup.class.getName());
if(ref != null) {
ICustomerLookup lookup = (ICustomerLookup)
context.getService(ref);
if(lookup != null) {
Customer cust = lookup.findById(id);
context.ungetService(ref);
return cust.getName();
}
}

// Couldn't get name -- service not available


return null;
}

Figure 2 shows a sequence diagram of the steps involved in registering and consuming a service.
Figure 2: Services

Because doing this is so awkward, there is a utility class that can be used to make things much
easier. It is called ServiceTracker and can be used as follows :

public void start(BundleContext context)


{
this.custLookupTracker = new ServiceTracker(context,
org.example.ICustomerLookup.class.getName(), null);
this.custLookupTracker.open();
}

public String getCustomerName(long id)


{
ICustomerLookup lookup = (ICustomerLookup)
this.custLookupTracker.getService();
if(lookup == null)
{
return null; // Alternatively might throw an exception
} else
{
Customer cust = lookup.findById(id);
return cust.getName();
}
}

ServiceTracker also makes other types of interaction with services easier, such as keeping track
of when the service is registered and unregistered. Doing this with the lower level APIs such as
ServiceListener can be quite error-prone, so it is recommended to always use
ServiceTracker to consume services.

Notice that in both registering services and accessing services, the interaction with OSGi is through
an instance of the BundleContext interface. In fact, the BundleContext interface is the only
way for bundles to interact with the facilities of the OSGi runtime. Furthermore, the only way we can
get a BundleContext is to wait for the OSGi runtime to give one to us — we do this by providing
a BundleActivator for our bundle. When the bundle is started, the runtime calls the start()
method of our BundleActivator and supplies a BundleContext instance. Before our bundle
can be started, it must be loaded. Therefore, until the bundle is loaded, there can be no services
registered. Suppose, then, that all the functionality of our application is implemented as OSGi
services. Which bundles do we start ?

There are three options. First, we could start none of them. This clearly doesn’t work. Second, we
could start all of them. This works, but it would result in slow startup times, and our application
would use more memory than it needs to get a particular job done. The third option is to know in
advance which bundles need to be started, and only start those. This option is very hard to achieve
when services are registered by programmatic code, as we have just described. The problem is that
a bundle has total freedom to register a service whenever it chooses, or alternatively it might not
register a service at all because of certain preconditions. For example, suppose we have service A
and service B. it is very common for service B to have a dependency on service A, i.e. service B
uses the facilities of A to get its own work done. To support this scenario, the bundle that registers
service B can install a listener, and ensure that service B registers only when service A becomes
available. This is just one scenario — there are many more possibilities. A bundle might even
decide only to register a service when started on Fridays between 1PM and 2PM. Because control is
in the hands of arbitrary programmatic logic, the possibilities are infinite and unpredictable.

So, because bundles have such flexibility in registering services, it is really only possible to build an
application out of services when the preconditions of all the services are carefully documented. This
is clearly impractical for applications like the Eclipse IDE, where the base application is extended
by plug-ins from third parties. In fact, it can quickly become impractical for large applications, even
those built by a single team. But Declarative Services can help (see next section).

So do services have any advantages over extensions? In my opinion, yes, they do have one
significant advantage: they are very much better at dealing with dynamic installation and
uninstallation than extensions. This is not to say that extensions do not handle dynamic behavior.
They do, but some people feel the API is complex and difficult to work with, and the impression
when working with it is that the dynamic aspects were bolted on top of an existing API rather than
being part of the API from the start. In fact that’s exactly what happened. Before Eclipse 3.0 the
extensions API was not dynamic, and the core of the API has not changed since then. By contrast
the API for working with services is inherently dynamic. This is sometimes inconvenient — one is
forced to think about the dynamic aspects even when one doesn’t want to! — but in truth this is
good discipline, since the real world is intrinsically dynamic.
There are some scenarios where the advantages of services outweigh the problems related to
activation. Take for example servers. In an ideal world, servers should almost never be shut down,
but keep going and going until the hardware they run on wears out. In this context, we might as well
start all bundles when the server comes up. It may take longer to start, but what do we care about a
few extra minutes in start-up time if the server is going to be running for months or years? Actually
developers care, because they need to quickly deploy and test new versions of their code to
development servers. However, here again the dynamic qualities of services can help, because new
versions can be deployed to a running server without needing to restart the whole thing.

Another key difference is in the way that services and extensions interact with their consumers. The
extension model is essentially “one-to-many”, meaning that an extension is explicitly intended for
consumption by one particular plug-in; i.e. the definer of the extension point. On the other hand
services use a “many-to-many” model, meaning that a single service can have many consumers.
Services are registered so that anybody can find them and use them. For example, imagine the
scenario of publish/subscribe messaging. Each publisher could be matched with multiple
subscribers, and each subscriber could receive messages from multiple publishers.

So what we really want is something that combines the advantages of both extensions and services.
Something that is implicitly dynamic like services, but loaded “on demand” like extensions. Ideally,
something that can also simplify the code that application developers must write.

The first steps towards such a solution were taken by Humberto Cervantes and Richard S. Hall in
their Service Binder library. This attempted to bring a declarative flavor to OSGi services, along with
automating the wiring up of dependencies between services. Service Binder, together with some
input from the Eclipse developers (who by this point had become heavily involved in OSGi) evolved
into a framework called Declarative Services (DS), developed within the scope of OSGi Release 4.
An implementation of Declarative Services can be found in the Equinox project. Equinox is an
implementation of OSGi Release 4 and it has been at the core of Eclipse since version 3.0.

Declarative Services
The key observation that led to Service Binder and Declarative Services was that there are actually
two separate responsibilities involved in offering a service. Firstly somebody has to create an
implementation of a service. Secondly somebody has to publish the service in the service registry. In
the traditional services model we described above, those two somebodies were usually the same –
i.e. the bundle that implements the service also registers it. However if we separate the two
responsibilities, then we can achieve something really powerful.

That is what Declarative Services does. The responsibility for implementing services remains with
the bundles as before; however the responsibility for registering services is subsumed by a special
bundle called the Service Component Runtime or SCR. So instead of each bundle needing supply
code to register its services, it simply allows the SCR to register those services on its behalf.

Naturally the SCR needs some way to know about services which it is supposed to register. As the
name “Declarative Services” suggests, this information is provided declaratively. In fact, we’ve
come full circle back to XML files. A bundle containing services that it wants the SCR to manage on
its behalf contains one or more XML files, with each file representing a “Service Component”. The
SCR scans bundles for these XML files, and registers the services described therein. As opposed to
extensions (where there is a single XML file per bundle and it is always called plugin.xml), there
can be an arbitrary number of XML files per bundle, with arbitrary names. Therefore the files have
to be listed in the bundle manifest under a new Service-Component in order for SCR to find
them.
Now, the scenario above is still not “on demand”. To support lazy registration, Declarative Services
has the notion of “delayed” services. When the SCR registers a delayed service, it creates a proxy
object to act as a placeholder, and registers that in the service registry. From the point of view of a
consumer, the service is now available for use, however the bundle containing the real service
implementation has not been started yet. Then when a consumer tries to actually use the service,
the SCR detects this, and asks the OSGi runtime to fully load and activate the bundle. It then
substitutes the proxy for the real service. A key difference between extensions and Declarative
Services is that, for the consumer, DS implements laziness transparently, i.e. the code that uses a
service need not know or care that the service is temporarily only represented as a placeholder. In
contrast, the consumer of an extension must create and manage the placeholder explicitly, and
choose when to swap the placeholder for the real implementation.

Figure 3 shows the sequence diagram for Declarative Services. Notice that all of the steps from the
vanilla OSGi services diagram are still present. DS refines the services model, rather than replacing
it.

Figure 3: Declarative Services

Another problem we identified with services — namely that programmatic code has too much
flexibility with regard to whether and when it registers services — is also addressed by Declarative
Services. The logic controlling the registration of services is specified via declarations, which are
easy to access and reason about. This makes it much easier for administrators to, say, work out why
a particular service won’t come up, and then remedy the situation.
Composing Services
One very interesting and powerful feature of Declarative Services is the ease with which one can
compose services.

As mentioned earlier, it is quite common to find two services, A and B, where service B depends on
service A. That is, when a method on service B is called, it may make one or more calls to service A
to achieve its end result. Next suppose that service C depends on service B: we have started to
create a graph of dependent services. Declarative Services makes this graph easy to construct. In
the XML file for service B, we simply create a reference to service A – then SCR will wire up the
dependency whenever it can be satisfied.

Note that, services being dynamic, there are some interesting questions that arise. For example,
what happens if service A goes away – what should we do with service B? Should we kill it, or
should it continue working anyway? The answer to this depends on whether the dependency is
optional or mandatory. Next, what happens when there are twenty instances of A? Does B want them
all, or just one? If just one, which one do we choose? Finally, suppose B is bound to a particular
instance of A, and that instance goes away, but there is already a suitable substitute available (e.g.
one of the remaining 19 instances). Should we switch B to use the new A, or do we need to kill B
and then create a new B pointing at the new A ?

These are all valid questions, and the answer in each case is that it depends on our requirements.
Therefore DS provides control in the three dimensions involved :

1. Optional vs mandatory.
2. Unary vs multiple.
3. Static vs dynamic.

Combining the first two axes gives the familiar four choices of 0..1 (optional + unary), 1..1
(mandatory + unary), 1..n (mandatory + multiple) and 0..n (optional + multiple). The third axis
is less familiar. A dependency is dynamic if it can be hot-swapped, i.e. if service B can be supplied
substitute instances of A. Sometime this isn’t possible; for example A might be stateful, or B may
simply not be able to handle substitution because of the way it was programmed. We say that the
dependency is static – we must destroy B and create a new instance of it.

All of the above actions naturally can cause follow-on effects in the larger graph. If service C has a
static, mandatory dependency on B, and service B has a static, mandatory dependency on A, then
every time an instance of A goes away we find that both B and C must be stopped and restarted.
When the graph is large, we find that a single service restart can cause an avalanche of restarts
across the system. However the avalanche stops when it hits an optional or dynamic dependency. So
for the most scalable solution, it is good practice to make your dependencies optional and dynamic
whenever possible.

Note that all of the above can be achieved with OSGi services. DS is built on services, after all. But
the code required to handle all of the scenarios and their corner cases is complex and error-prone.
By contrast, DS lets you specify declaratively what the behavior should be, and is tested thoroughly
for the corner cases.

Making a Choice
It might seem that Declarative Services can do everything that extensions can do, and in addition is
better at dealing with dynamics. Also since DS is a part of the OSGi specification whereas
extensions are an external extra (albeit part of every Eclipse download), there should be a natural
desire to use DS.

Unfortunately this is not quite the case yet. The “delayed” services feature requires some small
tweaks to the basic Equinox runtime, and these tweaks have not been implemented yet in the
released version 3.2. They do not appear at all yet (at the time of writing) in the other open source
OSGi runtimes, Apache Felix and Knopflerfish. They do appear in the latest milestone releases of
Equinox 3.3, but you may feel it is risky to use a milestone release in a production application.

Also, there is simply no tooling available in the Eclipse Plugin Development environment (PDE) at
the moment for Declarative Services. Building bundles with DS requires maintaining XML files
according to a special schema, keeping a list of those XML files in the bundle manifest and
ensuring it remains synchronized, and keeping XML files up to date with changes in the Java code
as the class and method names evolve. By contrast PDE provides lots of support for graphical
editing of extensions and extension points, refactoring support and so on. So the current tooling in
Eclipse strongly encourages you to use extensions rather than DS.

Finally, DS is not the only solution to the problems we described with services. Two alternatives
from Apache Felix are the Felix Dependency Manager, and a library called iPOJO. However I believe
that the stiffest competition will come from the Spring Framework.

In 2006, Spring continued to spread its influence to almost all corners of the Java world. Rod
Johnson (the father of Spring) declared that 2006 was the year Spring became ubiquitous. I think
Rod was exaggerating, but only slightly: in all likelihood 2007 will be the year.

What does Spring have to do with Eclipse and OSGi? Well, just as Spring 2.0 was being prepared for
final release, several of the core developers working on Spring started to take notice of OSGi, and
they liked what they saw. In particular they liked services, which they realized were similar in many
ways to the “beans” that Spring wires together. However OSGi is dynamic, whereas Spring is largely
static. Another thing that the Spring developers noticed was that the programming model for
services was somewhat awkward to use, and tended to involve a fair amount of repetitive boilerplate
code. They reckoned that if Spring and OSGi could work together, then the resulting platform would
benefit from OSGi’s strength in dynamics and Spring’s strength in simplified programming models
and reduced boilerplate. Therefore a decision was made to build support for OSGi in Spring 2.1.

There is, frankly, a very high degree of overlap between Spring’s OSGi support and Declarative
Services. The Spring developers looked at Declarative Services and decided that Spring already does
a lot of what DS does, and does it better. This point is debatable. But the upshot is, the long term
success of DS is by no means guaranteed. Despite being the de jure standard from the OSGi
specifications, developers tend to favor a de facto standard — which may well end up being Spring.
In fact, recent suggestions from Peter Kriens (the OSGi Evangelist) indicate that he is in favor of
Spring-OSGi becoming part of the OSGi specification in Release 5.

By the way, it’s important to note that (just like DS) Spring’s OSGi support will require the same
runtime tweaks to allow for on-demand usage. Also Spring-OSGi is in its infancy, and is absolutely
not suitable for production usage at the moment. Declarative Services is somewhat more mature,
but the implementation available in Eclipse is still a little buggy. In part this is due to a chicken-
and-egg problem — if more developers were using DS and reporting bugs, then DS would become
more stable. But until it is stable, many developers hold back on using it.

So, will DS or even Spring-OSGi someday replace the use of extensions in Eclipse? It’s conceivable,
yes. But it’s highly unlikely to happen for a few years. By that time I believe that Eclipse will be
widely used both for server platforms as well as IDEs and GUIs, and with the widened scope Eclipse
may need a more flexible model than is provided by extensions. However, extensions will certainly
be around for a long time yet.

So what should we do today? Should we start planning our migration from extensions to Declarative
Services or Spring-OSGi? Should we be worried about building our applications with extensions,
which may be heading towards obsolescence ?

No, not at all. If extensions are a good fit for your requirements, then have no fear: use extensions.
They are mature and will be supported for a long time into the future. So does that mean you should
avoid services, or DS or Spring-OSGi? Also no. If they are a good fit for your requirements, use
them. Well, it would be prudent to wait for Spring-OSGi to mature, but traditional services are very
mature already, and DS is mature enough for early adopters to start using.

Alas, the qualification “if they are a good fit for your requirements” is not so easy to evaluate. In
practice, you may find your requirements could be satisfied by both extensions and services. The
hard part is deciding which is the best fit. Here are a few guidelines.

For people building plug-ins that will be installed into a larger application such as the Eclipse IDE,
the choice is extremely clear: use extensions. That is simply the only way at the moment, since you
have to use what the host application uses. If you write your plug-ins using only services, there will
simply be nobody listening at the other end.

If you are building an RCP application, the choice is still fairly clear: use extensions, mostly. It is
not impossible to abandon extension and use services instead, especially if you have control over
the whole application. But by doing so you will be sacrificing a lot of the existing framework of RCP,
which expects you to be using extensions. You will have to reimplement the entire infrastructure of
views, perspectives, editors, action sets etc. Also, you will have issues with activation, and you will
not benefit from lazy loading unless you go with Declarative Services (or Spring-OSGi) plus the
latest milestones of Eclipse 3.3.

On the other hand, you might find some parts of your application work well with services. If that’s
the case then by all means use them in addition to extensions. But be sure to understand the
activation issues, and have a plan for ensuring the plug-ins that need to be started actually get
started.

If you’re using Eclipse or OSGi to develop something other than an RCP application — such as a
server, or perhaps a batch process — then services may be a better bet. In these kinds of
applications, hot-swapping functionality without downtime can be more important than fast start-
up. Again, there is nothing to stop you using extensions, but you will have to deal with the dynamic
extensions API and its warts.

Common Misconceptions
Before concluding, lets take a quick look at some common misconceptions. The following
arguments are sometimes used to justify a preference for extensions or services :

1. “Extensions are not pure OSGi”. This is not true. The Extension Registry is implemented by
the bundle org.eclipse.equinox.registry, which depends on
org.eclipse.equinox.common. These bundles are implemented with pure OSGi code.
There are no secret hooks into specific features of Equinox (the Eclipse implementation of
OSGi) and therefore there is no reason, at least in theory, that extensions cannot be used on
other OSGi runtimes such as Apache Felix or Knopflerfish.
2. “Services do not have meta-data.” This is also wrong. Services can be published with any
number of arbitrary properties, and these properties can be easily accessed by service
consumers. Extensions perhaps provide more flexible meta-data than services (i.e. an XML
node versus a list of name/value pairs) but this is unlikely to be a real differentiator.

3. “Extensions are a legacy of Eclipse 2.0”. This is true in a sense, but “legacy” can imply
“obsolete”. As has been argued, extensions are anything but obsolete, and will not be for
some time to come.

Comparison Matrix

Extensions Services Declarative Services Spring-OSGi


Placeholder proxies Placeholder
for Java objects, proxies for Java
XML declarations,
What are replaced by real Java objects, replaced
optionally containing Java objects.
registered? objects on first use. by real Java
class names.
objects on first
use.
All Spring XML
All service component
files contained in
XML files declared
All <extension> the META-
through the
nodes in the Through the INF/spring
How are they Service-
plugin.xml are BundleContext folder of a
registered? Component manifest
automatically API bundle, or
entry are
registered. declared through
automatically
the Spring-
registered.
Context
Internally uses same
query over interface
Queried by Same as for DS,
Queried by extension name plus filter, but
interface name, but can
point ID. Registry the query is
plus a property additionally
How are they returns all entries, performed within
filter. Usually the supply matching
consumed? consumer must iterate SCR. Matching
filter is specific services via
them to find which services are supplied
enough to ensure constructor
one(s) it wants. to consumer code via
just one match. arguments.
JavaBean-style setter
methods.
Conventionally, one to
many. One extension
point has many Many to many. One
extensions, but each service can be used
What is the extension has exactly by multiple Same as for
Same as for services
cardinality? one extension point. consumers, and one services
However another plug- consumer can use
in can query extension many services.
points that it doesn’t
own.
When are Extension declarations The class that For delayed services, Same as for DS.
they loaded? are loaded during implements a the SCR registers a
service must be placeholder proxy
start-up, or when a
loaded and service immediately
new plug-in is
instantiated before when a DS-enabled
installed. Classes
the service can be bundle is resolved.
named in the
registered. This The real class is
extension are loaded
happens only when loaded and
lazily, i.e. only when
the bundle is instantiated when the
needed.
explicitly started. service is first used.
SCR calls methods on
the component to
Similarly to DS,
How is supply it with the
Either query on supplies latest
dynamic Either query on each latest available
each use or track matching service
installation/ use or track with matching service. It
with through setter
uninstallation ExtensionTracker. can also call an
ServiceTracker. method on the
dealt with? unset method when
bean.
the service becomes
unavailable.
Can caching Yes, but this is
references to strongly
Yes, and as a legacy of
extensions/ discouraged by the No, SCR does not do No, Spring-OSGi
pre-OSGi usage, some
services specification, and this. does not do this.
plug-ins still do this.
cause in practice happens
problems? rarely.

Conclusion
In this article I have described in general terms some of the strengths and weaknesses of Eclipse-
style extensions and OSGi-style services. However I would not wish my readers to take away a
simplistic message that “extensions aren’t dynamic” or “services can’t be used in RCP
applications.” I’m afraid the issues are too subtle for that, and there is no substitute for making
your own evaluation in the context of your requirements. To help you do that, I leave you with some
references to further information on each of the subjects discussed.

References

• Eclipse Equinox can be downloaded from http://www.eclipse.org/equinox/.

• The OSGi spec and JavaDocs can be browsed via http://www.osgi.org.

• For full details on extensions, check the Help documentation included with Eclipse. Also try
the book Eclipse Rich Client Platform: Designing, Coding, and Packaging Java Applications
by Jeff McAffer and Jean-Michel Lemieux (Addison-Wesley).

• For services, see the OSGi Service Platform Core Specification Release 4, section 5. Also
see the services tutorial on the Knopflerfish website and Peter Kriens’ Snippets page

• Humberto Cervantes’ and Richard S. Hall’s Service Binder


• For Declarative Services, see the OSGi Service Platform Service Compendium Release 4,
section 112.

• Felix Dependency Manager appears to be undocumented as yet, but it is based on the


Xenotron Service Manager

• Clement Escoffier’s iPOJO

• For Spring-OSGi, see the preview documentation on the Spring website.

• For the design of OSGi Lazy Activation policy (the “tweak” required to make delayed services
work in Declarative Services), see this page on the OSGi Wiki.

Acknowledgements

I would like to thank Alex Blewitt, Jeff McAffer and Peter Kriens for their invaluable input into this
document. However, all opinions expressed are mine, as are all errors and omissions.

We encourage you to ask the author any questions or discuss the article here.

You might also like