Sunday, October 12, 2014

How to change the StAX implementation in an OSGi environment

The StAX API uses the so called JDK 1.3 service provider discovery mechanism to locate providers of its three factory classes (XMLInputFactory, XMLOutputFactory and XMLEventFactory). This mechanism uses the thread context class loader to look up resources under META-INF/services/. Switching to a StAX implementation other than the one shipped with the JRE therefore requires deploying the JAR containing that implementation in such a way that it becomes visible to the thread context class loader.

In a simple J2SE application, the thread context class loader is set to the application class loader and the right way to do this is to add the JAR to the class path. In a JavaEE environment, each application (EAR) and each Web module (WAR) has its own class loader and the specification requires that the application server sets the thread context class loader to the corresponding application or module class loader before invoking a component (servlet, bean, etc.). To change the StAX implementation used by a given application or module, it is therefore enough to add the JAR to the relevant EAR or WAR.

Things are different in an OSGi environment because each bundle has its own class loader, but the thread context class loader is undefined. JDK 1.3 service provider discovery will therefore not be able to discover a StAX implementation deployed as a bundle. The solution to this problem is to modify the StAX API to replace the JDK 1.3 service provider discovery with an OSGi aware mechanism not relying on the thread context class loader. That modified StAX API would then be deployed as an OSGi bundle itself so that it will be used in place of the StAX API from the JRE. At least two such StAX API bundles exist: one from the Apache Geronimo project and one from Apache ServiceMix.

In the following we will discuss how they work, and in particular how they can be used to switch to Woodstox as StAX implementation. Note that the Woodstox JAR (Maven: org.codehaus.woodstox:woodstox-core-asl) as well as the StAX2 API JAR (Maven: org.codehaus.woodstox:stax2-api) on which it depends already have OSGi manifests and therefore can be deployed as bundles without the need to repackage them.

To use the StAX support from Apache Geronimo, two bundles need to be installed: the Geronimo OSGi registry (Maven: org.apache.geronimo.specs:geronimo-osgi-registry:1.1) and the Geronimo StAX API bundle (Maven: org.apache.geronimo.specs:geronimo-stax-api_1.2_spec:1.2). The OSGi registry tracks bundles that have the SPI-Provider attribute set to true in their manifests. It scans these bundles for resources under META-INF/services/. That information is then used by the StAX API bundle to locate the StAX implementation. This means that Geronimo uses the same metadata as the JDK 1.3 service provider discovery, but requires an additional (non standard) bundle manifest attribute. The stock Woodstox bundle doesn't have this attribute and therefore will not be recognized. Instead, a repackaged version of Woodstox is required. The Geronimo project provides this kind of bundles (Maven: org.apache.geronimo.bundles:woodstox-core-asl), albeit not for the most recent Woodstox versions.

The StAX support from Apache ServiceMix comes as a single bundle to deploy (Maven: org.apache.servicemix.specs:org.apache.servicemix.specs.stax-api-1.2:2.4.0). It scans all bundles for StAX related resources under META-INF/services/, i.e. it uses exactly the same metadata as the JDK 1.3 service provider discovery. This means that it will recognize the vanilla Woodstox bundle and no repackaging is required.

To summarize, the most effective way to switch to Woodstox as the StAX implementation in an OSGi environment is to deploy the following three bundles (identified by their Maven coordinates):

No comments:

Post a Comment