Combining Hibernate and Facelets with Maven, Netbeans and GlassFish

Over the past weeks I have been exploring the possibilities of Maven, Netbeans and GlassFish. Two of my previous blog entries explain the basics of using Maven in Netbeans and how to deploy to GlassFish. By default, GlassFish uses Toplink Essentials for JPA. Also, Netbeans by default uses jsp files for web pages. In this article I will explain how to use Hibernate for JPA and Facelets for JSF.

In this article I will assume that you have created a simple enterprise application as explained in my article “Building Enterprise Applications for GlassFish using Netbeans 6.0“. If you haven’t followed those stpes then I suggest you do now so you can follow the stpes in this article more easily. Please note that Netbeans 6.0 RC1 has been released now. This version contains a newer version of the MevenIDE Maven plugin which solves some of the issues I described in my previous articles.

Moving to Hibernate

In order to use container managed JPA with Hibernate, some jar files need to be copied over to the lib directory inside the GlassFish install directory. There are several ways to obtain these jar files. One way is to go to the Hibernate downloads page and download both Hibernate Core (current version: 3.2.5.ga) and Hibernate EntityManager (current version: 3.3.1.GA), or download all individual jars from the Apache Maven repository. I chose the latter way because during preparing for this article I ended up downloading all jars via Maven to my local repository anyway. In the end, according to this Netbeans article, these jar files are needed

From Hibernate Core

  • antlr-2.7.7.jar
  • asm-1.5.3.jar
  • asm-attrs-1.5.3.jar
  • c3p0-0.9.1.jar
  • cglib-2.1_3.jar
  • commons-collections-2.1.1.jar
  • commons-logging-1.1.jar
  • concurrent-1.3.4.jar
  • dom4j-1.6.1.jar
  • ehcache-1.2.3.jar
  • hibernate-3.2.5.ga.jar
  • javassist-3.3.ga.jar

From Hibernate EntityManager

  • hibernate-entitymanager-3.3.1.ga.jar
  • hibernate-annotations-3.3.0.ga.jar
  • hibernate-commons-annotations-3.3.0.ga.jar
  • hibernate-validator-3.0.0.ga.jar
  • jboss-archive-browsing-5.0.0alpha-200607201-119.jar

Please note that the versions specified here are the latest ones from the Apache Maven Repository. The versions in the downloads from hibernate.org vary slightly. Also, I didn’t include Log4J which has lead to no problems so far.

Now, switching from Toplink Essentials to Hibernate is easy. In the pom.xml file for the EJB project, remove all dependencies for Toplink Essentials and replace them with

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-annotations</artifactId>
            <version>3.3.0.ga</version>
            <optional>true</optional>
            <exclusions>
                <exclusion>
                    <groupId>org.hibernate</groupId>
                    <artifactId>hibernate</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

The only reason that hibernate-annotations is needed here is to make the entity classes compile. If hibernate is not included in the exclusions list, Maven will download it and then complain about javax.transactions.jta-1.0.1B.jar missing. Since hibernate is not needed for compilation, excluding it is the easiest way of preventing Maven to mess up our dependencies. Another way of setting up the dependencies is to include hibernate-3.2.5.ga.jar and then include jta in the excludes list.

Besides that, our persistence unit needs to be modified so it will use Hibernate as persistence provider and not Toplink Essentials. To make this happen, modify persistence.xml and add this line

<provider>org.hibernate.ejb.HibernatePersistence</provider>

Redeploy the project and witness Hibernate do its job:

deployed with moduleid = MavenEnterpriseApplication-ear-1.0-SNAPSHOT
Processing PersistenceUnitInfo [
        name: MavenEnterpriseApplication-ejbPU
        ...]
found EJB3 Entity bean: nl.amis.maven.enterprise.ejb.persistence.Jobs
found EJB3 Entity bean: nl.amis.maven.enterprise.ejb.persistence.Departments
found EJB3 Entity bean: nl.amis.maven.enterprise.ejb.persistence.Countries
found EJB3 Entity bean: nl.amis.maven.enterprise.ejb.persistence.Employees
found EJB3 Entity bean: nl.amis.maven.enterprise.ejb.persistence.Locations
found EJB3 @Embeddable: nl.amis.maven.enterprise.ejb.persistence.JobHistoryPK
found EJB3 Entity bean: nl.amis.maven.enterprise.ejb.persistence.JobHistory
found EJB3 Entity bean: nl.amis.maven.enterprise.ejb.persistence.Regions
Binding entity from annotated class: nl.amis.maven.enterprise.ejb.persistence.Jobs
...

Adding Facelets support

The Web module that was created in my first article depended on a servlet to prove that the EJB module was doing it’s job properly. But servlets are old fashioned and many people are using JavaServer Faces nowadays to build shiny web applications. A JSF implementation that is rapidly gaining momentum is Facelets. Instead of usings jsps for web pages, it uses xhtml files. Some of the benefits of using Facelets and xhtml over jsp can be found in this weblog article.

Since Facelets uses JSF tags, we need to enable JSF in our project. Before we do so, please first remove the servelt since we will no longer need it. If you expand the Source Packages node, select the servlet and hit the Delete button, you will be asked if Netbeans should safely delete the servlet. doing so will also clean up the web.xml file, so make sure to delete the servlet in this way. Next, open the pom.xml file and replace the servlet-api dependency by

        <dependency>
            <groupId>com.sun.facelets</groupId>
            <artifactId>jsf-facelets</artifactId>
            <version>1.1.14</version>
        </dependency>

Please note that resolving this dependency will only succeed if the java.net repository at http://download.java.net/maven/1 has been added to the pom.xml file. Since we already did this in the Parent Pom Project pom.xml file, Maven should be able to download the facelets jar.

Configuring Facelets and JSF

Next we need a faces-config.xml file. Expand the Web Pages node and then the WEB-INF node. Next right click the WEB-INF node and select New ->  XML Document. If XML Document cannot be selected from the list, select Other and then search for XML document under the XML node. Name the new file “faces-config” (without the quotes, but also without the .xml extension) and finish the wizard. Replace the entire contents of the file with this

<faces-config version="1.2"
              xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
    <application>
        <view-handler>
            com.sun.facelets.FaceletViewHandler
        </view-handler>
    </application>
</faces-config>

Note that the necessary lines to initiate and use the FaceletViewHandler already have been added. Next some modifications need to be made to web.xml for Facelets to operate correctly. I suggest you now add these lines to web.xml

    <!-- Use Documents Saved as *.xhtml -->
    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.xhtml</param-value>
    </context-param>

    <!-- Special Debug Output for Development -->
    <context-param>
        <param-name>facelets.DEVELOPMENT</param-name>
        <param-value>true</param-value>
    </context-param>

    <!-- Faces Servlet -->
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Faces Servlet Mapping -->
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>

Basically, these lines specify that our JSF pages should have the .xhtml suffix, that we’d like to get some Facelets debugging output, what class our Faces Servlet is and which URL pattern should be caught by that Faces servlet. In short, browsing to, say, http://localhost:8280/MavenEnterpriseApplication-war/index.jsf will make the Facelets servlet process index.xhtml and render its output.

Add a backing bean

Before we add a Facelets page we need a backing bean to fetch data from our local session bean. This bean will fetch the number of Employees in our company from the local session bean and provide a getter for our future Facelets page. a very dull application, but it suffices for the purpose of this article. This bean simply could look like this

package nl.amis.maven.jsf.beans;

import javax.ejb.EJB;
import nl.amis.maven.enterprise.ejb.session.DataLocal;

public class NumberBackingBean {
    private int numberOfEmployees;

    @EJB DataLocal dataLocal;

    public int getNumberOfEmployees() {
        return dataLocal.countEmployees();
    }

    public void setNumberOfEmployees(int numberOfEmployees) {
        this.numberOfEmployees = numberOfEmployees;
    }

}

These lines in faces-config.xml will register the bean in the JSF context

    <managed-bean>
        <managed-bean-name>NumberBackingBean</managed-bean-name>
        <managed-bean-class>nl.amis.maven.jsf.beans.NumberBackingBean</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>

these lines tell JSF to initiate and make available an instance of nl.amis.maven.jsf.beans.NumberBackingBean under the name NumberBackingBean.

Add a Facelets page

Facelets pages can be very simple, or very complex. In this case, we will create a simple Facelets page. The idea is to invoke the getNumberOfEmployees method in our NumberBackingBean bean and display the return value in a browser. Create a new XHTML file by right clicking the Web Pages node and selecting New -> Other. The XHTML type can be found under the Web node. Simply name the file “index” (without quotes and without the .xhtml extension) and make sure it gets created in the src/main/webapp directory in your project. Replace the contents of the file with

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html">
    <body>
        The number of Employees is #{NumberBackingBean.numberOfEmployees}.<br/>
    </body>
</html>

Finally, Clean and Build your application and then execute the exec:exec goal on the EAR module. Browse to e.g. http://localhost:8280/MavenEnterpriseApplication-war/index.jsf and see something like this:

Combining Hibernate and Facelets with Maven, Netbeans and GlassFish gf mvn nb6 result in facelets page

Conclusion

Setting up Hibernate and Facelets with Maven isn’t very hard. For me, the hardest part was to figure out what Maven repository to use. JBoss have their own repository at http://repository.jboss.com/maven2/ but jars for e.g. hibernate can be found at several places and the latest versions seem to be missing. If anyone can tell me the use of this repository then please drop me a line.

My next goal will be to be able to build Seam projects with Maven in Netbeans and deploy them to Glassfish. Stay tuned!

6 Comments

  1. Wouter van Reeven November 23, 2007
  2. David R. Heffelfinger November 23, 2007
  3. Wouter van Reeven November 23, 2007
  4. David R. Heffelfinger November 23, 2007
  5. Amit November 22, 2007
  6. Matthias Wessendorf November 22, 2007