Sample JSF-EJB3 Application

Sample JSF-EJB3 Application

Data Model
JSF Web Pages
EJB3 Session Beans
Configuration and Packaging
Building The Application
Configuration Files
The Database
Creating the Database Schema
The HSQL Database Manager Tool
Deploying the Application

We use a simple "TODO" application to show how JSF and EJB3 work together in a web application. The "TODO" application works like this: You can create a new 'todo' task item using the  "Create" web form. Each 'todo' item has a 'title' and a 'description'. When you submit the form, the application saves your task to a relational database. Using the application, you can view all 'todo' items, edit/delete an existing 'todo' item and update the task in the database.

The sample application comprises the following components:

  • Entity objects - These objects represent the data model; the properties in the object are mapped to column values in relational database tables.

  • JSF web pages - The web interface used to capture input data and display result data. The data fields on these web pages are mapped to the data model via the JSF Expression Language (EL).

  • EJB3 Session Bean - This is where the functionality is implemented. We make use of a Stateless Session Bean.

Data Model

Let's take a look at the contents of the Data Model represented by the Todo class in the Todo.java file. Each instance of the Todo class corresponds to a row in the relational database table. The 'Todo' class has three properties: id, title and description. Each of these correspond to a column in the database table.

The 'Entity class' to 'Database Table' mapping information is specified using EJB3 Annotations in the 'Todo' class. This eliminates the need for XML configuration and makes it a lot clearer. The @Entity annotation defines the Todo class as an Entity Bean. The @Id and @GeneratedValue annotations on the id property indicate that the id column is the primary key and that the server automatically generates its value for each Todo object saved into the database.

@Entity
public class Todo implements Serializable {

  private long id;
  private String title;
  private String description;

  public Todo () {
    title ="";
    description ="";
  }

  @Id @GeneratedValue

  public long getId() { return id;}
  public void setId(long id) { this.id = id; }

  public String getTitle() { return title; }
  public void setTitle(String title) {this.title = title;}

  public String getDescription() { return description; }

  public void setDescription(String description) {
    this.description = description;
  }

}

JSF Web Pages

In this section we will show you how the web interface is defined using JSF pages. We will also see how the data model is mapped to the web form using JSF EL. Using the #{...} notation to reference Java objects is called JSF EL (JSF Expression Language). Lets take a look at the pages used in our application:

  • index.xhtml : This page displays two options: 1. Create New Todo 2. Show all      Todos. When you click on the Submit button the corresponding action      is invoked.

    <h:form>
    <ul>
      <li><h:commandLink type="submit" value="Create New Todo" action="create"/></li>
    
      <li><h:commandLink type="submit" value="Show All Todos" action="todos"/></li>
    </ul>
    </h:form>
  • create.xhtml : When you try to create a new task, this JSF page captures the      input data. We use the todoBean to back the form input text fields. The #{todoBean.todo.title} symbol refers to the "title" property of the "todo" object in the "TodoBean" class. The #{todoBean.todo.description} symbol refers to the "description" property of the "todo" object in the "TodoBean"      class. The #{todoBean.persist} symbol refers to the "persist" method in the "TodoBean" class. This method creates the      "Todo" instance with the input data (title and description) and persists the data.

    <h:form id="create">
    <table>
      <tr>
        <td>Title:</td>
        <td>
    
          <h:inputText id="title" value="#{todoBean.todo.title}" size="15">
            <f:validateLength minimum="2"/>
          </h:inputText>
    
        </td>
      </tr>
      <tr>
        <td>Description:</td>
        <td>
    
          <h:inputTextarea id="description" value="#{todoBean.todo.description}">
            <f:validateLength minimum="2" maximum="250"/>
          </h:inputTextarea>
    
        </td>
      </tr>
    </table>
    <h:commandButton type="submit" id="create" value="Create"
    
                     action="#{todoBean.persist}"/>
    </h:form>

    The "Create Todo" web page ” shows the "Create Todo" web page with the input fields mapped to the data model.

    The "Create Todo" web page

     

  • todos.xhtml : This page displays the list of all "todos" created.      There is also an option to choose a "todo" item for 'edit'      or 'delete'.

    The list of all 'todos' is fetched by      #{todoBean.todos} symbol referring to the 'getTodos()' property in      the 'TodoBean' class. The JSF dataTable iterates through the list and displays each Todo object in a row. The 'Edit' option is available across each row. The      #{todo.id} symbol represents the "id" property of the      "todo" object.

    <h:form>
    <h:dataTable value="#{todoBean.todos}" var="todo">
      <h:column>
        <f:facet name="header">Title</f:facet>
        #{todo.title}
    
      </h:column>
      <h:column>
        <f:facet name="header">Description</f:facet>
        #{todo.description}
      </h:column>
    
      <h:column>
        <a href="edit.faces?tid=#{todo.id}">Edit</a>
      </h:column>
    </h:dataTable>
    <center>
      <h:commandButton action="create"
    
                value="Create New Todo" type="submit"/>
    </center>
    </h:form>

    The "Show All Todos" web page ” shows the "Show All Todos" web page with the data fields mapped to the data model.

    The "Show All Todos" web page

     

  • edit.xhtml : This page allows you to edit the "todo" item's 'title' and 'description' properties. The #{todoBean.update} and #{todoBean.delete} symbols represent the "update" and "delete" methods in the "TodoBean" class.

    <h2>Edit #{todoBean.todo.title}</h2>
    <h:form id="edit">
    <input type="hidden" name="tid" value="#{todoBean.todo.id}"/>
    
    <table>
      <tr>
        <td>Title:</td>
        <td>
          <h:inputText id="title" value="#{todoBean.todo.title}" size="15">
    
            <f:validateLength minimum="2"/>
          </h:inputText>
        </td>
      </tr>
      <tr>
    
        <td>Description:</td>
        <td>
          <h:inputTextarea id="description" value="#{todoBean.todo.description}">
            <f:validateLength minimum="2" maximum="250"/>
    
          </h:inputTextarea>
        </td>
      </tr>
    </table>
    <h:commandButton type="submit" id="update" value="Update"
    
                     action="#{todoBean.update}"/>
    <h:commandButton type="submit" id="delete" value="Delete"
                     action="#{todoBean.delete}"/>
    
    </h:form>

    The "Edit Todo" web page ” shows the "Edit Todo" web page with the mapping to the data model.

    The "Edit Todo" web page

     

Note

We have used XHTML pages in the sample applications because we recommend using Facelets instead of JSP to render JSF view pages.

EJB3 Session Beans

EJB 3.0 is one of the major improvements introduced with Java EE 5.0. It aims at reducing the complexity of older versions of EJB and simplifies Enterprise Java development and deployment. You will notice that to declare a class as a 'Session Bean' you simply have to annotate it. Using annotations eliminates the complexity involved with too many deployment descriptors. Also the only interface an EJB3 Session Bean requires is a business interface that declares all the business methods that must be implemented by the bean.

We will explore the two important source files associated with the Bean implementation in our application: TodoDaoInt.java and TodoDao.java.

  • Business interface : TodoDaoInt.java

    We define here the methods that need to be implemented by the bean implementation class. Basically, the business methods that will be used in our application are defined here.

    public interface TodoDaoInt {
    
      public void persist (Todo todo);
      public void delete (Todo todo);
    
      public void update (Todo todo);
    
      public List <Todo> findTodos ();
      public Todo findTodo (String id);
    }
  • Stateless Session Bean : TodoDao.java

    The @Stateless annotation marks the bean as a stateless session bean. In this class, we need to access the Entity bean Todo defined earlier. For this we need an EntityManager. The @PersistenceContext annotation tells the JBoss Server to inject an entity manager during deployment.

    @Stateless
    public class TodoDao implements TodoDaoInt {
    
      @PersistenceContext
      private EntityManager em;
    
      public void persist (Todo todo) {
        em.persist (todo);
      }
    
      public void delete (Todo todo) {
        Todo t = em.merge (todo);
        em.remove( t );
    
      }
    
      public void update (Todo todo) {
        em.merge (todo);
      }
    
      public List <Todo> findTodos () {
    
        return (List <Todo>) em.createQuery("select t from Todo t")
                                      .getResultList();
      }
    
      public Todo findTodo (String id) {
    
        return (Todo) em.find(Todo.class, Long.parseLong(id));
      }
    
    }

Configuration and Packaging

We will build the sample application using Ant and explore the configuration and packaging details. Please install Ant if currently not installed on your computer.

Building The Application

Let's look at building the example application and then explore the configuration files in detail.

In the section: About_the_Example_Applications, , we looked at the directory structure of the jsfejb3 sample application. At the command line, go to the jsfejb3 directory. There you will see a build.xml file. This is our Ant build script for compiling and packaging the archives. To build the application, you need to first of all edit the build.xml file and edit the value of jboss-dist to reflect the location where the JBoss Application Server is installed. Once you have done this, just type the command ant and your output should look like this:

[user@localhost jsfejb3]$ ant
Buildfile: build.xml

compile:

    [mkdir] Created dir: /jboss/gettingstarted/jsfejb3/build/classes
    [javac] Compiling 4 source files to /home/user/Desktop/gettingstarted/jsfejb3/build/classes
    [javac] Note: /jboss/gettingstarted/jsfejb3/src/TodoDao.java uses unchecked or unsafe operations.
    [javac] Note: Recompile with -Xlint:unchecked for details.

war:
    [mkdir] Created dir: /jboss/gettingstarted/jsfejb3/build/jars

      [war] Building war: /jboss/gettingstarted/jsfejb3/build/jars/app.war

ejb3jar:
      [jar] Building jar: /jboss/gettingstarted/jsfejb3/build/jars/app.jar

ear:
      [ear] Building ear: /jboss/gettingstarted/jsfejb3/build/jars/jsfejb3.ear

main:

BUILD SUCCESSFUL
Total time: 3 seconds

If you get the BUILD SUCCESSFUL message, you will find a newly created build directory with 2 sub-directories in it:

  • classes : containing the compiled class files.

  • jars : containing three archives - app.jar, app.war and jsfejb3.ear.

    • app.jar : EJB code and descriptors.

    • app.war : web application which provides the front end to allow users to interact with the business components (the EJBs). The web source (HTML, images etc.) contained in the jsfejb3/view directory is added unmodified to this archive. The Ant task also adds the WEB-INF directory that contains the files which aren’t meant to be           directly accessed by a web browser but are still part of the web application. These include the deployment descriptors (web.xml) and extra jars required by the web application.

    • jsfejb3.ear : The EAR file is the complete application, containing the EJB modules and the web module. It also contains an additional descriptor, application.xml.           It is also possible to deploy EJBs and web application modules individually but the EAR provides a convenient single unit.

Configuration Files

Now that we have built the application, lets take a closer look at some of the important Configuration files. We have built the final archive ready for deployment - jsfejb3.ear. The contents of your EAR file should look like this:

jsfejb3.ear
|+ app.jar   // contains the EJB code
    |+ import.sql
    |+ Todo.class
    |+ TodoDao.class
    |+ TodoDaoInt.class
    |+ META-INF

        |+ persistence.xml
|+ app.war   // contains web UI
    |+ index.html
    |+ index.xhtml
    |+ create.xhtml
    |+ edit.xhtml

    |+ todos.xhtml
    |+ TodoBean.class
    |+ style.css
    |+ META-INF
    |+ WEB-INF
       |+ faces-config.xml

       |+ navigation.xml
       |+ web.xml
|+ META-INF  // contains the descriptors
    |+ application.xml
    |+ jboss-app.xml
  • application.xml: This file lists the JAR files in the EAR (in our case app.jar) and tells the JBoss server what files to look for and where. The root URL for the application is also specified in this file as 'context-root'.

    <application>
      <display-name>Sample Todo</display-name>
      <module>
        <web>
          <web-uri>app.war</web-uri>
    
          <context-root>/jsfejb3</context-root>
        </web>
      </module>
      <module>
        <ejb>app.jar</ejb>
    
      </module>
    </application>
  • jboss-app.xml: Every EAR application should specify a unique string name for the class loader. In our case, we use the application name 'jsfejb3' as the class loader name.

    <jboss-app>
      <loader-repository>
    
        jsfejb3:archive=jsfejb3.ear
      </loader-repository>
    </jboss-app>
  • app.jar: This contains EJB3 Session Bean and Entity Bean classes and the related configuration files. In addition, the persistence.xml file configures the back-end data source (in our case the default HSQL database) for the EntityManager.

    <persistence>
       <persistence-unit name="helloworld">
          <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>
  • app.war: This contains the Web UI files packaged according to the Web Application aRchive (WAR) specification. It contains all the web pages and the required configuration files. The web.xml file is an important file for all JAVA EE web applications. It is the web deployment descriptor file. The faces-config.xml file is the configuration file for JSF. The navigation.xml file contains the rules for JSF page navigation.

    //faces-config.xml
    <faces-config>
      <application>
        <view-handler>
    
          com.sun.facelets.FaceletViewHandler
        </view-handler>
      </application>
      <managed-bean>
        <description>Dao</description>
    
        <managed-bean-name>todoBean</managed-bean-name>
        <managed-bean-class>TodoBean</managed-bean-class>
        <managed-bean-scope>request</managed-bean-scope>
      </managed-bean>
    
    </faces-config>

The Database

Creating the Database Schema

To pre-populate the database, we have supplied SQL Code (import.sql) to run with HSQL in the examples/jsfejb3/resources directory. When you build the application using Ant, this is packaged in the app.jar file within the jsfejb3.ear file. When the application is deployed, you should be able to view the pre-populated data.

The HSQL Database Manager Tool

Just as a quick aside at this point, start up the JMX console application and click on the service=Hypersonic link which you’ll find under the section jboss. If you can’t find this, make sure the Hypersonic service is enabled in the hsqldb-ds.xml file.

This will take you to the information for the Hypersonic service MBean. Scroll down to the bottom of the page and click the invoke button for the startDatabaseManager() operation. This starts up the HSQL Manager, a Java GUI application which you can use to manipulate the database directly.

The HSQL Database Manger

 

Deploying the Application

Deploying an application in JBoss is simple and easy. You just have to copy the EAR file to the deploy directory in the 'server configuration' directory of your choice. Here, we will deploy it to the 'default' configuration, so we copy the EAR file to the JBOSS_DIST/jboss-as/server/default/deploy directory.

You should see something close to the following output from the server:

15:32:23,997 INFO  [EARDeployer] Init J2EE application: file:/jboss/jboss-as-5.0.0<release>/server/default/deploy/jsfejb3.ear
15:32:24,212 INFO  [JmxKernelAbstraction] creating wrapper delegate for: org.jboss.ejb3.
entity.PersistenceUnitDeployment

15:32:24,213 INFO  [JmxKernelAbstraction] installing MBean: persistence.units:ear=
jsfejb3.ear,jar=app.jar,unitName=helloworld with dependencies:
15:32:24,213 INFO  [JmxKernelAbstraction]       jboss.jca:name=DefaultDS,service=
DataSourceBinding
15:32:24,275 INFO  [PersistenceUnitDeployment] Starting persistence unit persistence.
units:ear=jsfejb3.ear,jar=app.jar,unitName=helloworld
15:32:24,392 INFO  [Ejb3Configuration] found EJB3 Entity bean: Todo
15:32:24,450 WARN  [Ejb3Configuration] Persistence provider caller does not implements 
the EJB3 spec correctly. PersistenceUnitInfo.getNewTempClassLoader() is null.

15:32:24,512 INFO  [Configuration] Reading mappings from resource : META-INF/orm.xml
15:32:24,512 INFO  [Ejb3Configuration] [PersistenceUnit: helloworld] no META-INF/orm.xml 
found
15:32:24,585 INFO  [AnnotationBinder] Binding entity from annotated class: Todo
15:32:24,586 INFO  [EntityBinder] Bind entity Todo on table Todo
.
.
.
.

15:32:26,311 INFO  [SchemaExport] Running hbm2ddl schema export
15:32:26,312 INFO  [SchemaExport] exporting generated schema to database
15:32:26,314 INFO  [SchemaExport] Executing import script: /import.sql
15:32:26,418 INFO  [SchemaExport] schema export complete
15:32:26,454 INFO  [NamingHelper] JNDI InitialContext properties:{java.naming.factory.
initial=org.jnp.interfaces.NamingContextFactory, java.naming.factory.url.pkgs=org.jboss.
naming:org.jnp.interfaces}
15:32:26,484 INFO  [JmxKernelAbstraction] creating wrapper delegate for: org.jboss.ejb3.
stateless.StatelessContainer

15:32:26,485 INFO  [JmxKernelAbstraction] installing MBean: jboss.j2ee:ear=jsfejb3.ear,
jar=app.jar,name=TodoDao,service=EJB3 with dependencies:
15:32:26,513 INFO  [JmxKernelAbstraction]       persistence.units:ear=jsfejb3.ear,
jar=app.jar,unitName=helloworld
15:32:26,557 INFO  [EJBContainer] STARTED EJB: TodoDao ejbName: TodoDao
15:32:26,596 INFO  [EJB3Deployer] Deployed: file:/jboss/jboss-as-5.0.0<release>
server/default/tmp/deploy/
tmp33761jsfejb3.ear-contents/app.jar

15:32:26,625 INFO  [TomcatDeployer] deploy, ctxPath=/jsfejb3, warUrl=.../tmp/deploy/
tmp33761jsfejb3.ear-contents/app-exp.war/
15:32:26,914 INFO  [EARDeployer] Started J2EE application: file:/jboss/jboss-as-5.0.0<release>/server/default/deploy/jsfejb3.ear

If there are any errors or exceptions, make a note of the error message. Check that the EAR is complete and inspect the WAR file and the EJB jar files to make sure they contain all the necessary components (classes, descriptors etc.).

You can safely redeploy the application if it is already deployed. To undeploy it you just have to remove the archive from the deploy directory. There’s no need to restart the server in either case. If everything seems to have gone OK, then point your browser at the application URL.

http://localhost:8080/jsfejb3

You will be forwarded to the application main page. Sample TODO” shows the sample application in action.

Sample TODO