Monday, July 18, 2011

Hibernate and OSGi

This is a copy of a blog post I did about a year ago on Java.net. Of my messages on that blog, this was the most viewed and linked. So, I've improved it, and included it in my new blog to help folks looking for help with Hibernate inside of OSGi.

One of the major contributors to the OSGi movement is Peter Kriens who created an excellent tool called BND. The good folks at apache-felix then created a maven-plugin that makes quick work of bundling apps, but I'll go over that in a later blog. The reason I bring this up here is that a while ago Peter wrote www.aqute.biz/Code/BndHibernate which discusses how to create a mega-bundle with all of Hibernate 3's core .jar files and dependant .jar files wrapped up inside of one huge .jar.

This is an excellent approach, but it has a few drawbacks:

  • It requires the creation of a new .jar file which may confuse new developers,

  • It is pretty complex, and

  • The BND tool, while most excellent and wonderful, takes some time to figure out.

What I'm going to do is show you how to leverage Karaf provisioning and SpringSource bundles to do something similar, but without having to create a massive Hibernate mega-bundle. As Peter says Hibernate is one of the more complicated open source projects to wrap". To do this, I'll:

  • Talk about an excellent source for bundles, Spring Source,

  • Describe what a features.xml file is,

  • Show you a working features.xml file for Hibernate 3, and finally

  • Show to modify one of Karaf's configuration files to automagically start up Hibernate when you start Karaf.

First, I 'd like to talk about Spring Source. These folks are doing an outstanding job of creating bundles out of commonly used java apps, like Hibernate. I would be remiss if I didn't mention the fact that, without their hard work, simply deploying Hibernate using a features.xml file would not be possible. The link points to their bundle repository, you should bookmark it, its a great resource.

Karaf has a few core concepts that this blog will illustrate to you:

  • OSGi bundles,

  • Karaf Features,

  • Features.xml documents, and

  • the org.apache.felix.karaf.feature.cfg file.

When you have an application like Hibernate that has dependencies on other libraries, one way to deploy them is to turn them into OSGi bundles and then create a features.xml file. An OSGi bundle is simply a .jar file with a MANIFEST.MF file containing OSGi goodness. There are a lot of great resources already available on the internet that go into detail about what an OSGi bundle is composed of, so I won't go further into it here.

Deploying a large application composed of bundles using a features.xml file is much less time intensive than deploying them manually. Most of the large bundled open-source programs have created features.xml files for you, Camel being the first one that comes to mind. Unfortunately, at the time of this writing, I was unable to find one for Hibernate, so I made my own using a list of dependencies created by the good folks at Spring Source.

First, start Karaf. Then, to deploy a single OSGi bundle into Karaf, you simply need to invoke the following command (for the uninitiated "karaf@root> " is the prompt, dont' type that.)

karaf@root> osgi:install -s (uri of your bundle, eg mvn:myproject/myapp/version)


In practice, the uri can be anything that can be resolved: a maven URI, a url, or even some file on your local file-system! Once you've typed that, Karaf will print out the name of the bundle you installed on the command-line. Alternatively, you could find out the bundle number of the bundle you installed by typing:


karaf@root> osgi:list grep (bundle symbolic name)



That will give you the number of the bundle as it is installed in Karaf. Finally, you start the bundle by typing:




karaf@root> osgi:start (bundle Id number)


A bundle can have a number of states, it can be Installed, Active, or Active and Failed. What you want is for your bundles to be Active. Usually, anything else is a problem. This is what you'd type to install and start an OSGi bundle from a maven repository:

kara@root> osgi:install mvn:org.dom4j/com.springsource.org.dom4j/1.6.1
89
karaf@root> osgi:start 89


Now, imagine if you have 90 bundles in your application, including all of the dependencies. That's a lot of typing! A features.xml does all that heavy lifting for you. The features.xml file is simply an xml file where you identify a given feature, and then define the OSGi bundles and other features necessary for that feature to work inside of Karaf.

Karaf will read in the features.xml file, and when you install a feature, it will automatically download each bundle listed from its associated URI, install it as an OSGi bundle, and start it. It will do this for each bundle unless it finds a problem. If it finds a problem, it will then stop and uninstall each bundle it started. If a bundle was already installed, the Karaf will "refresh" it, and if there's a problem, it will leave it active. This is the features.xml file I wrote for Hibernate, the file is called hibernate-features-3.3.2-GA.xml.


<!--?xml version="1.0" encoding="UTF-8" ?-->
<features>
<feature name="hibernate" version="3.3.2.GA">
<bundle>mvn:org.dom4j/com.springsource.org.dom4j/1.6.1</bundle>
<bundle>mvn:org.apache.commons/com.springsource.org.apache.commons.collections/3.2.1</bundle>
<bundle>mvn:org.jboss.javassist/com.springsource.javassist/3.9.0.GA</bundle>
<bundle>mvn:javax.persistence/com.springsource.javax.persistence/1.0.0</bundle>
<bundle>mvn:org.antlr/com.springsource.antlr/2.7.7</bundle>
<bundle>mvn:net.sourceforge.cglib/com.springsource.net.sf.cglib/2.2.0</bundle>
<bundle>mvn:org.apache.commons/com/springsource.org.apache.commons.logging/1.1.1</bundle>
<bundle>mvn:javax.xml.stream/com.springsource.javax.xml.stream/1.0.1</bundle>
<bundle>mvn:org.objectweb.asm/com.springsource.org.objectweb.asm/1.5.3</bundle>
<bundle>mvn:org.objectweb.asm/com.springsource.org.objectweb.asm.attrs/1.5.3</bundle>
<bundle>mvn:org.hibernate/com.springsource.org.hibernate/3.3.2.GA</bundle> <bundle>mvn:org.hibernate/com.springsource.org.hibernate.annotations/3.3.1.ga</bundle>
<bundle>mvn:org.hibernate/com.springsource.org.hibernate.annotations.common/3.3.0.ga</bundle>
<bundle>mvn:org.hibernate/com.springsource.org.hibernate.ejb/3.3.2.GA</bundle>
</feature>
</features>


Now, copy that bad-boy into an editor, and save it in your ${karaf-home}/etc directory. Once that's done, you'll be ready for the next step.

We can make Karaf aware of this features.xml file manually by typing:


karaf@root> features:installUrl file:///home/myname/apache-felix-karaf-2.2.1/etc/features/hibernate-features-3.3.2-GA.xml


To verify your new features.xml file is installed, type

karaf@root> features:listUrl


If you see your feature listed there, you can start your feature by typing:

karaf@root> features:install hibernate


Give it a few seconds, and when you get the prompt, if you haven't gotten any errors, you can verify that hibernate is installed by typing:


karaf@root> features:list grep hibernate


Installing your features.xml and starting your feature this way is fun, but what if you've got a ton of features to install? Manually is fun; but lets face it, it's not very sexy... If only there was a way to make Karaf aware of the features.xml on start-up? Well, there is! We just add it to the ${karaf.home}/etc/org.apache.felix.karaf.features.cfg file! This is what it will look like when you download and install karaf:

################################################################################
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.java.net/external?url=http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#################################################################################
# Comma separated list of features repositories to register by default
#
featuresRepositories=mvn:org.apache.felix.karaf/apache-felix-karaf/1.6.0/xml/features
#
# Comma separated list of features to install at startup
#
featuresBoot=ssh,management


This file is composed of two very important items for us, a list of features repositories, and also a list of the features to start up when we start Karaf. Including our features.xml file is pretty straight-forward, we simply add the uri to the end of the featuresRepositories line so that it looks like this:

featuresRepositories=mvn:org.apache.felix.karaf/apache-felix-karaf/1.6.0/xml/features,file:///home/myname/apache-felix-karaf-1.6.0/etc/hibernate-features-3.3.2-GA.xml


When I first did this I tried to put a \ character after the first comma and start each features file on its own line, but that created issues, so now I put all of my features on the same line.

When we start up Karaf, we can verify that the features file is installed by typing:


karaf@root> features:listUrl


This produces a list of each features.xml file Karaf was able to successfully read. If you don't see your features.xml file there, go look at it, there's probably an issue. Also, check out the ${karaf.home}/data/log/karaf.log file and see if any errors or exceptions were reported.

Ok, what if Hibernate is part of a larger set of applications, and you want them all to start up when you start up karaf? Well, that's not too difficult. Simply add your new feature to the featuresBoot line so it looks like this:


featuresBoot=ssh,management,hibernate


If everything works properly, when you start up Karaf, your happy new hibernate feature should be up and running and ready for some abuse!

Please let me know if this helps!

No comments:

Post a Comment