JSF frameworks: Shale and Seam

Enhanced techniques for building JavaServer Faces applications

JavaServer Faces (JSF) brings a new paradigm to developing Web-based applications in Java. Released a few years ago, but now slated to become part of Java Enterprise Edition 5 (Java EE is Sun's new name for J2EE), JSF will gradually supplant the old manner of structuring Java Web tier applications in JavaServer Pages (JSP) and servlets. JSF, whether by standardizing multi-device renderable UI components for delivering specific device markup, or allowing interfaces to be defined by prebuilt parts—widgets, buttons, menus, among other things—or tightening the link between client-side events and server application logic, is an embodiment of lessons learned from Java Web development throughout the years.

However, its out-of-the-box state is not without its faults. In this article, I illustrate how a particular set of frameworks—specifically, Shale from the Apache Software Foundation and Seam from JBoss—has already stepped up to fill in the gaps of this up-and-coming Java technology. With that said, you should realize that JSF represents an elaborate technology in and of itself, so if you are unfamiliar with its core concepts, you are advised to check out the links in Resources to get up to speed on the terminology used in our exploration, as we will jump right into the deep end of JSF.

JSF in isolation

No technology evolves in a vacuum, and Java is testament to this. More than 300 working groups are trying to incorporate the latest and most innovative approaches to using Java for particular software development tasks, and JSF composes just one of these many groups. The latest milestone release for JSF represented by the 1.2 version has two reference implementations: the Apache Software Foundation's MyFaces and Sun Microsystems' de facto reference implementation.

While JSF's working group tries to pack as much functionality as possible in each release, three primary reasons hinder the inclusion of interesting and powerful features and give way to frameworks such as Shale and Seam:

  • Consensus: Most Java working groups are composed of various industry players. While this guarantees compatibility among many different products, it also slows the adoption process for features that might be considered unique to particular vendors' needs.
  • Cross functionalities: Java specifications, more often than not, need to play well together with other Java specifications; this leads to open-ended scenarios that in turn require ad hoc bridging techniques to tailor an adequate solution.
  • Scope creep: Like any technology, release points have to be defined, where unfortunately the next big thing has to wait until the next release cycle.

Given these aforementioned facts, let's look at what can actually be done with JSF in its 1.2 release. As we move on, we will modify this application, addressing what features can make JSF development more efficient through particular offerings in Seam and Shale.

Our application allows users to reserve flights by providing their email addresses along with departure dates and destination cities—you can observe a snapshot of this application in the figure below. Things are kept relatively simple, but this initial iteration does try to pack a few standard features so even uninitiated JSF users can grasp the capabilities behind the technology. Listing 1 shows the JSF markup page that generates the output presented in the illustration.

Reservation form composed by JSF. Click on thumbnail to view full-sized image.

Listing 1. JSF markup page for reservation form

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://myfaces.apache.org/tomahawk" prefix="t"%>

<html> <head> <title>Metro Systems </title> <link href="css/style.css" rel="stylesheet" type="text/css"> </head> <body>

<div id="container">

<f:loadBundle basename="com.webforefront.resource.booking_messages" var="booking_messages"/>

<f:view> <h3> <h:outputText value="

#{booking_messages['welcome']}

"/> </h3> <h:form> <table align="center" cellpadding="5" cellspacing="5"> <tr> <td>Email</td> <td><h:inputText id="email" value="

#{flight.email}

"/> </td> </tr> <tr> <td><h:outputText id="departure" value="

#{booking_messages['date']}

"/></td> <td>

<t:inputCalendar monthYearRowClass="yearMonthHeader" weekRowClass="weekHeader" currentDayCellClass="currentDayCell" value="

#{flight.departure}

" renderAsPopup="true" popupTodayString="#{booking_messages['popup_today_string']}" popupWeekString="#{booking_messages['popup_week_string']}"/> </td> </tr> <tr> <td><h:outputText value="#{booking_messages['city']}"/> </td> <td> <h:selectOneMenu value="#{flight.city}" required="true">

<f:selectItem itemLabel="Los Angeles" itemValue="Los Angeles"/> <f:selectItem itemLabel="Madrid" itemValue="Madrid"/> <f:selectItem itemLabel="Mexico City" itemValue="Mexico City"/> <f:selectItem itemLabel="New York" itemValue="New York"/> <f:selectItem itemLabel="Paris" itemValue="Paris"/> </h:selectOneMenu></td> </tr> </table>

<h:commandButton type="submit" value="#{booking_messages['reserve']}" action="#{flight.reserve}"/> <h:messages/> </h:form>

</f:view> </div> </body> </html>

Most of the markup in this compact listing belongs to three JSF tag libraries: Core, HTML, and Tomahawk. While going into tag specifics would go beyond this article's scope, three details are worth mentioning:

  1. The <f:loadBundle> declaration gives internationalization (i18n) capabilities to our application. The basename attribute is used to specify the namespace of the language bundles, while var is the reference name used for extracting resource values. Scattered throughout the page you will notice attribute declarations in the form value="#{booking_messages['*']}" that represent i18n values, which, depending on a user's browser locale, will be substituted with his/her corresponding language values. (See the application's source code (downloadable from Resources) if you are unfamiliar with i18n bundle deployment.)
  2. The single markup line <t:inputCalendar> generates our entire pop-up calendar—that's an individual line that creates extensive HTML and JavaScript logic, which is JSF's touted component focus. The actual code is tucked away as a JSF component in the Tomahawk library provided in the Apache MyFaces JSF implementation.
  3. Notice the attributes with markup in the form value="#{flight.*}". The name of the backing bean is flight, and the second value represents the field name defined in the bean. In our case, the field names are email, departure, and city. Although flight.reserve is part of the backing bean, it's not a field per se, but we will get to that later.

This markup is only part of our application, the remaining elements, which are the backing bean and deployment descriptors, will be made much simpler or abbreviated as we move along and use either Shale or Seam. If you want to look at the standalone JSF application, see Resources to download the sample code. Now we will move forward with our first look at Shale.

Shale

Shale actually emerged from an earlier Java framework devoted to dealing with JSP pages and servlets: Struts. This last framework was among the pioneers in Java Web development and provided much of the building blocks for Model 2 designs—a variation of the MVC (Model View Controller) paradigm. Though Struts managed to garner a wide user base, its roots tied it down to the underlying architecture of JSP and servlets, which of course vastly differ from JSF. So to this end, Shale is a fresh incarnation of Struts written to leverage JSF's component-oriented architecture.

Framework compatibility: Application server and JSF implementation
Though standard JSF applications should function equally across any JSF implementation and any Java application server or Web container on the market (see Resources for application servers and JSF implementations), a higher-level framework like Seam or Shale is inevitably pegged or more thoroughly designed to work with a particular application server or JSF implementation. For example, Shale works best with Jakarta Tomcat, and Seam works best with JBoss Application Server—both using the MyFaces implementation developed by Apache. Regardless, you can still use these JSF frameworks in another server environment, though you may experience a little trouble when entering the deployment phase.

If you have previously worked with Struts, then some of Shale's features will surely look familiar. The difference is that you can now take advantage of them in a completely JSF-centric manner.

Among Shale's offerings are the following:

  • View controller, allowing extra services to be accessible from JSF backing beans
  • Dialog manager, for defining navigation rules needed to manage transitions between views
  • Integration facilities in areas like Java Naming and Directory Interface, Spring, and Tiles, among others

There is nothing like seeing for believing, so let's get down to modifying our existing JSF applications and use two of Shale's many functionalities.

JSF annotations and validation with Shale

Annotations are metadata placed within source code, which can later be used for configuration or execution purposes. While the approach is not new to programming or Java, this capability was previously only achievable using frameworks like XDoclet. But with the emergence of J2SE 5.0, annotations are ushering in a standard that will form part of the core Java language. JSF's most recent release grew in total isolation of the annotation functionalities provided in J2SE 5.0, but with Shale, you can leverage annotations for developing JSF solutions.

You need J2SE 5.0 for annotation support
To execute a JSF application using annotations in either Shale or Seam, you must upgrade your JDK to version 5.0.

Data validation is another aspect that, although given consideration in JSF—especially compared to JSP and servlets, which had none—can still be enhanced. Shale builds on its predecessor, Struts, and employs the same form-validating techniques using Apache Commons to lift the burden of writing server-side validation scaffolding code.

The bulk of our reworked JSF application avoids the use of JSF's deployment descriptor and instead uses annotations directly in the application's source code. This will grant us the benefits of having the same entry point for both configuring and developing JSF components, converters, renderers, and validators. We will also integrate Shale's validation library into our JSF markup to guarantee data integrity.

Listing 2. JSF backing bean with annotations for Shale Framework

 

package com.webforefront.shale;

import java.util.Date; import java.io.Serializable;

import javax.faces.context.FacesContext; import javax.faces.application.FacesMessage;

import java.util.Locale; import java.util.ResourceBundle;

import org.apache.shale.tiger.managed.Bean; import org.apache.shale.tiger.managed.Scope; import org.apache.shale.tiger.view.View; import org.apache.shale.tiger.view.Init; import org.apache.shale.tiger.view.Prerender;

@Bean(name="flight",scope=Scope.SESSION) @View public class Flight implements Serializable { private String email; private String city; private Date departure; public Flight(String email, String city, Date departure) { this.email = email; this.city = city; this.departure = departure; } public Flight() {}

public String getEmail() { return email; }

public void setEmail(String email) { this.email = email; }

public String getCity() { return city; }

public void setCity(String city) { this.city = city; } public Date getDeparture() { return departure; }

public void setDeparture(Date departure) { this.departure = departure; }

public void reserve() {

// Get JSF context to retreive messages from properties file FacesContext context = FacesContext.getCurrentInstance(); ResourceBundle bundle = ResourceBundle.getBundle("com.webforefront.resource.booking_messages", context.getViewRoot().getLocale());

String msg = bundle.getString("success1") + " " + this.getCity() + " " + bundle.getString("success2") + " " + this.getDeparture(); String msg2 = bundle.getString("success3") + this.getEmail();

// Add message to be displayed on the page via <h:messages> tag context.addMessage (null, new FacesMessage(msg)); context.addMessage (null, new FacesMessage(msg2)); }

// Shale callback method for init @Init public void customInitalizer() {

System.out.println("Callback method customInitializer() called"); }

// Shale callback method for prerender @Prerender public void customsBeforeRendering() { System.out.println("Callback method customsBeforeRendering() called"); }

}

Note: Without the annotations, this backing bean is identical to the one used in our standalone JSF application.

The four lines starting with @ represent annotations used by Shale. @Bean(name="flight",scope=Scope.SESSION) declares the name and scope of our backing bean—which coincides with the value used in our JSF markup. These values would typically be placed in the additional deployment descriptor, myfaces-config.xml, used in standalone JSF applications. The second annotation, @View, is referred to as an annotated view controller, which gives the backing bean access to various callback methods during the JSF's application lifecycle. Without this Shale annotation, access to a view controller would need to be done through inheritance. Finally, the remaining annotations, @Init and @Prerender, mark the methods that will execute—due to the view controller—at the initialization and prerendering steps of the JSF page.

Other things you will notice in this backing bean are the staple getter/setter methods of any JavaBean and the reserve() method, which is bound to the application's form-submitting action. When a user submits his/her data, this method composes a message structured from the application's resource bundles (i18n) and adds the message to the application's context for display to the end user. Since submitting information without the proper validation lends itself to corrupt data, let's see how Shale supports this particular process. Listing 3 contains the modified markup using Shale's validator library.

Listing 3. JSF markup with validator routines provided by Shale Framework

 

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://struts.apache.org/shale/core" prefix="s" %> <%@ taglib uri="http://myfaces.apache.org/tomahawk" prefix="t"%>

<html> <head> <title>Metro Systems </title> <link href="css/style.css" rel="stylesheet" type="text/css"> </head> <body>

<div id="container"> <f:loadBundle basename="com.webforefront.resource.booking_messages" var="booking_messages"/> <f:view>

<h3> <h:outputText value="#{booking_messages['welcome']}"/> </h3> <h:form onsubmit="return validateForm(this);"> <table align="center" cellpadding="5" cellspacing="5"> <tr> <td>Email</td> <td><h:inputText id="email" value="#{flight.email}"> <s:commonsValidator type="required" arg="Email" server="true" client="true"/> <s:commonsValidator type="email" arg="#{flight.email}" server="true" client="true"/> </h:inputText> </td> </tr> <tr> <td><h:outputText id="departure" value="#{booking_messages['date']}"/></td> <td> <t:inputCalendar monthYearRowClass="yearMonthHeader" weekRowClass="weekHeader" currentDayCellClass="currentDayCell" value="#{flight.departure}" renderAsPopup="true" popupTodayString="#{booking_messages['popup_today_string']}" popupWeekString="#{booking_messages['popup_week_string']}"> <s:commonsValidator type="required" arg="Departure date" server="true" client="true"/> </t:inputCalendar> </td> </tr> <tr> <td><h:outputText value="#{booking_messages['city']}"/> </td> <td> <h:selectOneMenu value="#{flight.city}" required="true"> <f:selectItem itemLabel="Los Angeles" itemValue="Los Angeles"/> <f:selectItem itemLabel="Madrid" itemValue="Madrid"/> <f:selectItem itemLabel="Mexico City" itemValue="Mexico City"/> <f:selectItem itemLabel="New York" itemValue="New York"/> <f:selectItem itemLabel="Paris" itemValue="Paris"/> </h:selectOneMenu></td> </tr> </table> <h:message for="email" styleClass="errors"/> <h:message for="departure" styleClass="errors"/> <s:validatorScript functionName="validateForm"/>

<h:commandButton type="submit" value="#{booking_messages['reserve']}" action="#{flight.reserve}"/> <h:messages/> </h:form> </f:view> </div> </body> </html>

Our modified JSF markup shows a series of <s:commonsValidator> tags. These tags, which must be nested within each field to be verified, guarantee the integrity of both the email and date fields used in our reservation form. Of worthy mention is the use of parameter client=true in these statements, which allows validation to occur via JavaScript immediately, without a round-trip to the server, contrary to the classical JSF round-trip validation technique also offered by the Shale validator attribute server=true.

Finally, it should be noted that though we saved ourselves the trouble of writing a JSF-specific deployment descriptor, the standard web.xml deployment descriptor does require some changes to accommodate Shale's controller filter and other possible functionalities. You can view these changes in the accompanying application's source code.

Now that you have seen first-hand parts of Shale that can speed up your JSF developments, let's move on to our next JSF framework: Seam.

Seam

Though Seam is also an open source JSF framework like Shale, Seam is not developed by a foundation, but rather a corporation, JBoss, which has a vested interest in Java as a whole. Depending on your position, this might be either a boon or a drawback. JBoss, recently purchased by Red Hat, develops the JBoss Application Server, the popular object-relational (O/R) mapping framework Hibernate, and a few other open source projects in the Java landscape.

In this sense, Seam is not only focused on more efficiently using JSF components in Java applications, but also intended to be an all encompassing framework for dealing with various scenarios that can emerge in JBoss's suite of offerings, like:

  • Integration with business process management via jBPM
  • The capability of creating Seam components for producing custom layering designs
  • The handling of declarative application state management, among other tasks

If your organization is committed to JBoss, then Seam will surely be a logical choice for working with JSF. On the other hand, if you use any other application server, some further research might be necessary before you take the plunge. Though Seam can be used with any application server or even a Web container like Tomcat, Seam must be deployed in conjunction with JBoss's micro-container, which is a separate piece of software running within the hosting application server. While this extra layer might be trivial for some projects, it might not be the adequate solution for other scenarios due to issues ranging from licensing to an over-bloated runtime.

But let's not make these last possibilities a determent to our JSF framework exploration, Seam still has its merits, one of which we explore in the upcoming section.

JSF integration with EJB through Seam

JSF focuses on the encapsulation and rendering of Web interfaces, but like any other interface, it eventually must be linked to actual data. For most Web-enabled Java applications, an extra tier is introduced to deal specifically with this linkage; current approaches range from O/R frameworks like Hibernate, Enterprise JavaBeans (EJB), or plain-old Java Database Connectivity code, among other techniques. Given this fact, usually a JSF component is linked to one of these aforementioned technologies, which solely provide business logic processing or data binding.

In the following iteration of our JSF application, our first major change will come to our JSF backing bean. Instead of using a run-of-the-mill JavaBean, we use an EJB component that will grant us access to the additional services provided by EJB, such as the ability to interact with an external datasource as well as additional middleware services like transactions and security. Listing 4 illustrates the backing bean in the form of an entity bean that will be used to interact with our JSF application.

Listing 4. JSF backing bean for Seam Framework

 

package com.webforefront.seam;

import static org.jboss.seam.ScopeType.SESSION;

import java.io.Serializable; import java.util.Date;

import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table;

import org.hibernate.validator.NotNull; import org.hibernate.validator.Min; import org.hibernate.validator.Pattern; import org.hibernate.validator.Email; import org.hibernate.validator.Future; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope;

@Entity @Name("flight") @Scope(SESSION) @Table(name="flights") public class Flight implements Serializable { private String email; private String city; private Date departure; public Flight(String email, String city, Date departure) { this.email = email; this.city = city; this.departure = departure; } public Flight() {} @Id @NotNull @Email public String getEmail() { return email; }

public void setEmail(String email) { this.email = email; }

public String getCity() { return city; }

public void setCity(String city) { this.city = city; } @NotNull @Future public Date getDeparture() { return departure; }

public void setDeparture(Date departure) { this.departure = departure; } }

Notice that much of this backing bean employs the same annotation principals used by Shale, which demonstrates, to a certain extent, the degree of overlap between both of these JSF frameworks—though the annotations do posses different meanings. The @Entity annotation tells the Java environment we are dealing with an entity bean, while the @Table markup indicates the relational database table name onto which the entity data will be persisted. On the other hand, the @Name and @Scope markup are used to specify the reference name and scope used by our JSF component to work with the entity—notice that both belong to the Seam namespace.

Moving along the listing, you will also observe that the entity bean has various annotations along its getter methods; these fulfill the purpose of validating data before it's persisted to the database. In the case of the getDeparture() method, the @NotNull and @Future markup guarantee that a user will provide a departure date that occurs in the future. What is important to realize about these validation annotations is that though we are dealing with an entity bean, these possible error messages make their way back to the user's interface, which is of course composed by JSF.

Finally, notice that contrary to the other backing bean design, our entity bean lacks the reserve() method. The reason for the omission is that the reserve() method is not directly related to data, but rather a method triggered when a user submits data. Following the separation principal of data and business logic in EJB, that would require us to use a session bean for this task. Listing 5 illustrates such a session bean.

EJB 3.0 programming model
EJB, in its 3.0 version, has embraced a distinct programming model from earlier EJB versions. Through the use of annotations and dependency injection, the old approaches to using inheritance hierarchies, various interfaces, and deployment descriptors are a thing of the past. While these code listings may seem extremely simple—especially compared to the EJB 2.1 world—all EJB features available in previous versions are still there, except now they are more manageable and succinct.

Listing 5. Session bean for linking JSF backing entity bean using Seam Framework

 

package com.webforefront.seam;

import java.util.List;

import javax.ejb.Interceptors; import javax.ejb.Stateless; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext;

import org.hibernate.validator.Valid; import org.jboss.seam.annotations.IfInvalid; import org.jboss.seam.annotations.In;

import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Outcome; import org.jboss.seam.ejb.SeamInterceptor;

@Stateless @Name("reserve") @Interceptors(SeamInterceptor.class) public class ReserveAction implements Reserve {

@In @Valid private Flight flight; @PersistenceContext

private EntityManager em; @In private FacesContext facesContext; @IfInvalid(outcome=Outcome.REDISPLAY) public String reserve() { List existing = em.createQuery("select email from Flight where email=:email") .setParameter("email", flight.getEmail()) .getResultList(); if (existing.size()==0) { em.persist(flight); return "success"; } else { facesContext.addMessage(null, new FacesMessage("Email already has an assigned reservation")); return null; } }

}

The further use of annotations will probably stand out in this EJB code, so let's address them. The @Stateless annotation indicates we are dealing with a stateless EJB component, while the @Name markup is used to reference the EJB from within the JSF markup. Meanwhile the @Interceptors declaration states which classes will inspect the bean's incoming request, which in this case is the default SeamInterceptor class.

Inside the EJB component's body, we find three fields: Flight, which represents an instance of our entity bean; EntityManager, which gives the stateless EJB access to the Java persistence manager; and FacesContext, which lets us tap into the JSF context. Finally, we find the reserve() method, which is triggered when a user submits our reservation form; however, if you have a sharp eye, you will notice that this time around it has vastly different logic.

First, the reserve() method creates a query using the EntityManger reference to find out if the email currently being submitted is in the database. If the email is not present, then the whole entity bean instance is persisted—line em.persist(flight)—returning a "success" value to the JSF context. If the email is present in the database, we add a message to the JSF context indicating a duplicate email is in the system. Listings 6 and 7 illustrate what our JSF markup looks like in our modified Seam application.

Listing 6. JSF markup page for reservation form using Seam

 

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://myfaces.apache.org/tomahawk" prefix="t"%>

<html> <head> <title>Metro Systems </title> <link href="css/style.css" rel="stylesheet" type="text/css"> </head> <body>

<div id="container">

<f:loadBundle basename="com.webforefront.resource.booking_messages" var="booking_messages"/> <f:view> <h3> <h:outputText value="#{booking_messages['welcome']}"/> </h3> <h:form> <table align="center" cellpadding="5" cellspacing="5"> <tr> <td>Email</td> <td><h:inputText value="#{flight.email}"/></td> </tr> <tr> <td><h:outputText value="#{booking_messages['date']}"/> </td> <td> <t:inputCalendar id="secondOne" monthYearRowClass="yearMonthHeader" weekRowClass="weekHeader" currentDayCellClass="currentDayCell" value="#{flight.departure}" renderAsPopup="true" popupTodayString="#{booking_messages['popup_today_string']}" popupWeekString="#{booking_messages['popup_week_string']}" /> </td> </tr> <tr> <td><h:outputText value="#{booking_messages['city']}"/> </td> <td> <h:selectOneMenu value="#{flight.city}" required="true"> <f:selectItem itemLabel="Los Angeles" itemValue="Los Angeles"/> <f:selectItem itemLabel="Madrid" itemValue="Madrid"/> <f:selectItem itemLabel="Mexico City" itemValue="Mexico City"/> <f:selectItem itemLabel="New York" itemValue="New York"/>

<f:selectItem itemLabel="Paris" itemValue="Paris"/> </h:selectOneMenu></td> </tr> </table> <h:messages/>

<h:commandButton type="submit" value="#{booking_messages['reserve']}" action="#{reserve.reserve}"/>

</h:form> </f:view> </div> </body> </html>

Listing 7. JSF markup page for reservation form on "success" using Seam

 

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <html> <head> <title>Metro Systems</title> <link href="css/style.css" rel="stylesheet" type="text/css"> </head> <body> <div id="container"> <f:loadBundle basename="com.webforefront.resource.booking_messages" var="booking_messages"/>

<f:view> <p> <h:outputText value="#{booking_messages['success1']}"/> <h:outputText value="#{flight.city}"/> <h:outputText value="#{booking_messages['success2']}"/> <h:outputText value="#{flight.departure}"/>. </p> <p> <h:outputText value="#{booking_messages['success3']}"/> <h:outputText value="#{flight.email}"/> </p> <p> <h:outputLink value="index.html" title="#{booking_messages['reserve_another_flight']}"> <h:outputText value="#{booking_messages['reserve_another_flight']}"/> </h:outputLink> </p> </f:view> </div> </body> </html>

Our main JSF page has only one minor change: the <commandButton> action attribute is bound to the value reserve.reserve, which represents the session bean's name and its only method. Besides this, notice that the form's values are still bound to flight.* values, with the first being the name given to the entity bean via Seam annotations.

Regarding Listing 7, this JSF markup represents a page that will display if the JSF context receives a "success" response from the backing session bean. The actual response to page mapping for this occurs within the standard JSF deployment descriptor myfaces-config.xml.

Besides this last deployment descriptor, the standard web.xml descriptor also requires various changes to accommodate Seam's redirect filter and JBoss's micro-container, in case you are using a non-JBoss application server, among other things. Finally, since we are using an entity bean, we must set up a connection to an external datasource. In case you are unfamiliar with this last setup, look over the sample application configured to work with HSQL-DB—an embedded relational database included with JBoss's micro-container.

With this, I conclude our overview of the Seam framework, which, as you have seen, allows you to close the gap between a JSF-based design and one requiring the capabilities found in EJB.

Conclusion

As the balance for developing Java Web applications starts to tilt in favor of JSF, many common "strings" to Java Web applications may still prove too many to tie down with JSF's out-of-the-box state. While a JSF framework like Shale or Seam is not a replacement for filling in knowledge gaps surrounding JSF capabilities—just like Struts or Webwork is not a magic bullet for JSP and servlet development—when properly used, Shale or Seam can help you cut many corners typical to JSF development, thereby reducing your overall project development times by orders of magnitude.

Daniel Rubio is an independent technology consultant specializing in enterprise and Web-based software. He blogs regularly on these and other software areas at http://www.webforefront.com/.

Learn more about this topic

Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more