OSGi applications vs. bunch of bundles

When I speak of a OSGi application, then i mean a group of bundles, which result in a application. Such a breakdown seems obvious when using OSGi. The single parts of the application communicate through the OSGi registry. One of the benefits is that you can replace a part of the application at the runtime and it want affect the other parts.

Unfortunately there is no way in OSGi to differ between bundles, which belong to different applications. This nuisance probably has a historical reason. OSGi originally was meant to run on small devices with decent amount of bundles. Today OSGi is used in projects like Eclipse IDE which hundreds of bundles inside the OSGi container. When I start my current installed Eclipse IDE (./eclipse -console) and type “ss” in the console it shows over 600 installed bundles. I have only few extra plug-ins installed. Other installations of Eclipse IDE surely get more the 1000 bundles. If I want to uninstall a plug-in over the console I would have my hands full by searching the bundles, which belongs to that plug-in. Instead I would use the update-manager of eclipse. In a different project, where I use OSGi (Equinox in my case) I do not have a update-manger, only the console.

Together with my application (composed of 6 bundles) there are a servlet container, the spring framework and few libraries installed in the OSGi container. When I develop on my application I am actually not interested in the other bundles. Some of them remain untouched since installed once. Nevertheless I have to go trough the list with all bundles, when I look for my application. It would be handy to list the bundles, which belongs to my application with a single command. Furthermore it would be handy to change the status of those bundles with a single command. As you can read in those blogs[1][2], I am not the only one missing such a feature. So I looked around whether there are already existent solutions. I discovered the Platform Archive (PAR), which was introduced by SpringSource with the release of the SpringSource dm Server (former SpringSource Application Platform). A PAR is a regular JAR-file carrying multiple OSGi bundles. When you deploy the PAR all the packaged bundles will be installed automatically. Actually the PAR concepts fixes all my problems and offers equal management functionalities as known from normal WAR and EAR archives. As PARs are currently only supported by the SpringSource dm Server this is not a solution for all OSGi runtimes. In addition to that one of the issues with the PAR archive is, that it has to bew rebuild if one bundle is updated.

To gain some more flexibility I wanted to add the desired functionality to the Equinox myself. What I want is a way to compose groups of bundles without to violate the OSGi specification, so I still can install the bundles in a different OSGi container. Furthermore I want the bundles to remain separated. After a look in the source code of equinox I realized that I don’t even have to extend the OSGi framework itself. I only have to implement the CommandProvider interface in the org.eclipse.osgi.framework.console package and build a bundle which registers a instance of the resulting class in the OSGi registry. That’s what you do in order to add your own commands to the Equinox console.

The resulting class looks like this:

public class GroupCommandProvider implements CommandProvider {
   private BundleContext bctx;
 
   public GroupCommandProvider(BundleContext bctx) {
      this.bctx = bctx;
   }
 
   public String getHelp() {
      return "\tstopgroup <group> - stops all bundles in the specified group.";
   }
 
   public void _stopgroup(CommandInterpreter ci) throws BundleException {
      String groupToStop = ci.nextArgument();
      if (groupToStop == null)
         return;
 
      Bundle[] bundles = bctx.getBundles();
      for (Bundle bundle : bundles) {
         String currentGroup = (String) bundle.getHeaders().get("Bundle-Group");
         if (currentGroup == null || !currentGroup.equals(groupToStop))
            continue;
 
         if (bundle.getState() == Bundle.ACTIVE) {
            bundle.stop();
         }
      }
   }
}

The interesting method is _stopgroup(). By calling it you can stop all bundles with a specified value in the “Bundle-Group” field in the manifest file.

A manifest file could look like this:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: de.codecentric.mybundle
Bundle-Group: myGroup
Bundle-Version: 0.1.0
Import-Package: org.osgi.framework

All bundles with the same “Bundle-Group” value can be sopped by typing “stopgroup myGroup” in the equinox console.

In order to get the GroupCommandProvider working, you need a activator which registers a instance in the OSGi registry. It could look like this:

public class Activator implements BundleActivator {
   private CommandProvider commandProvider;
 
   public void start(BundleContext bctx) throws Exception {
      commandProvider = new GroupCommandProvider(bctx);
      bctx.registerService(CommandProvider.class.getName(), commandProvider, null);
   }
 
   public void stop(BundleContext arg0) throws Exception {
      commandProvider = null;
   }
}

In order to benefit from the GroupCommandProvider you probably will have to write methods to start, uninstall and update a group of bundles. In the method for starting a group of bundles you will have to differ between bundles which need to be started and those which don’t. I decided to extend the “Bundle-Group” field in the manifest file by a additional attribute. So it looks like this “Bundle-Group: myGroup;startable=true”. I think the _stopgroup() method clarifies the idea.

This solution doesn’t provide as much features as the PAR does, but it suites my needs. We will have to wait and see whether the OSGi will get some grouping capabilities in the future.

  • Facebook
  • Delicious
  • Digg
  • StumbleUpon
  • Reddit
  • Blogger
  • LinkedIn
Eugen Melnichuk

4 Responses to OSGi applications vs. bunch of bundles

  1. Der Begriff der Anwendung fehlt sicher in OSGi. Allerdings reicht es nicht, nur Bundles zusammen zu starten. Man muss auch ein Format haben, um eine Anwendung als Einheit zu deployen. Und man muss verhindern, dass Typen oder Services in andere Applicationen “hineinwuchern”. Wenn man beispielsweise zwei Anwendungen hat, die beide dieselbe Klasse enthalten, kann man mit OSGi die beiden Klassen nicht außeinander halten. Wenn also ein Bundle einer Anwendung eine solche Klasse importiert, ist unklar, ob es die richtige bekommt oder die der anderen Anwendung.

    Noch schlimmer bei Services: Eine DataSource als OSGi-Service kann ohne weiteres auch von einer anderen Anwendung “aus versehen” verwendet werden. All diese Probleme lösen die PARs des dm Server – und sie ermöglichen auch eine sinnvolle Nutzung von Hibernate oder JPA in OSGi-Umgebungen.

    Übrigens ist das hier vorgestellte Feature Bundle-Group eine proprietäre Erweiterung von Equinox und kein OSGi-Standard – genauso wie PARs eine Erweiterung des dm Servers sind.

  2. Yevgeniy Melnichuk says:

    Hallo Eberhard,

    Danke für deinen Kommentar.
    Das ist richtig, diese Lösung ist Equinox-spezifisch. Allerdings lassen sich Bundles mit dem „Bundle-Group“ Manifest-Eintrag auch in anderen OSGi Containern installieren und starten. Der Manifest-Eintrag wird dann nicht interpretiert.

    Mit freundlichen Grüssen,
    Yevgeniy Melnichuk

  3. Juri Lazur says:

    helo Yevgeniy!

    How can I make your GroupCommandProvider run on Apache Felix?

    Juri.

  4. Yevgeniy Melnichuk says:

    Hello Juri,

    GroupCommandProvider implements the CommandProvider interface, which is a part of the Equinox Framework. It won’t work for the Apache Felix Framework.

    You can build a similar solution for the Apache Felix Framework using the ShellService interface. The following article might be helpful http://felix.apache.org/site/apache-felix-shell-service.html

    Greetings,
    Yevgeniy Melnichuk

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>