Code / BndHibernate aQute - Software Consultancy
Search
*

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.

Hibernate structure

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:

  Import-Package: *;resolution:=optional

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:

  bnd hibernate.bnd

The Import/Exports

To see the content of the jar, do:

  bnd hibernate.jar
Copyright 2006 aQute SARL, All Rights Reserved