Timeout is not equal timeout

Last week I had to change a webservice-client in such a way as to be able to configure a timeout. The webservice is implemented with spring-webservices and uses the WebServiceTemplate class. (read more…)

Eugen Melnichuk

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.

Eugen Melnichuk