http://www.developer.com/

Back to article

Spring into JavaServer Faces


April 27, 2006

In the context of Java development, the Spring framework and JavaServer Faces are two names that frequently come up in conversation. Spring is a powerful application framework that rivals Enterprise JavaBeans in the breadth of its features. JavaServer Faces, commonly known as JSF, is a component-oriented, event-driven framework for building Web applications. Given the popularity of both Spring and JSF, it is natural that there will be some interest in integrating Spring and JSF. As it turns out, this is quite possible. In fact, they compliment each other very nicely. This article demonstrates how to utilize JSF and Spring to build an application.

A detailed discussion of either Spring or JSF is beyond the scope of this article. There are numerous resources on the Web where you can learn about these two topics. Having said that, I will attempt to provide a very brief overview of both of them.

Spring is a framework that consists of several modules. Its core module provides Inversion of Control services. Inversion of Control is often referred to as IOC; I will use this term for the remainder of the article. With IOC, the container injects an object's dependencies at runtime. This is in contrast to the common approach of writing code to look up dependent objects using the Java Naming and Directory Interface (JNDI) interface or an object implementing the Service Locator design pattern. When you allow an IOC container to inject dependencies for you, you simplify your application code. Spring specifies object dependencies in a configuration file; this is more flexible than putting this information in source code. Spring's other modules provide an array of other services. These services include transaction support and support classes for working with O-R mapping tools. Spring also provides its own Web framework as an alternative to Struts or even JSF.

JavaServer Faces represents a new approach to Web development. Previously, developers using Servlet-based technologies such as JavaServer Pages manipulated an object model that reflected the stateless nature of the HTTP protocol. This model includes objects such as Request and Response. Developers had to write code to explicitly preserve a Web form's values between requests (although frameworks helped in this regard). although these objects are still important to JSF developers, JSF user interface components are designed to automatically preserve their state between requests. Code to handle state management is greatly reduced. In addition to user interface components, JSF provides 'managed-beans' that can be used to hold data and respond to user events. JSF also provides numerous non-visual components that handle validation and data conversion tasks. Using a JSF development tool, building an interface is as simple as dragging components and dropping them onto a page where you can modify their behavior and appearance through a property palette. In short, JSF is designed to make the Web development experience similar to building applications with a technology such as Visual Basic.

JSF and Spring do share some of the same features, most noticeably in the area of IOC services. By declaring JSF managed-beans in the faces-config.xml configuration file, you allow the FacesServlet to instantiate that bean at startup. Your JSF pages have access to these beans and all of their properties. This is a powerful feature and is similar to how Spring's applicationContext works. JSF's managed-beans facility may be all that you need for developing small applications but Spring's applicationContext is a more powerful option. In addition, by using Spring IOC developers have at their disposal all of Spring's other capabilities.

In the remainder of this article, you will step through a simple application that utilizes both Spring and JSF. The sample application is a hotel reservation system. Here is the full schema for this application. You will focus on a single table, room, for the purposes of this article. The room table contains information about different hotel rooms.

You will build this application from the bottom up, so your first task is to create a domain object to represent your room table. Room.java contains the source code for the Room class. The attributes of this class match the columns in the table. You will add this class to the package called 'domain'. In this application, you will use the Hibernate object-relational mapping framework. Hibernate can significantly reduce the amount of data access code necessary in Java applications. The mapping between tables and Java objects is specified in an XML configuration file. Room.hbm.xml maps the room table to domain.Room:

<hibernate-mapping>
   <class name="hotelReservations.domain.Room" table="room">
   <id name="roomId" column="room_id" unsaved-value="0">
      <generator class="increment" />
   </id>
   <property name="floor" column="floor" not-null="true"/>
   <property name="roomNumber" column="room_number" not-null="true"/>
   <property name="reserveStatus" column="reserve_status"
             not-null="true"/>
   <property name="roomType" column="room_type" not-null="true"/>
   <property name="canSmoke" column="can_smoke" not-null="true"/>
   lt;/class>
</hibernate-mapping>

This file should be in the same 'domain' directory as the Room class. Next, a class is needed that handles the data access requirements for working with room data. This designated class follows the Data Access Object, or DAO, design pattern. To add greater flexibility to switch data access implementations later on, your DAO should implement an interface. By doing so, the rest of the application can remain unaware of the data access specifics. The RoomDao defines the public methods of any DAO class the application implements, whether you use Hibernate or not. RoomDaoHibernate implements RoomDao and will use the Hibernate programmatic interface. Here are the methods in this Hibernate-specific class:

public List getRooms() {
   return getHibernateTemplate().find("from Room");
}

public Room getRoom(Long id) {
   return (Room) getHibernateTemplate().get(Room.class, id);
}

public void saveRoom(Room room) {
   getHibernateTemplate().saveOrUpdate(room);
}

public void removeRoom(Long id) {
   Object room = getHibernateTemplate().load(Room.class, id);
   getHibernateTemplate().delete(room); 
}

Now that you have established your domain layer and implemented a data access layer, it would be acceptable to begin developing the view layer of the application with JSF. However, a common practice is to add one final layer to the application. This final layer sits between the view and the data access objects and defines the interface through which all clients access the application. This layer contains the core business logic for the application and invokes DAO methods. JSF managed beans will communicate only with this layer, not the DAOs. The HotelManager class does nothing more than invoke the DAO methods. In a more complex application, additional business logic would be found here.

HotelManager contains an instance of the application's DAO object:

private RoomDao dao;

   public void setRoomDAO(RoomDao dao) {
      this.dao = dao;
   }

You did not write this code. Rather, you let Spring inject this dependency at runtime. This dependency is specified in Spring's applicationContext.xml file.

<!--Dao (Data Access Object) for application. -->
<bean id="roomDAO" class="hotelReservations.dao.RoomDaoHibernate">
   <property name="sessionFactory">
      <ref local="sessionFactory"/>
   </property>
</bean>

<!--Manager for Hotel rooms application.-->
<bean id="hotelManager" class="hotelReservations.HotelManager">
   <property name="roomDAO">
      <ref local="roomDAO"/>
   </property>
</bean>

There can be many different settings in a Spring configuration file, such as database connection properties. The Spring framework also allows developers to specify transactions at the business layer of an application. This is accomplished by specifying a transaction proxy bean that wraps the business layer object, in this case HotelManager.

<!--Wraps manager in order to support transactions.-->
<bean id="manager"
      class="org.springframework.transaction.interceptor.
             TransactionProxyFactoryBean">
   <property name="transactionManager">
      <ref local="transactionManager"/>
   </property>
   <property name="target">
      <ref local="hotelManager"/>
   </property>
   <property name="transactionAttributes">
      <props>
         <prop key="save*">PROPAGATION_REQUIRED</prop>
         <prop key="remove*">PROPAGATION_REQUIRED</prop>
         <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
      </props>
   </property>
</bean>

This has admittedly been a brief introduction on how Spring is used in this application. I would suggest visiting the Spring Web site for a more thorough explanation of Spring's features. As mentioned earlier, JSF provides managed-beans to Web pages once they are specified in the faces-config.xml file. FacesServlet loads the beans listed in this file at application startup. It is possible, though not recommended, to put business logic inside JSF managed-beans. Typically, you will want to keep managed-bean code focused on view-related tasks. I created a managed-bean called ShowRooms that can contain methods and properties that your JSF Web page, ShowRooms.jsp can reference.

Managed-Bean Accessible to a JSF Web Page

<managed-bean>
   <managed-bean-name>showRooms</managed-bean-name>
   <managed-bean-class>hotelReservations.ShowRooms</managed-bean-class>
   <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

JSF Web Page Accessing a ShowRooms Instance and Its Rooms Property

<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html;
            charset=UTF-8">
      <link href="styles.css" type="text/css" rel="stylesheet">
      <title>Hotel Reservation System</title>
   </head>
   <body>
      <f:view>
         <h1><h:outputText value="Hotel Rooms" /></h1>
         <h:dataTable value="#{showRooms.rooms}" var="rowRoom" 
                      border="1" headerClass="Heading"
                      rowClasses="RowOdd,RowEven">
         <h:column>
            <f:facet name="header">
               <f:verbatim>Room #</f:verbatim>
            </f:facet>
            <h:outputText value="#{rowRoom.roomNumber}"/>
         </h:column>

         ...
         ...

         </h:dataTable>
      </f:view>
   </body>
</html>

ShowRooms.jsp displays a collection of Room objects. These objects should be obtained by invoking the Spring business method getRooms(). Now, look at what it will take to make this possible.

The key component that makes Spring objects available to JSF managed beans is Spring's DelegatingVariableResolver. A JSF VariableResolver can be used to bind values from objects available in one of an application's scopes, such as the request scope or session scope. JSF's VariableResolver searches through each possible scope and if it finds no match, it then searches for the value using any variable resolver specified in the faces-config file. By specifying Spring's DelegatingVariableResolver, you can inject the HotelManager instance into your JSF managed-bean:

<!-- Allows you to inject Spring beans into JSF managed beans... -->
<application>
   <variable-resolver>
      org.springframework.web.jsf.DelegatingVariableResolver
   </variable-resolver>
</application>

Once this entry has been added, you must modify your managed-bean definition and define a managed-property. This property is called 'manager', the name of your Spring bean defined in applicationContext.xml:

<!--Managed-bean accessible to JSF Web page.-->
<managed-bean>
    <managed-bean-name>showRooms</managed-bean-name>
    <managed-bean-class>hotelReservations.ShowRooms</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
    <managed-property>
       <property-name>manager</property-name>
       <value>#{manager}</value>
    </managed-property>
</managed-bean>

Finally, after adding the manager property to the JSF managed-bean, you can delegate to the Spring manager in the ShowRooms managed-bean:

public class ShowRooms {

   /** Creates a new instance of ShowRooms */
   public ShowRooms() {
   }


   /**
    * Holds value of property hotelReservation.
    */
   private HotelManager manager;

   /**
    * Setter for property hotelManager.
    * @param hotelManager New value of property hotelManager.
    */
   public void setManager(HotelManager manager) {
      this.manager = manager;
   }

   public HotelManager getManager() {
      return manager;
   }

   /**
    * Returns List of all hotel rooms objects.
    */
   public List getRooms() {
      return this.getManager().getRooms();

   }

ShowRooms.jsp utilizes a JSF table component to display the list of Room objects using the expression "#{showRooms.rooms}". At runtime, it invokes the getRooms method to retrieve this data. Each column within the table contains output text to display a property within the current Room instance. Again, this is accomplished with expressions such as "#{rowRoom.roomNumber}". Applying a simple stylesheet, the following output appears on the page:

More complex JSF components exist to display tabular data that support sorting and pagination. This simple table is adequate for this demonstration. One area you should improve upon is the display of room data. To begin with, room id is a unique identifier with no business meaning. It is unlikely the user will care about this attribute, so you can remove it. Also, chances are good that database character codes such as 'O' for an occupied room or 'V' for a vacancy will mean little to users. One way to translate this text is to perform decodes in the database query. However, it is also possible to translate these values in the view layer. You could accomplish this by directing some of the JSF table's columns to managed-bean methods that will perform these translations. An enhanced ShowRoom bean contains the following translation methods:

//Get current room object.
private Room getCurrentRoom() {
   return (Room) FacesContext.getCurrentInstance().
      getExternalContext().getRequestMap().get("rowRoom");
}

//Get translated room type.
public String getDisplayedRoomType() {
   return getCurrentRoom().getRoomType().
      equals(new Character('S')) ? "Single" : "Double";
}

//Get translated reserve status.
public String getDisplayedReserveStatus() {
   return getCurrentRoom().getReserveStatus().
      equals(new Character('V')) ? "Vacant" : "Occupied";
}

//Get translated can smoke.
public String getDisplayedCanSmoke() {
   return getCurrentRoom().getCanSmoke().
      equals(new Boolean(true)) ? "Yes" : "No";
}

An updated ShowRoom.jsp file will reference these new methods. For example, instead of the expression "#{rowRoom.canSmoke}", use '"#{showRooms.displayedCanSmoke}"'. The result is a more meaningful display of user data:

Conclusion

Spring is a powerful framework for building enterprise Java applications. JSF is a standards-based technology that can simplify Web development. It is possible to combine the two with surprisingly little effort, allowing developers to take advantage of the best that both Spring and JSF have to offer. The source code for this article is available for download here.

About the Author

Michael Klaene is a Senior Consultant with Sogeti LLC. He has spent over 9 years in Information Technology and is an experienced Systems Analyst, delivering solutions that involve numerous technologies, such as J2EE and .NET.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date