Glassfish provides TopLink as its default JPA provider. However it’s possible for applications to instead use Hibernate within a Glassfish deployment. The challenge is to determine where to install the Hibernate libraries so that the application references Hibernate instead of TopLink. While googling for an answer I saw several recommendations suggesting that the Hibernate libraries be installed within Glassfish’s server lib directory, thereby in essence removing TopLink and replacing it with Hibernate.
Although installing Hibernate directly within Glassfish’s server lib directory will accomplish the goal, it isn’t the best solution in that this affects every application at a global level. Instead the following solution scopes the selection of JPA provider to that of an individual application, effectively isolating it so that its architecture choices don’t affect that of other applications.
The solution is to include the Hibernate libraries directly within the application’s EAR as shown in the following image:
Simply including the Hibernate JARs in the same directory as the application’s component WARs won’t work – Glassfish won’t recognize the Hibernate JARs. Instead we have to store the Hibernate JARs within the EAR’s “lib” directory so that Glassfish loads the Hibernate JARs into the application’s individual classloader. See the chapter titled “Class Loader Hierarchy” within the Glassfish Application Development Guide for a good explanation of the Glassfish classloader hierarchy.
If you look closely at the above EAR layout you’ll notice that I’ve packaged our application’s persistent object layer – a separate development project – into its own JAR file (persistence-0.1.0.jar). By doing so we can use JUnit to verify that the persistence layer works properly separate from the application. The following image shows a screen snapshot of the persistence project within Eclipse, including the Maven POM file that includes the various Hibernate libraries (click image for full size):
We also have to update the application’s persistence.xml file (shown below). Line 5 instructs Glassfish that Hibernate should be used instead of Toplink as the chosen JPA provider. In line 6 Hibernate is configured to use the JTA-managed data source we installed using the Glassfish admin console. Line 8 informs Hibernate that MySQL has been chosen as our back-end SQL database. Finally Line 12 ties Hibernate into Glassfish’s container-managed transactions so that the database is rolled back if a transaction fails. Note that this file is one place where we have to include Glassfish-specific information in our application.
<persistence 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_2_0.xsd" version="2.0">
<persistence-unit name=”debatePU” transaction-type=”JTA”>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/debateDS</jta-data-source>
<properties>
<property name=”hibernate.dialect” value=”org.hibernate.dialect.MySQLDialect” />
<!– GLASSFISH SPECIFIC: The following property is necessary for
deployment within Glassfish. Note that each application
server vendor has its own unique value. –>
<property name=”hibernate.transaction.manager_lookup_class” value=”org.hibernate.transaction.SunONETransactionManagerLookup” />
</properties>
</persistence-unit>
</persistence>
Once we have the persistent object model packaged into a JAR file, the next step is to build the application’s EAR file. Fortunately there is a Maven setting for easily creating an EAR lib directory to contain the application’s third-party libraries. The following is the Maven POM file we use to build our application’s EAR. Of special interest is the setting at the file’s end instructing Maven to build the EAR lib directory.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>debate</artifactId>
<groupId>com.snlb.debate</groupId>
<version>0.1.0</version>
</parent>
<groupId>com.snlb.debate</groupId>
<artifactId>earglassfish</artifactId>
<version>0.1.0</version>
<packaging>ear</packaging>
<dependencies>
<dependency>
<groupId>com.snlb.debate</groupId>
<artifactId>business</artifactId>
<version>0.1.0</version>
<type>ejb</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.snlb.debate</groupId>
<artifactId>uibrowser</artifactId>
<version>0.1.0</version>
<type>war</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.snlb.debate</groupId>
<artifactId>uiphone</artifactId>
<version>0.1.0</version>
<type>war</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.snlb.debate</groupId>
<artifactId>serviceweb</artifactId>
<version>0.1.0</version>
<type>war</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.snlb.debate</groupId>
<artifactId>servicerest</artifactId>
<version>0.1.0</version>
<type>war</type>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.4.2</version>
<configuration>
<displayName>Debate</displayName>
<modules>
<ejbModule>
<groupId>com.snlb.debate</groupId>
<artifactId>business</artifactId>
</ejbModule>
<webModule>
<groupId>com.snlb.debate</groupId>
<artifactId>uibrowser</artifactId>
</webModule>
<webModule>
<groupId>com.snlb.debate</groupId>
<artifactId>uiphone</artifactId>
</webModule>
<webModule>
<groupId>com.snlb.debate</groupId>
<artifactId>serviceweb</artifactId>
</webModule>
<webModule>
<groupId>com.snlb.debate</groupId>
<artifactId>servicerest</artifactId>
</webModule>
</modules>
<generateApplicationXml>true</generateApplicationXml>
<!– The following setting builds the EAR file in a format suitable for Glassfish deployment.
With this we don’t have to copy the libs into Glassfish’s appserver lib directory –>
<defaultLibBundleDir>lib</defaultLibBundleDir>
</configuration>
</plugin>
</plugins>
</build>
</project>