I have finally started converting the examples in my book from glassfish to JBoss-5.0.0.GA. I won't describe all the conversion steps in this blog, just JBoss features that differed from other Java EE containers, or gotchas that caught me out. I used JBoss in its standard packaging; using the default Hibernate persistence engine and the embedded Hypersonic (HSQL) relational database. In this post I'll cover chapters 2, 3 and 4. As before I avoided choosing an IDE, instead I converted the glassfish ant build scripts to run on JBoss. The conversion took the following steps: (1)Create the JBOSS_HOME environment variable that points to the JBoss installation directory. In Windows do this from the System Control panel. (2) Set the ant property jboss.home to the JBOSS_HOME environment variable in the env.properties file (3) in build.xml file modify the classpath to use JBoss directories
${jboss.home}/lib and ${jboss.home}/client
(4) in build.xml replace the glassfish asadmin tool for deployment with a simple copy of the EAR or JAR file to the
.
JNDI
The very first example in chapter 2 has a Java client running outside an application client container invoke a stateless session bean using JNDI. Because of JNDI differences, for JBoss we need to have the statement
TimeService timeService = (TimeService) ctx.lookup("ejb30.session.TimeService");
replaced by
TimeService timeService = (TimeService) ctx.lookup("TimeServiceBean/remote");
in
Client.java.
In the above example we deployed the TimeService EJB packaged in a JAR file. If the EJB is packaged in an EAR file, which is the normal case, then the JNDI lookup would be "EAR file name/ejb name/remote" for remote interfaces or "EAR file name/ejb name/local" for local interfaces. So in lab3 of chapter 2 the JNDI lookup is:
TimeService timeService = (TimeService) ctx.lookup("TimeService/TimeServiceBean/remote"); PERSISTENCE
Chapter 3 deals with persistence which entails modifying the persistence.xml file. Following examples in JBoss documentation I initially tried
<persistence> <persistence-unit name="BankService"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/DefaultDS</jta-data-source> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> </properties> </persistence-unit> </persistence>
This gave the error
<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_1_0.xsd" version="1.0"> <persistence-unit name="BankService"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/DefaultDS</jta-data-source> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> </properties> </persistence-unit> </persistence>
JBoss provides a GUI based tool, the HSQL Database Manager tool for querying tables created when persisting entities. This tool is accessed from the JBoss administrator console. To initiate the console enter
http://localhost:8080
in your web browser. Then click on the JMX Console link. This brings up the JMX Agent View screen. Then under the jboss subheading click on the database=localDB,service=Hypersonic link. On the resulting screen click on the Invoke button of the startDatabaseManager operation. This will then bring up the HSQL Database Manager window. You can then perform standard SQL queries. In lab4 of chapter 3 we use a strategy of GenerationType.AUTO to generate primary key values. In JBoss (using default Hibernate persistence engine and HSQL database) specifying a primary key generation strategy of GenerationType.AUTO will default to an IDENTITY strategy. In this case HSQL will use an identity column for generating a primary key value. If a column has not been specified as an identity column then HSQL will use the primary key column as an identity column.
O/R Mapping
In chapter 4 lab1 the Customer.toString() method was modified so that addresses and accounts are not referenced. This is because these are lazily loaded by default, and would otherwise give the run time org.hibernate.LazyInitializationException. So the following code fragment
public String toString() { return "[Customer Id =" + id + ",first name=" + firstName + ",last name=" + lastName + ", referee=" + referee + ",addresses=" + addresses + ",accounts=" + accounts + "]";
was modified to
public String toString() { return "[Customer Id =" + id + ",first name=" + firstName + ",last name=" + lastName + ", referee=" + referee + ",addresses= {not initialized}" + ",accounts= {not initialized}" + "]";
In lab2 JBoss gives a deploy error of "org.hibernate.HibernateException: cannot simultaneously fetch multiple bags." This is a known Hibernate feature when using a bag (i.e. Collection or List) for eager fetches. For example the following fragment from the customer entity: @OneToMany(mappedBy="customer", fetch=EAGER) public Collection<Account> getAccounts() { return accounts; } public void setAccounts(Collection<Account> accounts) { this.accounts = accounts; } This can be resolved by (a) adding an @IndexColumn annotation or (b) using a Set instead. (a) is a Hibernate extension to Java EE, so I used option b, Sets. That's all for this post.
Thanks for sharing this Michael!
It made things a lot easier for me who is converting from JBoss 4.0.5 to 5.0.1
//Bernhard
Posted by: Bernhard Nackdal | March 24, 2009 at 12:50 PM