Very Simple EAR with HibernateGetting Hibernate to work inside an application server can be a bit confusing. Here is a short description of how we modified a JOnAS example application (the "Alarm" sample) to use Hibernate in place of CMP entity beans. The "Alarm" sample - http://jonas.objectweb.org/doc/tutorial/src/html/alarm.html#N10E80 - uses a stateless session bean, an entity bean, and some message-driven beans (along with a servlet frontend including some message-sending code) to illustrate message handling and database persistence. The Alarm example is meant to illustrate receiving notifications from systems in trouble. An alarm has a "source device", a message, and a severity level. As alarms arrive, they are logged in an AlarmTable database table, and AlarmData objects (POJOs) are created and saved in the session layer. The persistence of the AlarmData objects is handled via an AlarmRecord entity bean. Our goal was to remove this AlarmRecord entity bean, and persist the AlarmData objects directly in the AlarmTable with Hibernate. The source archive of our converted example can be found at http://www.unrealities.com/hibernate/JOnAS_alarm_example_hibernate.zip -- it has not been tested by anyone other than us as yet (as of 16 Jan 2004) so if you try it, update this page! :-) (Most of the steps in this example will apply to any app server -- there is not much JOnAS-specific knowledge required here, beyond the vendor-specific deployment information. But for concreteness, we will describe what we did to this specific example.) First, of course, we got the sample itself working, by putting the MySQL driver in {%JONAS_ROOT%}/lib/ext and configuring a data source with JNDI name "jdbc_1". (We used MySQL in our testing.) We'll not describe that process further since the JOnAS example documentation covers it. We placed the following Hibernate libraries in {%JONAS_ROOT%}/lib/ext:
- cglib2.jar
- commons-collections.jar
- commons-logging.jar
- dom4j.jar
- ehcache.jar
- hibernate2.jar
- odmg.jar
- xalan.jar
We deleted the AlarmRecord.java, AlarmRecordBean.java, and AlarmRecordHome.java files, and commented out all deployment descriptor sections that referred to them. Chop that entity bean right out! We defined a Hibernate mapping file for the AlarmData class:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="com.nimblefish.alarm.beans.AlarmData" table="AlarmTable">
<!--
dbpk varchar(12) not null primary key, dbsev integer, dbfrom varchar(12), dbreason varchar(30),
dbcount integer, dbstate integer, dbdate date
-->
<id name="num" type="string" unsaved-value="null" >
<column name="dbpk" sql-type="varchar(12)" not-null="true"/>
<!-- we will generate them ourselves for now.... -->
<generator class="assigned"/>
<!-- <generator class="uuid.hex"/> -->
</id>
<property name="sev">
<column name="dbsev" sql-type="int" not-null="true"/>
</property>
<property name="device">
<column name="dbfrom" sql-type="varchar(12)" not-null="true"/>
</property>
<property name="message">
<column name="dbreason" sql-type="varchar(30)"/>
</property>
<property name="count">
<column name="dbcount" sql-type="int"/>
</property>
<property name="state">
<column name="dbstate" sql-type="int"/>
</property>
<property name="date">
<column name="dbdate" sql-type="date"/>
</property>
</class>
</hibernate-mapping>
Note that this maps the AlarmData object to the AlarmTable exactly as it was defined in the original example. We then revised the AlarmManager and Profil classes (which together provide a facade hiding the persistence details) to use Hibernate rather than the (now defunct) AlarmRecord class. We defined a new class PersistenceManager to act as a singleton location for obtaining the Hibernate SessionFactory. (We had no luck in loading Hibernate properties from the classpath, for reasons unknown, so we hardcoded the Hibernate configuration details in PersistenceManager.java. You will likely need to change these configuration parameters to work in your environment, should you try to run this sample.) Finally, we revised the build.xml file to include AlarmData.hbm.xml in the ejbjar. We also added some build.xml tasks to deploy directly into JOnAS ("ant deploy") which greatly sped up our debugging. (In the course of doing this, we rearranged the message bean classes to support our experiments, and we renamed a number of the packages to "com.nimblefish" since that is the company we work for. This is not to indicate that we have ownership of the original code! These other changes are irrelevant to the Hibernate use of this example, but we do not have the time to reverse them. Hopefully it will not add undue confusion.) The example runs for us under JOnAS 3.3.1 and Hibernate 2.1.1. You must install and exercise the original example before you give our modified one a try -- this is both to ensure that you have your JOnAS/database setup correct, and to initialize your database properly! (The original example creates AlarmTable if it does not yet exist, but our modified example does not and will fail if AlarmTable is not created. See the readme.txt in the root of the .zip.) Even if you do not use JOnAS, hopefully you will be able to glean some sense of how to use Hibernate in your EARs from comparing this example to the original example in the JOnAS distribution. Our best regards to all J2EE (and especially JOnAS and Hibernate) developers! See you on the forums :-) Cheers! RobJellinghaus
|