Using Bnd To Do a Quick Wrap of Hibernate
Hibernate is one of the more complicated open source projects to wrap. First because it uses so many different other open source projects (and is therefore quite large), but also because the Hibernate bundle needs to import the bundles that use it. This is an unknown set when we create the bundle. This page shows how you can quickly wrap Hibernate in a bundle. It is likely that with more time the bundle could be improved, however, the goal is to show how one attacks the problem of wrapping an existing Jar into a bundle and not spending weeks doing it.
When we download Hibernate Core from their website and unzip it we get a directory with a file called
hibernate3.jar. This is the core hibernate file. As a convenience, Hibernate also provides all open source jars that it depends on.
The most easy route is to just wrap the hibernate3.jar. This can be easily tried out with bnd:
bnd wrap hibernate3.jar
This saves the bundle under
hibernate3.bar. Bnd provides an easy function to check the imports, to see what hibernates' dependencies are.
bnd print -impexp hibernat3.bar
This returns a very long list:
antlr antlr.collections antlr.collections.impl com.mchange.v2.c3p0 com.opensymphony.oscache.base com.opensymphony.oscache.general javassist javassist.bytecode javassist.util.proxy javax.naming javax.naming.event javax.naming.spi javax.security.auth javax.security.jacc javax.sql javax.transaction javax.transaction.xa net.sf.cglib.beans net.sf.cglib.core net.sf.cglib.proxy net.sf.cglib.reflect net.sf.cglib.transform net.sf.cglib.transform.impl net.sf.ehcache net.sf.swarmcache org.apache.commons.collections org.apache.commons.logging org.apache.tools.ant org.apache.tools.ant.taskdefs org.apache.tools.ant.types org.dom4j org.dom4j.io org.jboss.cache org.jboss.cache.config org.jboss.cache.lock org.jboss.cache.optimistic org.logicalcobwebs.proxool org.logicalcobwebs.proxool.configuration org.objectweb.asm org.objectweb.asm.attrs org.w3c.dom org.xml.sax
Let us take a look at the documentation. The reference manual specifies that the following libraries must be available:
+lib antlr.jar cglib.jar asm.jar asm-attrs.jars commons-collections.jar commons-logging.jar jta.jar dom4j.jar log4j.jar
We can take two routes. We could make bundles of all these libraries and deploy them along with hibernate. Alternatively, we could wrap these libraries inside the hibernate bundle. This will work as long as we do not share any objects with other subsystems. Antlr, Cglib, Asm, collections, logging, dom4j, log4j all seem to be function blocks that we can wrap. However, we must be careful with JTA (the transaction provider). This library must be provided by another party and objects will be exchanged with this other party. However, we want to contain it as well so that we can run even if there is no JTA provider.
We can set up a bnd file that follows our prescription. First we must set the class path to include all the jar files that will be part of our bundle. In this example we create the bnd file, let us say hibernate.bnd, in the root of the hibernate directory so we can use short relative path names.
-classpath: hibernate3.jar, \ lib/antlr-2.7.6.jar, \ lib/asm-attrs.jar, lib/asm.jar, \ lib/cglib-2.1.3.jar, \ lib/commons-collections-2.1.1.jar, \ lib/commons-logging-1.0.4.jar, \ lib/jta.jar, \ lib/dom4j-1.6.1.jar, \ lib/log4j-1.2.11.jar
This instruction sets up our classpath. We can now select the packages from this classpath. In this case we want to contain all packages on the classpath and import the missing part. We only want to export the hibernate packages and the javax.transaction packages from jta.jar, the other libraries we want to keep private. This could be a first guess, when we start to use hibernate, we might want to learn that we want to export more packages.
The following instructions should achieve this.
Private-Package: * Export-Package: javax.transaction.*,org.hibernate.*
If we now run bnd and print the import and export:
bnd hibernate.bnd bnd print -impexp hibernate.jar
We get the following list of imported packages:
Import-Package com.mchange.v2.c3p0 com.opensymphony.oscache... com.sun.jdmk.comm com.sun.msv.datatype... javassist... javax.jms javax.mail... javax.management javax.naming... javax.security... javax.sql javax.swing... javax.xml... net.sf.ehcache net.sf.swarmcache org.apache.avalon.framework.logger org.apache.log org.apache.tools.ant.. org.codehaus.aspectwerkz.hook org.gjt.xpp org.jaxen... org.jboss.cache... org.logicalcobwebs.proxool... org.objectweb.asm.util org.relaxng.datatype org.w3c.dom org.xml.sax...
Inspecting this list a bit closer makes it clear we have a problem. There are many packages which are obviously not mandatory.
org.apache.avalon.framework.logger? Not likely that such a reference can still be found at the average classpath. What we see here is a typical case of how our industry is not modularized. The single jar that a service provider provides is usually developed so it can connect to different frameworks when it is run inside that framework. Connections like Swing, Ant, Avalon, can not be required by the core software.
Clearly there are also optional features that should not be required by our bundle, for example javax.mail. In an ideal world we would have bundles of all the dependent jars and closely inspect them to provide mandatory and optional requirements. However, this is not an ideal world and we are in a hurry. A shortcut is to make all our imports optional. The OSGi specification recognizes a directive on an Export-Package clause, called resolution. This directive can be optional or mandatory (the default). An easy way out in this case is to declare all our imports optional. The following line will achieve this when added to the bnd file:
The total bnd file therefore now looks like:
-classpath: hibernate3.jar, \ lib/antlr-2.7.6.jar, \ lib/asm-attrs.jar, lib/asm.jar, \ lib/cglib-2.1.3.jar, \ lib/commons-collections-2.1.1.jar, \ lib/commons-logging-1.0.4.jar, \ lib/jta.jar, \ lib/dom4j-1.6.1.jar, \ lib/log4j-1.2.11.jar Import-Package: *;resolution:=optional Private-Package: * Export-Package: javax.transaction.*,org.hibernate.*
To create the jar file:
To see the content of the jar, do: