The justification of Hibernate was definitely maturity. It's much faster that EclipseLink/Toplink and definitely less buggy. I've had too many problems with Toplink to ever willingly use it again where I have a better option. To get Hibernate integrated into Geronimo wasn't easy though. It's the first time I use Geronimo to this degree. Previously I just ported a small project to Geronimo which had nothing more than a JMS queue and an MDB. To get Hibernate running in Geronimo isn't difficult, though I didn't know how, and thus struggled a bit. So this entry will be my second one describing how to use a specific persistence framework in OpenEJB.
Deploying Hibernate in Geronimo
The basic idea on using Hibernate is too deploy the dependencies and setup a special transaction manager. This explanation was based on Hibernate 3.3. So first get hold of:
- Hibernate Distribution 3.3.2
- Hibernate Annotations 3.4.0, and
- Hibernate EntityManager 3.4.0
- Hibernate Distribution
- hibernate3.jar
- lib/required/antlr-2.7.6.jar
- lib/required/commons-collections-3.1.jar
- lib/required/dom4j-1.6.1.jar
- lib/required/javassist-3.9.0.GA.jar
- lib/required/jta-1.1.jar
- lib/required/slf4j-api-1.5.8.jar
- Hibernate Annotations
- hibernate-annotations.jar
- lib/ejb3-persistence.jar
- lib/hibernate-commons-annotations.jar
- lib/slf4j-api.jar
- Hibernate EntityManager
- hibernate-entitymanager.jar
- Start a new Java Class Library project and call it GeronimoTransactionManager.
- Create a class "org.hibernate.transaction.GeronimoTransactionManagerLookup".
- Paste the following code into this new class.
package org.hibernate.transaction;
import java.util.Properties;
import java.util.Set;
import javax.transaction.TransactionManager;
import org.apache.geronimo.gbean.AbstractName;
import org.apache.geronimo.gbean.AbstractNameQuery;
import org.apache.geronimo.kernel.Kernel;
import org.apache.geronimo.kernel.KernelRegistry;
import org.hibernate.HibernateException;
import org.hibernate.transaction.TransactionManagerLookup;
public class GeronimoTransactionManagerLookup implements TransactionManagerLookup
{
public static final String UserTransactionName = "java:comp/UserTransaction";
public TransactionManager getTransactionManager(Properties props) throws HibernateException
{
try
{
Kernel kernel = KernelRegistry.getSingleKernel();
AbstractNameQuery query = new AbstractNameQuery(TransactionManager.class.getName());
Set<AbstractName> names = kernel.listGBeans(query);
if (names.size() != 1)
{
throw new IllegalStateException("Expected one transaction manager, not " + names.size());
}
AbstractName name = names.iterator().next();
TransactionManager transMg = (TransactionManager) kernel.getGBean(name);
return (TransactionManager) transMg;
}
catch (Exception e)
{
e.printStackTrace();
System.out.println();
throw new HibernateException("Geronimo Transaction Manager Lookup Failed", e);
}
}
public String getUserTransactionName()
{
return UserTransactionName;
}
} - Then under the project's properties, make sure "JDK 5" is selected in the "Source/Binary Format" drop down on the "Sources" property page.
- Before closing the project properties dialog, goto Libraries and add all the Hibernate JAR files we listed above to your classpath by clicking the "Add JAR/Folder" button and selecting all of them. If you are using Netbeans you might already have a "Hibernate JPA" library configured in the IDE, so in this case you can instead click the "Add Library" button and select "Hibernate JPA" from the list. We only need the our class to compile against Hibernate, so it doesn't matter if you don't use the exact version we will be deploying into Geronimo. As long as the API is the same, you should be able to safely compile against any Hibernate 3.3 JARs.
- Then you need to add one more JAR as a library. This will be the Geronimo kernel jar, which you can find in the Geronimo distribution directory under: repository/org/apache/geronimo/framework/geronimo-kernel/2.1.4/geronimo-kernel-2.1.4.jar
- Confirm the properties dialog by pressing the "OK" button.
- Now build the project and find the GeronimoTransactionManager.jar file in the project's "dist" directory.
- This is the JAR we will use when adding repository resources to Geronimo in the next step, so put it with the rest of the Hibernate JAR files you collected above.
- hibernate3.jar - hibernate/core/3.3/jar
- lib/required/antlr-2.7.6.jar - hibernate/antlr/2.7.6/jar
- lib/required/commons-collections-3.1.jar - hibernate/commons-collections/3.1/jar
- lib/required/dom4j-1.6.1.jar - hibernate/dom4j/1.6.1/jar
- lib/required/javassist-3.9.0.GA.jar - hibernate/javassist/3.9.0.GA/jar
- lib/required/jta-1.1.jar - hibernate/jta/1.1/jar
- hibernate-annotations.jar - hibernate/annotations/3.4/jar
- lib/ejb3-persistence.jar - hibernate/jpa/3.0/jar
- lib/hibernate-commons-annotations.jar - hibernate/commons-annotations/3.4/jar
- hibernate-entitymanager.jar - hibernate/entitymanager/3.4/jar
- GeronimoTransactionManager.jar - hibernate/GeronimoTransactionManager/1.0/jar
- Create a JDBC pool through the Geronimo console (in this example called: console.dbpool/jdbc_myDatabasePool/1.0/rar)
- List the following dependencies in your EJB project's deploy plan (geronimo-ejb.xml):
- Your JDBC pool
- All the Hibernate dependencies we added above
- Geronimo's "slf4j-api" dependency in your deploy plan.In Geronimo 2.1.4 it's called: org.slf4j/slf4j-api/1.4.3/jar
<?xml version="1.0" encoding="UTF-8"?>
<openejb-jar xmlns="http://openejb.apache.org/xml/ns/openejb-jar-2.2"
xmlns:naming="http://geronimo.apache.org/xml/ns/naming-1.2"
xmlns:sec="http://geronimo.apache.org/xml/ns/security-2.0"
xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2">
<dep:environment>
<dep:moduleId>
<dep:groupId>user</dep:groupId>
<dep:artifactId>MyHibernateEJB</dep:artifactId>
<dep:version>1.0</dep:version>
<dep:type>jar</dep:type>
</dep:moduleId>
<dep:dependencies>
<dep:dependency>
<dep:groupId>console.dbpool</dep:groupId>
<dep:artifactId>jdbc_myDatabasePool</dep:artifactId>
<dep:version>1.0</dep:version>
<dep:type>rar</dep:type>
</dep:dependency>
<dep:dependency>
<dep:groupId>hibernate</dep:groupId>
<dep:artifactId>core</dep:artifactId>
<dep:version>3.3</dep:version>
<dep:type>jar</dep:type>
</dep:dependency>
<dep:dependency>
<dep:groupId>hibernate</dep:groupId>
<dep:artifactId>annotations</dep:artifactId>
<dep:version>3.4</dep:version>
<dep:type>jar</dep:type>
</dep:dependency>
<dep:dependency>
<dep:groupId>hibernate</dep:groupId>
<dep:artifactId>antlr</dep:artifactId>
<dep:version>2.7.6</dep:version>
<dep:type>jar</dep:type>
</dep:dependency>
<dep:dependency>
<dep:groupId>hibernate</dep:groupId>
<dep:artifactId>commons-annotations</dep:artifactId>
<dep:version>3.4</dep:version>
<dep:type>jar</dep:type>
</dep:dependency>
<dep:dependency>
<dep:groupId>hibernate</dep:groupId>
<dep:artifactId>commons-collections</dep:artifactId>
<dep:version>3.1</dep:version>
<dep:type>jar</dep:type>
</dep:dependency>
<dep:dependency>
<dep:groupId>hibernate</dep:groupId>
<dep:artifactId>dom4j</dep:artifactId>
<dep:version>1.6.1</dep:version>
<dep:type>jar</dep:type>
</dep:dependency>
<dep:dependency>
<dep:groupId>hibernate</dep:groupId>
<dep:artifactId>entitymanager</dep:artifactId>
<dep:version>3.4</dep:version>
<dep:type>jar</dep:type>
</dep:dependency>
<dep:dependency>
<dep:groupId>hibernate</dep:groupId>
<dep:artifactId>javassist</dep:artifactId>
<dep:version>3.9.0.GA</dep:version>
<dep:type>jar</dep:type>
</dep:dependency>
<dep:dependency>
<dep:groupId>hibernate</dep:groupId>
<dep:artifactId>jpa</dep:artifactId>
<dep:version>3.0</dep:version>
<dep:type>jar</dep:type>
</dep:dependency>
<dep:dependency>
<dep:groupId>hibernate</dep:groupId>
<dep:artifactId>jta</dep:artifactId>
<dep:version>1.1</dep:version>
<dep:type>jar</dep:type>
</dep:dependency>
<dep:dependency>
<dep:groupId>hibernate</dep:groupId>
<dep:artifactId>GeronimoTransactionManager</dep:artifactId>
<dep:version>1.0</dep:version>
<dep:type>jar</dep:type>
</dep:dependency>
<dep:dependency>
<dep:groupId>org.slf4j</dep:groupId>
<dep:artifactId>slf4j-api</dep:artifactId>
<dep:version>1.4.3</dep:version>
<dep:type>jar</dep:type>
</dep:dependency>
</dep:dependencies>
</dep:environment>
</openejb-jar> - Specify the transaction manager in your persistence.xml. Here is an example. Note how the JTA data source is specified by only using the artifact ID of the pool you created, with any underscore (_) characters replaced with a "/". This is how Geronimo maps repository resource's module IDs to JNDI names.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="MyHibernateEJB-PU" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/myDatabasePool</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.GeronimoTransactionManagerLookup"/>
</properties>
</persistence-unit>
</persistence> - And deploy your EJB.
2 comments:
thanks for the awesome article. just one question tough; when i implement TransactionManagerLookup interface, i am expected to provide a method called getTransactionIdentifier. i'm guessing that the geronimo 2.2 kernel change is responsible, but since i don't know what these are all about, i have no idea how to implement it. any suggestions for me to go after?
I recall running into the same problem with Geronimo 2.2. It accepts a parameter of type "Transaction" and you can simply return this same parameter. So something like the following should work:
public Object getTransactionIdentifier(Transaction tx)
{
return tx;
}
It's a new method added to the Hibernate API, used mainly for lookups/caching purposes, and since these lookups should generally be very unique a reference to the transaction itself works perfectly well.
Using an older version of Hibernate is another way of getting around it. According to the documentation, it was mainly added for use in servers they refer to as "Unfriendly JEE containers" like WebSphere. Exactly for what I can't say, and neither can I recall in which version of Hibernate it was added. It sounds very specific so I guess it's only intended for WebSphere.
Post a Comment