OSGIfying Metro for GlassFish V3
By ritzmann on Nov 07, 2008
Metro has been a part of GlassFish for a long time now and provides the GlassFish web services implementation. That goes of course for the newly released GlassFish V3 Prelude as well. One of the most important points of GlassFish V3 from an implementation point of view is that it is based entirely on OSGI. This means that all modules like Metro that go into GlassFish have to be provided as OSGI bundles. That is why we recently released Metro 1.4, which is also included in GlassFish V3 Prelude. The main feature it provides is that it makes OSGI bundles of Metro 1.4 for GlassFish V3 available. If you want to install the latest version on GlassFish V3, you do not download Metro yourself anymore. Instead use the update center. We are still making Metro available as an ordinary download of course for non-GlassFish V3 installations.
I wanted to talk a little about the technical challenges we had in creating OSGi bundles from Metro. OSGi is very well suited to develop a large modular system like Metro from scratch. It is not quite as easy however to convert a large base of existing code and libraries into an OSGi bundle. Metro consists of app 30 - 40 libraries, many of which are e.g. basic XML libraries that have developed over many years and are used in a huge variety of applications. Many of the libraries are not actually owned by the Metro project but are third party libraries, e.g. Woodstox. In other words, changing code or even starting to use OSGi services internally was not practical.
Ideally, we would have created separate bundles for every technology contained in Metro. Unfortunately, that would have meant lots of work and so we decided to stick with two bundles, one for JAXB and one for the rest of the Metro stack. The reason that we singled out JAXB was its unique approach that allows JAXB 2 to ensure backwards compatibility with JAXB 1.0. JAXB 2 is packaging the JAXB 1.0 classes in its JAR file. It puts these classes into a subdirectory so that an ordinary Java classloader can not find them. JAXB 2 implements its own classloader that will load the JAXB 1.0 classes when someone uses the JAXB 1.0 API. Unfortunately, that approach confused the Bnd tool that we are using to create our OSGi bundles. It created entries for the JAXB 1.0 classes with bogus package names because it interpreted the subdirectory as part of the package name. That would later confuse the OSGi container when loading classes. Since JAXB is supposed to use its own classloader in this case, we did not want these classes to show up in the OSGi manifest at all. We ultimately extracted the JAXB 1.0 classes, running the Bnd tool on the remaining classes and then readding the JAXB 1.0 classes to the OSGi bundle.
What caused most work was that we had such a big amount of libraries with an uncontrollable amount of dependencies. As I explained before, many libraries have developed over many years and are used by large amounts of applications. Additionally, we found that the OSGi classloaders are not able to deal with e.g. loading of property classes unless the packages containing these properties are declared. We would have had to go through thousands of packages and analyze which ones we really needed to expose. Moreover, as soon as a version of a library changes, you have to check again if any change has an impact on your OSGi manifest. We finally concluded that our best option was to export all Metro packages, no matter if they were supposed to be used by other clients or not. That option is certainly not worse than what you have with any Java application where all public classes in the classpath are accessible throughout the entire JVM.
All in all, putting such a large collection of libraries into OSGi bundles is a worthwile exercise because it helps to point out incorrect dependencies. At the same time, you have to realize that it can be a lot of work depending on how far you are prepared to take the conversion.