JSF 2 fu: JSF wizards

Implement a wizard with JSF 2 and CDI

In this JSF 2 fu installment, you'll find out how to combine JSF 2 with Contexts and Dependency Injection (CDI) to implement an Ajaxified wizard. You'll see JSF's templating and Ajax in action, and you'll learn how to use CDI's dependency injection and conversation scope.

David Geary, President, Clarity Training, Inc.

Photo of David GearyAuthor, speaker, and consultant David Geary is the president of Clarity Training, Inc., where he teaches developers to implement Web applications using JSF and Google Web Toolkit (GWT). He was on the JSTL 1.0 and JSF 1.0/2.0 Expert Groups, co-authored Sun's Web Developer Certification Exam, and has contributed to open source projects, including Apache Struts and Apache Shale. David's Graphic Java Swing was one of the best-selling Java books of all time, and Core JSF (co-written with Cay Horstman), is the best-selling JSF book. David also speaks regularly at conferences and user groups. He has been a regular on the NFJS tour since 2003, is a three-time Java University instructor, and a three-time JavaOne Rock Star.



06 July 2010

Also available in Chinese Russian Japanese Portuguese

Java™ Enterprise Edition (Java EE) 6 includes many powerful technologies, including JSF 2. One of those technologies, Contexts and Dependency Injection (CDI), in many ways standardizes concepts that have been brewing for years in other frameworks.

In this article, I show you how to combine JSF 2 and CDI to implement a wizard for online quizzes. CDI gives me dependency injection, producer methods, and a conversation scope. I'll use all three to implement a wizard that you can easily use for any multiple-choice, online quiz.

About this series

The JSF 2 fu series, a follow-on to David Geary's three-article introduction of the same name, will help you develop and hone your JSF 2 framework skills like a kung fu master. The current series dives deeper into the framework and its surrounding ecosystem. And it takes a peek outside the box by showing how some Java EE technologies, such as Contexts and Dependency Injection, integrate with JSF.

This article, however, isn't just about CDI. I'll cover how to:

  • Use facelets templates to minimize code and maximize reuse
  • Ajaxify wizards for a smoother user experience
  • Use CDI's dependency injection to simplify your code
  • Implement and use CDI producer methods to use beans seamlessly in your views
  • Take advantage of CDI's conversation scope to implement multiple-request use cases

The full source code for the article's examples is available for download. See the Running the sample code sidebar for a download link and a pointer to deployment instructions.

The quiz wizard

Figure 1 shows the quiz wizard in action:

Figure 1. The quiz wizard
Quiz wizard

Initially, the application contains a lone link that starts the wizard: <h:commandLink value="#{msgs.startWizard}" action="#{wizard.start}"/>. The link's text (Start the wizard) comes from a properties file and is represented by the msgs.startWizard expression in the link's value. Internationalization is JSF 101 circa 2004, so I won't bore you with those details here. It suffices to note that the entire application is localized, so all strings are pulled from the messages.properties file.

Running the sample code

The code for this series is based on JSF 2 running in an enterprise container, such as GlassFish or Resin. See the first series installment, "JSF 2 fu: Ajax components" for a step-by-step tutorial on installing and running the code for this series with GlassFish. See Download to get the sample code for this article.

The Start the wizard link takes users to the quiz wizard page, where they are presented with questions, one at a time, as shown in the bottom two pictures in Figure 1. I control the enabled state of the wizard's buttons through some simple Ajax and a server-side bean, as I'll show you in The Ajax section of this article.

Figure 2 shows the last question, followed by a summary of the user's answers. The Finish button is only enabled when the user is on the last question; clicking that button takes the user to the summary page.

Figure 2. The summary page
Wizard summary

Now that you know how the quiz wizard works, I'll show you how it's implemented.


The quiz application

The quiz application's files are shown in Figure 3:

Figure 3. The application's files
Application directory

I implemented the quiz wizard with a JSF 2 template (/templates/wizardTemplate.xhtml) that's used by the wizard view (/quizWizard/wizard.xhtml).

In addition to the template and the view, I have facelets — all in the quizWizard directory — for each of the wizard's pieces:

  • The heading (/quizWizard/heading.xhtml)
  • The question (/quizWizard/question.xhtml)
  • The radio buttons (quizWizard/choices.xhtml)
  • The Next, Previous, and Finish buttons (quizWizard/controls.xhtml)

The index.xhtml facelet kicks off the application with the Start the wizard link, and the done.xhtml facelet displays a summary of questions and answers.

That's it for the client. On the server, the application has three beans, two of which I discuss next.


The application's question beans

The Question bean, shown in Listing 1, is actually a question, a set of answer choices, and an answer:

Listing 1. The Question bean
package com.clarity;

import java.io.Serializable;

public class Question implements Serializable {
  private static final long serialVersionUID = 1284490087332362658L;

  private String question, answer;
  private String[] choices;
  private boolean answered = false; // next button is enabled when answered is true
  
  public Question(String question, String[] choices) {
    this.question = question;
    this.choices = choices;
  }

  public void setAnswer(String answer) {
    this.answer = answer;
    answered = true;
  }

  public String getAnswer()    { return answer;   }
  public String getQuestion()  { return question; }
  public String[] getChoices() { return choices;  }
  public boolean isAnswered()  { return answered; }

  public void setAnswered(boolean answered) { this.answered = answered; }  
}

The application also maintains an array of questions in the Questions class, shown in Listing 2:

Listing 2. The Questions bean
package com.clarity;

import java.io.Serializable;

import com.corejsf.util.Messages;

public class Questions implements Serializable {
  private static final long serialVersionUID = -7148843668107920897L;

  private String question;
  private Question[] questions = {      
    new Question(
       Messages.getString("com.clarity.messages", "expandQuestion", null),
       new String[] { 
         Messages.getString("com.clarity.messages", "hydrogen", null),
         Messages.getString("com.clarity.messages", "helium", null),
         Messages.getString("com.clarity.messages", "water", null),
         Messages.getString("com.clarity.messages", "asphalt", null)
       }),
       
   new Question(
       Messages.getString("com.clarity.messages", "waterSGQuestion", null),
       new String[] { 
         Messages.getString("com.clarity.messages", "onedotoh", null),
         Messages.getString("com.clarity.messages", "twodotoh", null),
         Messages.getString("com.clarity.messages", "onehundred", null),
         Messages.getString("com.clarity.messages", "onethousand", null)
       }),
       
   new Question(
       Messages.getString("com.clarity.messages", "numThermoLawsQuestion", null),
       new String[] { 
         Messages.getString("com.clarity.messages", "one", null),
         Messages.getString("com.clarity.messages", "three", null),
         Messages.getString("com.clarity.messages", "five", null),
         Messages.getString("com.clarity.messages", "ten", null)
       }),
       
   new Question(
       Messages.getString("com.clarity.messages", "closestSunQuestion", null),
       new String[] { 
         Messages.getString("com.clarity.messages", "venus", null),
         Messages.getString("com.clarity.messages", "mercury", null),
         Messages.getString("com.clarity.messages", "mars", null),
         Messages.getString("com.clarity.messages", "earth", null)
       })         
  };
  
  public int size()                        { return questions.length; }
  public String getQuestion()              { return question; }
  public void setQuestion(String question) { this.question = question; }
  public Question[] getQuestions()         { return questions; }
}

Listing 1 and Listing 2 are unremarkable — they simply give me a list of questions on the server — except for the fact that I programatically pull strings from a resource bundle with a helper method. You can see how the method works by downloading the code for this article, and you can read about it in Core JavaServer Faces (see Resources).

That's it for the application's beans, except for the Wizard bean, which acts as a controller for the wizard. That's where the only really interesting Java code resides in this application. I discuss the Wizard bean in the CDI: Dependency injection and conversations section.

Now that you have a good feel for the files in the application and the question beans, I'll show you how I implement the wizard's view.


The template and view

For most wizards, you can safely generalize wizard anatomy, as depicted in Figure 4:

Figure 4. Wizard anatomy
Quiz wizard buttons

Listing 3 shows a template that encapsulates that anatomy:

Listing 3. The wizard template (templates/wizardTemplate.xhtml)
<!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:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

  <h:head>
    <title>
      <ui:insert name="windowTitle">
        #{msgs.windowTitle}
      </ui:insert>
    </title>
  </h:head>
  
  <h:body>  
    <h:outputStylesheet library="css" name="styles.css" target="head"/>       
    
    <ui:insert name="heading"/>
          
    <div class="wizardPanel">
    
      <div class="subheading">
        <ui:insert name="subheading"/>
      </div>
      
       <div class="work">
         <ui:insert name="work"/>
       </div>
       
      <div class="controls">
        <ui:insert name="controls"/>
      </div>
      
    </div>      
        
  </h:body>
</html>

The specific implementation of the quiz wizard is shown in Listing 4:

Listing 4. The wizard facelet (quizWizard/wizard.xhtml)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
     xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    template="/templates/wizardTemplate.xhtml">

  <ui:define name="heading">
    <ui:include src="heading.xhtml"/>
  </ui:define> 
  
  <ui:define name="subheading">
    <ui:include src="question.xhtml"/>
  </ui:define>
  
  <ui:define name="work">
    <ui:include src="choices.xhtml"/>
  </ui:define>
   
  <ui:define name="controls">
    <ui:include src="controls.xhtml"/>
  </ui:define> 

</ui:composition>

Templates are pretty simple. They insert sections of a page that are defined by a view. In this case, the template in Listing 3 inserts the heading, subheading, work, and controls sections defined by the view in Listing 4. Encapsulating common features of views in templates makes it easier to create new views — in this case, new types of wizards.

Listing 5 shows the quiz wizard's heading section:

Listing 5. The heading (quizWizard/heading.xhtml)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
     xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

      <div class="heading">
        #{msgs.quizTitle}
      </div>

</ui:composition>

Listing 6 shows the subheading section:

Listing 6. The subheading (quizWizard/question.xhtml)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<ui:composition xmlns="http://www.w3.or g/1999/xhtml"
     xmlns:f="http://java.sun.com/jsf/core"
     xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

  <h:panelGrid columns="1" id="question">
    #{wizard.cursor+1}. #{questions[wizard.cursor].question}?
  </h:panelGrid>
    
</ui:composition>

View abstractions

Templating lets you encapsulate features that views share, letting you focus on only the things that change between views. The wizard template, for example, provides the window title, a stylesheet, and — through <div> elements — the overall structure, of each view. Because of that encapsulation of common features, you can easily implement new views by simply plugging in pieces of a page.

The wizard template defines the structure, but not the look of a view. The look is further encapsulated in CSS, giving you another degree of freedom with which you can modify the basic template of a view.

The heading in Listing 5 displays the quiz title, in this case Science Quiz, and the subheading in Listing 6 shows the question. The wizard.cursor referenced in Listing 6 is a cursor (or index, if you prefer) that points to the current question. That cursor is zero-based, so #{wizard.cursor+1} displays the question number, and #{questions[wizard.cursor].question} shows the question.

With the preliminaries, such as server-side beans and templating, now out of the way, I'll show you the really interesting stuff: how the wizard's Ajax is implemented, and how the wizard uses CDI. First, the Ajax.


The Ajax

All user interaction in the quiz wizard results in Ajax calls, and only the appropriate sections of the page are rendered when those calls return. One thing the Ajax calls do is control the enabled state of the wizard's buttons. Figure 5 shows the enabled state of the wizard buttons during the first and second questions:

Figure 5. The quiz wizard buttons
Quiz wizard buttons

Click to see larger image

Figure 5. The quiz wizard buttons

Quiz wizard buttons

The wizard Ajax is neatly encapsulated in two facelet files. Listing 7 shows choices.xhtml:

Listing 7. The choices
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
     xmlns:f="http://java.sun.com/jsf/core"
     xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
       
  <h:form id="choices">
    <h:panelGrid columns="2">  
        <h:selectOneRadio value="#{questions[wizard.cursor].answer}"
                         layout="pageDirection">
          <f:selectItems value="#{questions[wizard.cursor].choices}"/>
          <f:ajax render=":buttons"/>
        </h:selectOneRadio>
     </h:panelGrid>
  </h:form> 
    
</ui:composition>

When the user selects a radio button, JSF makes an Ajax call to the server and records the radio-button selection (the answer to the question) in a backing-bean property. When the call returns, JSF updates the wizard's buttons.

Listing 8 shows controls.xhtml:

Listing 8. The controls
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
     xmlns:f="http://java.sun.com/jsf/core"
     xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

    <h:form id="buttons">
   
        <h:panelGrid columns="4" styleClass="wizardControls">
        <f:ajax render=":question :choices buttons">

            <h:commandButton id="next" 
                        styleClass="wizardButton"
                             value="#{msgs.nextButtonText}" 
                          disabled="#{not wizard.nextButtonEnabled}"/> 
                    actionListener="#{wizard.nextButtonClicked}"/>
      
            <h:commandButton id="previous"
                        styleClass="wizardButton"
                             value="#{msgs.previousButtonText}" 
                          disabled="#{not wizard.previousButtonEnabled}"
                    actionListener="#{wizard.previousButtonClicked}"/>
        </f:ajax>
                                                              
        <h:commandButton id="finish"
                    styleClass="wizardButton"
                         value="#{msgs.finishButtonText}" 
                      disabled="#{not wizard.finishButtonEnabled}"
                        action="#{wizard.end}"/>
                                                                      
        </h:panelGrid>
        
    </h:form>
</ui:composition>

When the user clicks on the Next or Previous buttons, JSF makes an Ajax call to the server, and when the Ajax call returns, JSF updates the question, the question's choices (the radio buttons), and the buttons themselves.

The Finish button is not an Ajax button because clicking it navigates to the done page.

Notice the many references in Listings 7 and 8 to the wizard bean. That bean is effectively a controller for the quiz wizard. I'll wrap up this article by taking a look at that bean.


CDI: Dependency injection and conversations

CDI can be described as JSF managed beans on steroids. As a component of Java EE 6, CDI is in many ways a standardization of concepts that have been brewing in Spring for a long time, such as dependency injection and interceptors. In fact, CDI and Spring 3 share many similar features.

CDI lets you decouple concerns by what it refers to as loose coupling and strong typing. In doing so, it provides an almost liberating escape from the banalities of everyday Java programming, such as instantiating objects and controlling their lifetimes.

From a JSF perspective, one especially attractive feature of CDI is conversation scope. Pioneered by Seam, conversation scope is a scope with a programatically controlled lifetime, which lets you escape the draconian all-or-nothing choice between request and session.

All of the wizard's use of CDI is in the Wizard bean, shown in Listing 9:

Listing 9. The Wizard bean
package com.clarity;

import java.io.Serializable;

import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.inject.Produces;
import javax.faces.event.ActionEvent;
import javax.inject.Inject;
import javax.inject.Named;

@Named()
@ConversationScoped()
public class Wizard implements Serializable {
  private static final long serialVersionUID = 1L;
  private Questions questions = new Questions();
  private int cursor = 0;
  
  @Inject
  private Conversation conversation;@Produces @Named
  public Question[] getQuestions() {
    return questions.getQuestions();
  }
  
  public void nextButtonClicked(ActionEvent e) {
    incrementCursor();
  }

  public void previousButtonClicked(ActionEvent e) {
    decrementCursor();
  }
    
  public void incrementCursor() { ++cursor; }
  public void decrementCursor() { --cursor; }
  public int  getCursor()       { return cursor; }
  public void resetCursor()     { cursor = 0; }

  public boolean getNextButtonEnabled() {
    return cursor != questions.size() - 1 &&
    (questions.getQuestions())[cursor].isAnswered();
  }
  
  public boolean getPreviousButtonEnabled() {
    return cursor > 0;
  }
  
  public boolean getFinishButtonEnabled() {
    return cursor == questions.size() - 1 &&
    (questions.getQuestions())[cursor].isAnswered();
  }
  
  public String start() {
    conversation.begin();
    return "quizWizard/wizard";
  }
  
  public String end() {
    conversation.end();
    return "/done";
  }
  
  private void setCurrentQuestionUnanswered() {
    Question currentQuestion = (questions.getQuestions())[cursor];
    currentQuestion.setAnswered(false);    
  }
}

Nearly all of the interesting code for the quiz wizard application resides in Listing 9. First, the Wizard bean has methods that control the enabled state of the wizard's buttons, as I discussed in the preceding section. It also has methods that JSF calls when the user clicks the Next or Previous buttons. Those methods advance to the next question or move back to the previous one, respectively.

But ostensibly, the most interesting thing about the Wizard bean is its use of CDI. First, as I have throughout this series, I am using CDI's implementation of the @Named annotation (which is actually defined by JSR 330, Dependency Injection for Java) in lieu of @ManagedBean. Both annotations create a scoped bean that you can access from the JSF expression language. But CDI's managed-bean facility is much more sophisticated, so if you are using a Java EE 6 compliant server, you should prefer @Named over @ManagedBean.

If you look closely at Listing 6 and Listing 7, you can see that I'm accessing a bean named questions in the JSF expression language. You may also recall that I implemented a Questions class in Listing 2. However, you won't see a @Named annotation in Listing 2. Under normal circumstances, that lack of an annotation would produce an error, but in this case, the questions bean comes from somewhere else — it's produced by the Wizard.getQuestions() method. That method is annotated with a @Produces annotation, which means that JSF calls that method to get the Questions bean when you reference the bean in the expression language.

Then there's the Wizard bean's use of conversation scope. The Start the wizard link in the application's welcome page is wired to the Wizard bean's start() method, which begins a conversation by calling the conversation's begin() method. That method promotes the current request (which is actually a conversation that lasts for a single request) into a long-running conversation that doesn't end until it times out or someone calls the conversation's end() method. Because I've specified Conversation scope for the Wizard, its lifetime will end when the conversation ends.

You could, of course, eschew conversation scope and implement your own pseudo conversation scope in the user's session. In fact, that's exactly what many developers did, prior to conversation scope, to maintain the state of multirequest use cases in their applications. CDI takes that manual bookkeeping off your hands.

Finally, notice that I'm using CDI injection to inject a conversation into the managed bean, so I can programatically start and end a conversation. Resource injection lets me concentrate on doing things with objects instead of the banal details of creating them and controlling their lifetimes.


Conclusion

In this article, I've covered a lot of ground — Ajax wizards, templates, dependency injection, conversation scope — with surprisingly little code. With the help of JSF 2 and CDI, you can implement robust, reusable web applications with a minimum of fuss, and a maximum of flexibility and reusability.

The JSF 2 fu series is going to take a break for the rest of the summer. I'll be back in the fall with lots more to help you sharpen your JSF skills.


Download

DescriptionNameSize
Sample code for this articlej-jsf2fu-0710-src.zip13KB

Resources

Learn

Get products and technologies

  • JSF: Download JSF 2.0.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology, Web development
ArticleID=499347
ArticleTitle=JSF 2 fu: JSF wizards
publish-date=07062010