Hibernate is a popular persistence engine that provides a simple, yet powerful, alternative to standard entity beans. As of JBoss 4.0.2, JBoss provides Hibernate 3 for use in applications. Prior to that, Hibernate 2 was used.
Hibernate can run in almost any application server or even outside of an application server completely. Hibernate is very simple, but when running in JBoss, you have the option of letting JBoss manage your Hibernate session as a JBoss service. This greatly simplifies the Hibernate configuration, allowing you to use Hibernate objects with minimal setup. In this chapter, you will learn how to configure Hibernate as a service for your application and you will see the simplified deployment and packaging options available.
The Hibernate MBean (org.jboss.hibernate.jmx.Hibernate) configures Hibernate as a service. It is responsible for constructing a Hibernate SessionFactory and exposing it to your application through JNDI. In addition to this, the Hibernate MBean allows you to inspect and change the configuration of the SessionFactory at run time.
In its most basic configuration, the Hibernate MBean simply needs to know the database name and dialect as well as where to bind the SessionFactory in the JNDI tree. The following sample Hibernate MBean configuration illustrates a typical minimal Hibernate configuration.
<mbean code="org.jboss.hibernate.jmx.Hibernate" name="jboss.adminguide:name=ExampleSessionFactory"> <attribute name="DatasourceName">java:/DefaultDS</attribute> <attribute name="Dialect"> org.hibernate.dialect.HSQLDialect </attribute> <attribute name="SessionFactoryName"> java:/hibernate/ExampleSessionFactory </attribute> </mbean>
The attributes shown here are:
DatasourceName: This is the JNDI name of the datasource Hibernate should use.
Dialect: This is the SQL dialect (database type) for the database being used. Any valid Hibernate dialect may be used. A few of the more commonly used dialects are:
SessionFactoryName: This is the JNDI name where the constructed SessionFactory should be bound. Here we've chosen java:/hibernate/ExampleSessionFactory. If you are deploying multiple Hibernate applications in the server, make sure to choose a unique name.
This really is a small Hibernate configuration. There are many more configuration options available. We'll look at a few of the more useful options.
Hbm2ddlAuto: This option controls the automatic creation of tables for Hibernate objects. The valid values are create, create-drop and update.
DefaultSchema: This option sets a schema or tablespace name used to qualify unqualified tablenames in generated SQL.
ShowSqlEnabled: Setting this option to true enables logging of SQL to the console.
CacheProviderClass: This option sets the second level cache provider.
DeployedTreeCacheJndiName: This sets the the JNDI name of the JBossTreeCache instance to use if using the DeployedTreeCacheProvider.
SessionFactoryInterceptor: This sets the Interceptor on the configuration.
ScanForMappingsEnabled: The Hibernate MBean normally only scans the HAR file for mapping files to be added to the configuration. When ScanForMappingsEnabled is set, Hibernate will scan the entire deployment unit (the EAR file containing the HAR file, for example) for mapping files to be deployed.
ListenerInjector: This sets a listener injector class that will be called to set Hibernate 3 listeners on a configuration. The injector class must implement the org.jboss.hibernate.ListenerInjector interface.
A full set of hibernate configuration properties is available on the MBean. Table 13.1, “The Hibernate MBean configuration properties and their corresponding property names” shows all the MBean properties that map to standard hibernate configuration properties. For more information on the hibernate configuration, and general usage see the Hibernate documentation.
Table 13.1. The Hibernate MBean configuration properties and their corresponding property names
|MBean Property||Standard Hibernate Property|
The job of the Hibernate MBean is to provide a pre-configured Hibernate session factory to your application. In the next section, you will see the options for packaging your Hibernate objects and mapping files so that they will be recognized by the Hibernate MBean.
The Hibernate MBean provides two deployment mechanisms. The first is the Hibernate Archive (HAR file). In this model, all of your Hibernate classes and mapping files are packaged in a special archive, the HAR file, that JBoss can recognize and deploy much the same way it would deploy an EJB JAR or a WAR file. The alternative to the HAR file is to simply bundle Hibernate classes and mapping files along side the other application classes, inside an EJB JAR for example. The Hibernate MBean would be seperately configured and told to search all application JARs for mapping files. Both deployment mechanisms allow you to provide Hibernate objects to your application code without performing any manual configuration or writing of the setup code normally required.
Structurally, a HAR file resembles a JBoss service archive (SAR file). The HAR file contains the Hibernate class files and a mapping files along with with the standard jboss-service.xml file containing a definition for the Hibernate MBean (see Section 13.1, “The Hibernate MBean”) configured correctly for the needs of the Hibernate application being created. The following example shows a typical jboss-service.xml file.
<server> <mbean code="org.jboss.hibernate.jmx.Hibernate" name="jboss.adminguide:name=ExampleSessionFactory"> <attribute name="DatasourceName">java:/DefaultDS</attribute> <attribute name="Dialect"> org.hibernate.dialect.HSQLDialect </attribute> <attribute name="SessionFactoryName"> java:/hibernate/ExampleSessionFactory </attribute> <attribute name="CacheProviderClass"> org.hibernate.cache.HashtableCacheProvider </attribute> <attribute name="Hbm2ddlAuto">create-drop</attribute> <attribute name="ShowSqlEnabled">true</attribute> </mbean> </server>
Notice that the jboss-service.xml file does not contain a list of the classes Hibernate is to map the way a hibernate.cfg.xml would nor do you need to manually add the Hibernate mapping files to the configuration the way you would when using a hibernate.properties file. Instead the Hibernate MBean scans the archive for .hbm.xml mapping files at deployment time and adds them to the configuration for you. Figure 13.1, “The structure of a typical HAR file” shows the layout of a typical HAR file.
The Hibernate deployer will create a configuration using all of the .hbm.xml files in the archive and bind a Hibernate SessionFactory into the JNDI tree at the appropriate location. The SessionFactory can then be used by any application in JBoss.
Hibernate archives can be deployed as top level packages or can be deployed as a component of an EAR file. Since Hibernate archives are not a standard J2EE deployment type, we need to declare them in the jboss-app.xml file of an EAR file to use them in that context. This is done with a module/har element as shown in the following example.
<!DOCTYPE jboss-app PUBLIC "-//JBoss//DTD J2EE Application 1.4//EN" "http://www.jboss.org/j2ee/dtd/jboss-app_4_0.dtd"> <jboss-app> <module> <har>chap13.har</har> </module> </jboss-app>
With this, a Hibernate archive can be deployed along side a WAR or EAR file in any EAR file.
The HAR file gives a great deal of flexibility in deployment, allowing the developer to use simple packaging to determine which hibernate objects are related to the managed session. In projects that use multiple Hibernate sessions, this is a critical feature. When only a single Hibernate session is needed, JBoss provides a deployment option that doesn't require any special packaging constructs.
Instead of searching only a local HAR file, the Hibernate MBean can instead search the entire surrounding application deployment for Hibernate classes and mapping files. This functionality is controlled by the ScanForMappingsEnabled attribute. The following Hibernate MBean definition illustrates the usage of the ScanForMappingsEnabled attribute
<server> <mbean code="org.jboss.hibernate.jmx.Hibernate" name="jboss.adminguide:name=ExampleSessionFactory"> <attribute name="DatasourceName">java:/DefaultDS</attribute> <attribute name="Dialect"> org.hibernate.dialect.HSQLDialect </attribute> <attribute name="SessionFactoryName"> java:/hibernate/ExampleSessionFactory </attribute> <attribute name="ScanForMappingsEnabled">true</attribute> </mbean> </server>
The typical deployment scenario for scanning is deploying inside of an EAR file. The Hibernate MBean would be defined in a *-service.xml file inside EAR file. A service file can be used from an EAR file by adding it to the EAR and adding a module/service entry referencing it to the jboss-app.xml deployment descriptor, as shown in the following example.
<jboss-app> <module> <service>hibernate-service.xml</service> </module> </jboss-app>
Because ScanForMappingsEnabled is set to true, the entire EAR file will be scanned for mapping files. While they can be located anywhere, the most likely place to put them would be in an EJB-JAR file inside the EAR. This is particularly convenient when session beans are used to access the hibernate objects. However, even if no EJBs are used in an application, the a JAR containing only Hibernate classes can still be deployed as an EJB-JAR. The only difference is that if no EJBs are used, there is no need to provide an ejb-jar.xml file in the EJB-JAR.
When the Hibernate archive is deployed, the Hibernate objects are made available to other applications through the provided SessionFactory. There are several ways to use it.
Since the session factory is bound into JNDI, it is possible to simply look it up and manually create a Hibernate session. The following code does just that.
InitialContext ctx = new InitialContext(); SessionFactory factory = (SessionFactory) ctx.lookup("java:/hibernate/ExampleSessionFactory"); Session hsession = factory.openSession();
This requires manual management of the session the Hibernate transaction and may be useful for migrating existing Hibernate code into JBoss. However, in the context of a larger J2EE application, you'll likely want your Hibernate objects to take part in an existing JTA transaction. This would be the normal case if you wanted to access Hibernate objects in a session bean, for example.
JBoss provides the org.jboss.hibernate.session.HibernateContext class as the integration piece that does this. The getSession method returns a Hibernate session that is linked to the current JTA transaction. Naturally this requires that a JTA transaction exist prior to the call. The following code illustrates the use of getSession.
Session hsession = HibernateContext.getSession("java:/hibernate/ExampleEmptorSessionFactory");
When you get the Hibernate session in this manner, you don't need close the Hibernate session or manage a hibernate transaction. You can be sure that all access to the Hibernate session from the current transaction will see the same state, and you can know that your Hibernate access will be committed to the database or rolled back along with the larger JTA transaction.