Monday, May 21, 2012

Karaf SCR Components

Hi All,

A while back I submitted a collection of SCR command and management components to the Apache Karaf project that were ultimately incorporated into the Karaf 3 trunk.  They have been added to the Karaf 3 Feature XML also so you can look for it in the feature list.  The components provide the ability to list, stop, start and get the details on currently loaded SCR components in the container.  There are also a small set of examples that I will be writing about here in the near future on simplifying OSGi development using SCR and the BND Annotations for SCR & Metatype.

Now while this is great for those of us that use SCR it is currently only available in the Karaf 3.0.0-SNAPSHOT and as such, is not backwards compatible with the Karaf 2 releases.  To remedy that I have released a couple of versions for Karaf 2 out on github under my karaf-sandbox project.

Currently I have created versions that are directly compatible with versions 2.2.5 & 2.2.7 as there were changes between them that broke the compatibility.  They can be found in branches of the same name.

I will be changing the trunk over to create a version for Karaf 2.3 soon so make sure you use what is in the branches and not in trunk.


ServiceMix/CXF Development in a Heterogeneous JVM Environment

When developing ServiceMix deployed CXF applications for a heterogeneous JVM environment,  there are some known steps that need to be taken to avoid incompatibilities between the JVM providers.  This typically involves overriding the JVMs implementation of JAXP with a constant and stable version of Xerces using the JVMs endorsed directory capabilities.  If you are in a large enterprise or distributed environment this can lead to project overhead though when you start adding up all the developer, test and production environments.  I faced this very issue and with the use of Maven was able to reduce this overhead to something much more manageable.  Below are those steps and hopefully they will help you all out.

First we need to establish what version of Xerces that will be used by our projects.  My recommendation is to use the version of Xerces that is defined by the version of ServiceMix you will be using.  Then make the version a defined property in your parent so we can change it in one place and it will be picked up by all our projects.

Next we have to establish a consistent location for our endorsed development directory to place our chosen version of Xerces.  If you have a large project with many modules and sub-modules this can be problematic.  To overcome this I used the Maven Dependency Plugin to copy the necessary libraries into a common location for each project.  The definition for this plugin is below:

The keys to the configuration above are ensuring the plugin runs during the process-resources phase and setting the version and the outputDirectory plugin configuration elements.  Setting the version allows you to control what version of the dependency is used otherwise you are leaving it up to the plugin to determine it which can be inconsistent.  I also overrode the default location of the output directory setting it to ${}/endorsed for readability.  This gives me a consistent endorsed location at a project level which will become important when we start to compile and test our projects.  Finally, I typically define this plugin it in my parent as a managed plugin and then reference in the build plugins on a project by project basis.  Otherwise this plugin will execute even for POM projects which is really unnecessary overhead.

The next step is to tell the compiler to use our endorsed directory as shown below:

We do this by setting the compiler plugins compilerArgument configuration parameter to -Djava.endorsed.dirs=${}/endorsed.  Defining this ensures all our projects will use the locally created endorsed directory when compiling our main and test code.

The next part of our Maven configuration involves setting up the Maven CXF Codegen Plugin to deal with a known issue with the IBM JVM.  We need to pass in our Xerces implementation as a dependency to the plugin as shown below:

The known issue involves the IBM JVM throwing the following error:
org.apache.xerces.impl.dv.DVFactoryException: DTD factory class org.apache.xerces.impl.dv.dtd.DTDDVFactoryImpl does not extend from DTDDVFactory
Typically we see this configuration as a IBM JDK profile in other Maven projects.  Given that we are making our all our projects use a consistent version of Xerces, this can now be the default.  We no longer have to worry about creating a separate profile for the various JVMs.

Now on to the the test phase of our projects.  Given that we are compiling against an endorsed library, we need to provide that same endorsed directory to phases in our project that execute our code base.  As such we need to make the endorsed directory available to our Maven Surefire (test phase) and Failsafe (integration test phase) Plugins. The example of how to configure the Maven Surefire Plugin is below (it is the same for both plugins):

The first property in the argLine configuration element is the system property to override the default endorsed JVM directory.  We have to go a step further with an executable though and tell the JVM which implementation of the JAXP factories we want the JVM to use.  This is done by setting the following system properties in the argLine configuration element also:
  • DocumentBuilderFactory
    • -Djavax.xml.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
  • DatatypeFactory
    • -Djavax.xml.datatype.DatatypeFactory=org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl
  • SAXParserFactory
    • -Djavax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl
Gotcha warning: Do not wrap the argLine configuration property as some versions of the plugin do not support line wrapping and blow up the plugin.

Finally we need to make sure our version of ServiceMix is using the endorsed version of Xerces and the factories we want to override.  Some older versions of ServiceMix do not define an endorsed directory so check to make sure one is available, it has the version of Xerces we are using and is referenced in the ServiceMix startup scripts.  With that, ServiceMix does not override the JAXP factories though so this is something we need to take care of ourselves.  This is accomplished by exporting the JAVA_OPTS environment variable with the system property factory overrides we specified above for our unit and integration tests.

Once all the steps above are finished, you should be able to build and run your CXF codebase in ServiceMix against any current JVM.