Friday, March 18, 2011

Importing packages into a 3rd party bundle

I regularly come across the situation where someone needs to import additional packages into a 3rd party OSGi bundle. Sometimes this is because the bundle manifest is incorrect, but more often it's because the bundle uses Class.forName or similar to load classes that are somehow configured at runtime.


Unless the bundle is signed, it's possible to edit the manifest to add the import, but this is a really bad idea. If the original bundle needs upgrading, you have to remember to re-edit the manifest. Also, it's easy to mess something up in the process. Finally, it's bad practice to change the contents of a bundle without modifying the bundle version.

Thankfully, there is a simple way to add imports to a bundle without resorting to such invasive surgery: use a fragment bundle. Fragment bundles can extend the manifest of their host in various ways. In particular, they can add package imports. The fragment bundle need only contain a manifest, for example:


Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: my.fragment
Bundle-Version: 1
Bundle-Name: My Fragment
Fragment-Host: host.symbolic.name;bundle-version="[2.4,2.5)"
Import-Package: extra.package;version="[1.1,1.2)"

More than one fragment bundle can attach to a given host bundle, so this technique can be used when unrelated groups of packages need to be imported: a separate fragment can be used for each group.

Each fragment bundle needs to be installed before its host is resolved at which point the fragment's manifest is merged into the host's and the resultant Bundle instance imports the packages added by the fragment. On Virgo, this can be achieved by placing the fragment bundles in repository/usr. When the host is deployed, the fragments are automatically installed along with the host.

Note: make sure you use the "bundle-version" attribute of Fragment-Host. "version" is not a standard attribute of Fragment-Host and if you use it accidentally in place of "bundle-version", chances are your fragment will not attach to its host.

3 comments:

Nicolas Lalevée said...

Very interesting. So this technique can also be used to deal with Hibernate ?

Glyn said...

I guess so, but it's more usual for hibernate to use the thread context class loader to load application classes rather than having to import their packages. Virgo has some nice support for this.

Robert said...

Very useful, indeed. May be for completeness it is worth mentioning that the same technique can be used to expose packages from outside the OSGi framework to bundles running inside in a pretty modular manner by using
Fragment-Host: system.bundle; extension:=framework
I find this especially helpful when OSGi runs embedded in a more complex legacy application and certain non-OSGi capable functionality should be made available in a controlled manner.

Projects

OSGi (130) Virgo (59) Eclipse (10) Equinox (9) dm Server (8) Felix (4) WebSphere (3) Aries (2) GlassFish (2) JBoss (1) Newton (1) WebLogic (1)

Blog Archive