Embedding OSGi

From Protege Wiki
Revision as of 15:45, August 8, 2009 by Tredmond (talk | contribs) ((checkpoint save))

Jump to: navigation, search

Embedding OSGi inside a host application

There are many reasons to embed OSGi inside a host application:

  • the host application may have an extension mechanism that offers plugins no classloader protection from other extensions. This means that version problems can crop up between different extensions.
  • you have an existing OSGi implementation (e.g. Protege 4) which you want to run in a non-OSGi application setting.

There are several examples of OSGi showing up on the web. In particular, the Apache and Equinox groups have teamed up to devise a scheme that works with tomcat. Inside the OSGi environment, bundles see the standard OSGi servlet services which are transparently mapped to the underlying tomcat implementation. In response to a potential Protege developer who was having serious classloader problems I implemented the following demonstration of how a plugin for a host application can be implemented inside a embedded OSGi environment. The demonstration can be checked out with svn and run by executing ant run.

In the HostApplication project, I simulated the host application (Host.java). This application finds and initializes a plugin (PluginImpl.java). I did not simulate the plugin mechanism inside the host application; the call to initialize the plugin is a simple call to a member of the PluginImpl class. The PluginImpl class then immediately starts up OSGi and the work of the plugin is then done in the OSGi environment.

EmbeddedOSGiArch.png

There are two main points that this example is intended to demonstrate. First, the OSGi bundle is able to invoke host services. To do this, when the host application plugin is initialized it saves a static copy of itself; the plugin is a singleton. This singleton becomes a reference point for the host application services that are needed in the OSGi environment. When the OSGi bundle Activator is started by the OSGi implementation it can find the plugin by using the static PluginImpl.getInstance() method and then access and call host application services through that reference.

Second, my example included a class loader conflict. There is a library (conflict.jar) used by the host application. The plugin for the host application needs to use the same routines from the library but needs to use a different version of the library (conflict-v2.jar). OSGi has many very flexible mechanisms to ensure that this class loader isolation takes place. I will describe three different ways of isolating these libraries here.

First and most simple, the OSGi environment can be simply configured not to expose certain java packages supplied in the host application environment. The classes loaded by the host application environment's class loader are introduced to the OSGi environment through the system bundle. The set of packages are visible to the system bundle can be controlled by a configuration parameter called

     org.osgi.framework.system.packages

If you examine this declaration in the OSGi configuration file (look at the end of the fourth line) you will see that the conflicting library is explicitly included:

   org.osgi.framework.system.packages=...,org.example.conflict;version="1.0.0"

Note the version information, this will be important later. If this entry is removed then OSGi environment will not be able to load this class from the host application class loaders. This method is probably the simplest approach for most people.

Second, bundles in the OSGi framework can control where and how they load their classes. For example , the manifest of one of the bundles running in the OSGi environment explicitly imports the library definitions in conflict. Note the first line from that manifest below:

Import-Package: org.example.conflict;version="2.0.0",
 org.example.host,
 org.example.plugin,
 org.osgi.framework,
 org.osgi.service.packageadmin
Bundle-ClassPath: .

If this import is removed and the relevant conflicting package is loaded through the Bundle-ClassPath, the bundle still will not import the host applications conflicting class.

Finally, and this is the technique that the example uses, the import can be controlled by using versions. The bundle states that it wants to import version 2.0.0 of the conflicting package. The version of this package from the host application is marked as version 1.0.0 and is therefore not sufficient. This means that the bundle will look elsewhere to find the desired version of the package. The advantage of this mechanism is that it allows other bundles in the same OSGi environment to use the host applications version of the conflicting library.

This example has been designed so that it should be easy to tweak the parameters described above and see how the result is changed. Note that if there is an error, a log file will appear in the

    staged/osgi/configuration

directory. Other than the presence of this log file there will be no indication of an error. In particular if you start a run and nothing happens after OSGi is initialized then OSGi probably got into some trouble.

Variations

Baseline

Running

    ant run

on a freshly checked out copy gives this result

     [java] -------------------- Starting Host Application --------------------
     [java] Host is calling library with conflict
     [java] 	host version of the conflicting library called
     [java] ----------------- Starting Host Application Plugin -----------------
     [java] Host Application Plugin starts up an OSGi environment
     [java] -------------------- OSGi Initialized --------------------
     [java] Demonstrating that OSGi can call the host services
     [java] 	host service called
     [java] Demonstrating that OSGi can call library routines with conflict
     [java] 	OSGi version of the conflicting library  called
     [java] Bundle loading the org.example.conflict.Util class is 
     [java] 	org.example.conflict_2.0.0 [2]
     [java] -------------------- OSGi Shutting down --------------------

This output shows that the OSGi plugin bundle executes a different copy of the conflict library that is used by the host application.

Altering the imported version of the library

Now suppose that we change the import line


in the plugin bundle manifest as follows