views:

1875

answers:

6

I'v encountered a somewhat frustating problem. Im using Apache Felix as my OSGi framework and Im also using Hibernate for persistency issues.

Im using the "osgi-bundle" version of Hibernate (com.springsource.org.hibernate-3.2.6.ga.jar). As far as I know this is the Hibernate Core with some additional osgi-metdata installed in the META-INF/MANIFEST.mf. This information (Package-Export and Package-Import) is vital for osgi systems.

My problem is that the Hibernate bundle cant find my JDBC-drivers. It feels very wrong to add Import statements to the springsource Hibernate bundle. There must be some better way to solve this.

+2  A: 

Did you take care of the correct bundle start ordering? There is a way to set the start level of every bundle, so that your system can bootstrap correctly. The correct start level of bundles might be required if some activators try to get services directly. In case the services are not available, the service consumers will just be stuck.

Try to set the proper start levels for your bundles and see whether it works. Concretely you would have to start the bundle with the JDBC drivers first before the hibernate bundle.

Another problem might be that you have some unsolved dependencies. Make sure that everythingg is there. You can do this by getting an OSGi console and asking for a list of services. In Equinox this boils down to the -console commandline argument and the "ss" followed by "diag" commands in the OSGi shell.

EDIT (answer to your comment):

The drivers are registerd by their interface. Hibernate then probably looks up a driver by its interface, no need to import specific driver classes. This anyway would introduce an undesired dependency on an implementation specific class.

lewap
but i cant see how the hibernate bundle ever will find the correct jdbc-driver without explicitly importing eg. org.embedded.derby or org.mysql.jdbc..
do you have the sources of your hibernate bundle? Have a look at the manifest and see which is the activator class. Then look at this class and this will probably answer your question
lewap
"Hibernate then probably looks up a driver by its interface, no need to import specific driver classes". Does that mean that the Hibernate bundle has some API for setting a specific JDBC-driver? (eg. set mysql-jdbc, set oracle-jdbc etc. otherwise i cant see how hibernate gets the correct driver)
the driver provider registers his driver (ctx.register(JDBCDriver, MySQLJDBCDriver) and whoever needs it asks for a driver (ctx.getService(JDBCDriver)) without knowing the driver directly
lewap
+5  A: 

Hibernate isn't a very good OSGi citizen as many of the assumptions Hibernate makes on class visibility are no longer true in an OSGi container.

The usual way of loading JDBC drivers with the Class.forName(<jdbc class name>) doesn't work inside OSGi because, in this case, Hibernate will try and load the driver but won't find it as Hibernate doesn't (and shouldn't) import the JDBC driver package.

The JDBC driver manager also tries to be smart by working out whether the calling class' class loader should see the driver and this also conflicts with OSGi.

If you use Spring to configure Hibernate then I suggest you use the SimpleDriverDataSource class as this works in OSGi and Spring allows you to configure Hibernate with a concrete data source rather than passing a class name that Hibernate needs to instantiate.

Once you get past that problem you'll probably run into the issues of Hibernate not seeing your domain classes. I only have experience with the XML mapping approach, with I think is simpler in OSGi as I think the annotations way requires AOP weaving of some sort and that's another current pain-point with OSGi.

At the moment, unless you use something like Spring's dm Server you'll need to become much more familiar with Java's class loading mechanism and how you can use OSGi's approach to services to work around the incompatibilities between vanilla Java and the OSGi world.

Specifically, look into how enterprise libraries use the context class loader and how you can manage this. I am using Spring dm to wrap legacy code in OSGi services as this makes it easy to control the context class loader.

+1  A: 

I've encountered similar problem a while ago. The solution was to register jdbc-provider bundle and jdbc-user bundles as "buddies". This is because one bundle can't use classes (so jdbc drivers too) from another without explicitly declaring it. This was for Eclipse, so I assume it may help you.

Imaskar
A: 

Hello Steven,

Once you get past that problem you'll probably run into the issues of Hibernate not seeing your domain classes. I only have experience with the XML mapping approach, with I think is simpler in OSGi as I think the annotations way requires AOP weaving of some sort and that's another current pain-point with OSGi.

can you explain a little more about the problems with "not seeing domain classes". I need a solution for spring, hibernate and osgi with annotated entitys (domain objects).

Best regards,

Jonas

+2  A: 

In an OSGi bundle you can only see classes and resources from packages you have imported. The Hibernate bundle doesn't (and shouldn't) import your domain classes. Therefore, when Hibernate tries to process an XML mapping file it will complain that it can't find the class that is being mapped (your domain class).

We get around the problem by using Equinox's buddy policy so every bundle that supplies domain objects is a class-loading buddy of Hibernate. I don't like this approach too much, but I don't have the time to write the (hopefully) elegant solution that's in my head.

As I said in my earlier post, manipulating the context class loader is probably the best long-term bet when it comes to Hibernate.

hbunny
A: 

I haven't tried this (as I'm anti-RDBMS and thus anti-ORM as well), but one solution might be to use OSGi fragments.

Create a fragment that contains your domain classes and specify the Hibernate bundle as the host. This fragment should export the packages of your domain classes.

Likewise, you can do the same thing for the JDBC driver you want to use. Take the driver classes and turn them in to an OSGi fragment with Hibernate as the host bundle. However, you don't have to export the driver's packages since they are only going to be used by the Hibernate bundle.

I suspect fragments weren't supported in full by Felix 9 months ago, but they certainly are now it seems: http://osgithoughts.blogspot.com/2009/09/felix-now-fully-supports-osgi-fragments.html

brindy
The recommendation from the OSGi guys is not to go down this route with fragments and to limit them to their initial intent. The problems are all solvable without using fragments. There's an interesting presentation floating around from the EclipseLink guys on this (can't remember the link at the moment).
hbunny