Helping ordinary people create extraordinary websites!
GET OUR NEWSLETTER
Your Email:
 

JSF for Nonbelievers: The JSF Application Lifecycle

By Rick Hightower
2005-05-05


Use Case 1: Add a New CD

In the first use case for the application, the user adds a new CD by going to the CD listing page and clicking the Add CD link, which is defined in the listing.jsp file, as shown in Listing 1.

Listing 1. Add CD button defined in listing.jsp

<h:commandLink action="#{CDManagerBean.addNew}"> 

<f:verbatim> Add CD</f:verbatim>
</h:commandLink>
This link is bound to the CDManagerBean's addNew method. The addNew method is invoked in the (final) invoke application phase of the JSF lifecycle. The action is bound to this method with the JSF binding expression #{CDManagerBean.addNew}. CDManagerBean is an alias for the application's store controller. CDManagerBean is the logical name for the controller. The controller class is a managed bean defined in the faces-config.xml file, as shown in Listing 2.

Listing 2. StoreController class defined in faces-config.xml

<managed-bean> 

<description> The "backing file" bean that backs up the CD application</description>
<managed-bean-name> CDManagerBean</managed-bean-name>
<managed-bean-class> com.arcmind.jsfquickstart.controller.StoreController</managed-bean-class>
<managed-bean-scope> session</managed-bean-scope>
</managed-bean>
Preparing the form
The addNew() method prepares the form by creating an empty CD, as shown in Listing 3.

Listing 3. addNew() creates an empty CD form

[StoreController.java]

/**
* Prepare the cdForm to add a new CD.
* This gets executed before we prompt
* the user to add a new CD.
*
* @return success
*/
public String addNew() {
if (subCategoryList == null) {
subCategoryList = new HtmlSelectOneListbox();
}

subCategoryList.setRendered(false);
this.cd = new CD();

return "success";
}
The addNew() method blanks out the CD form fields by creating a new CD. The fields of the CD form are bound to the cd property's properties. This method also blanks out the list of subcategories being displayed.

Returning a successful result
Next, the addNew() method is invoked, and control is redirected to the success mapping, which is the cdForm.jsp file. The cdForm.jsp file is defined in the faces-config.xml file, as shown in Listing 4.

Listing 4. cdForm.jsp is the success mapping for addNew()

<navigation-rule> 

<from-view-id> /listing.jsp</from-view-id>
...
<navigation-case>
<from-action> #{CDManagerBean.addNew}</from-action>
<from-outcome> success</from-outcome>
<to-view-id> /cdForm.jsp</to-view-id>
</navigation-case>

</navigation-rule>
Listing 4 states that if the user went from the listing to the addNew (#{CDManagerBean.addNew}) action, and the addNew action returned success, then would go to the cdForm.jsp.

Setting up the cdForm and panelGrid
cdForm.jsp is the form that contains the CD form. It has fields for ID, Title, Artist, Price, Category, and Subcategory. The fields are placed in a container called a panelGrid. JSF components, like AWT components, have containers and components. A container is a component that contains other components. This is an example of the composite design pattern. The panelGrid has three columns. Each field is laid out on its own row with a label and a message to display error messages for the field. The cdForm and panelGrid are defined in Listing 5.

Listing 5. cdForm and panelGrid defined

<f:view> 

<h2> CD Form</h2>

<h:form id="cdForm">

<h:inputHidden id="cdid" value="#{CDManagerBean.cd.id}"/>

<h:panelGrid columns="3" rowClasses="row1, row2">

<h:outputLabel for="title" styleClass="label">
<h:outputText value="Title"/>
</h:outputLabel>

<h:inputText id="title" value="#{CDManagerBean.cd.title}" required="true"/>

<h:message for="title" styleClass="errorText"/>

<h:outputLabel for="artist" styleClass="label">
<h:outputText value="Artist"/>
</h:outputLabel>

<h:inputText id="artist" value="#{CDManagerBean.cd.artist}" required="true"/>

<h:message for="artist" styleClass="errorText"/>

<h:outputLabel for="price" styleClass="label">
<h:outputText value="Price"/>
</h:outputLabel>

<h:inputText id="price" value="#{CDManagerBean.cd.price}" required="true"/>

<h:message for="price" styleClass="errorText"/>

<h:outputLabel for="category" styleClass="label">
<h:outputText value="Category"/>
</h:outputLabel>

<h:selectOneRadio id="category" value="#{CDManagerBean.cd.category}" immediate="true"
onclick="submit()"
valueChangeListener="#{CDManagerBean.categorySelected}">
<f:selectItems value="#{CDManagerBean.categories}"/>
</h:selectOneRadio>

<h:message for="category" styleClass="errorText"/>

<h:outputLabel for="subcategory" styleClass="label">
<h:outputText value="Subcategory"/>
</h:outputLabel>

<h:selectOneListbox id="subcategory" value="#{CDManagerBean.cd.subCategory}"
binding="#{CDManagerBean.subCategoryList}">
<f:selectItems value="#{CDManagerBean.subCategories}"/>
</h:selectOneListbox>

<h:message for="subcategory" styleClass="errorText"/>

</h:panelGrid>

<br />

<h:commandButton id="submitAdd" action="#{CDManagerBean.addCD}" value="Add CD"
rendered="#{not CDManagerBean.editMode}"/>

<h:commandButton id="submitUpdate" action="#{CDManagerBean.updateCD}" value="Update CD"
rendered="#{CDManagerBean.editMode}"/>

</h:form>

</f:view>
Notes about the code
Each input field binds the field to a property of the controller's cd property. For example, the input text field for the title is bound to the cd property with the following JSF binding expression: value="#{CDManagerBean.cd.title}".

You likely noticed that there is hardly any HTML in Listing 5. This is because the panelGrid generates most of the HMTL. Note that the real look and feel is determined by the style sheets associated with the panelGrid. The attribute rowClasses="row1, row2" sets the CSS classes for alternating rows. Row1 is white, and Row2 is gray. You can also specify the CSS classes for columns and much more. The JSF panelGrid component makes it convenient to quickly lay out a form. If you want to do something that the panelGrid does not provide, you don't have to use it: You can lay out your components using HTML. However, if you find that you use custom HTML on many pages, you may want to consider writing your own custom component. The idea is to make your reusable HTML as DRY as possible (DRY stands for don't repeat yourself, a term coined by Dave Thomas, the Pragmatic Programmer).

Something else to note about Listing 5 is that the controller presents an editMode property, which is used by the cdForm.jsp to selectively display the submitAdd button or thesubmitUpdate button; the submitAdd button is displayed when the form is not in edit mode. The submitUpdate button is displayed when the form is in edit mode. This makes it easy to use the same JSP for edit and add mode. (By default, the form is not in edit mode.) This magic is accomplished by the rendered expression on each button in the cdForm.jsp. For example, Listing 6 shows the rendered expression on the submitAdd button rendered="#{not CDManagerBean.editMode}". The submitAdd button is bound to the addCD method using the expression (action="#{CDManagerBean.addCD}") .

Listing 6. Adding a CD using the addCD() method

[StoreController.java]

/**
* Add a cd to the store.
*
* @return outcome
*/
public String addCD() {
store.addCD(this.cd);

return "success";
}
Validating the fields
Before the addCD method is invoked, JSF has to validate the fields from the GUI. This is actually fairly easy, since you haven't associated the fields with any validators. The values are copied from the request parameters to the components' values (by the components themselves) in the apply request value phase. At this point, the price is converted from a string to a float. If the user entered "abc" for the price, the conversion to float would fail, and control would be redirect to the cdForm.jsp page for the end user to fix. The h:message associated with the price would display a conversion error message. If all the values could be converted and were present (if required to be present), you could advance to validation processing. Since this example application doesn't have validators associated with the components (I'll introduce this feature in the next article), you'll simply advance to the update model values phase.

In the update model values phase, the setter methods on the CD are invoked with the converted and validated values stored in the GUI components. The addCD() method is invoked in the invoke application phase. The addCD() method uses a business delegate (a store object) to perform this operation. The addCD method uses the store object to store the CD in the system. Since the addCD method returns success, the listing will be displayed next, as defined in faces-config.xm. The navigation rule defined in faces-config.xml is shown in Listing 7.

Listing 7. Navigation rule for the addCD successful outcome

<navigation-rule> 

<from-view-id> /cdForm.jsp</from-view-id>
<navigation-case>
<from-action> #{CDManagerBean.addCD}</from-action>
<from-outcome> success</from-outcome>
<to-view-id> /listing.jsp</to-view-id>
</navigation-case>
...
</navigation-rule>


Tutorial Pages:
» Walk Through the 6 Phases of JSF's Request Processing Lifecycle
» The JSF Lifecycle: an Overview
» Phase 1: Restore View
» Phase 2: Apply Request Values
» Phase 3: Process Validation
» Phase 4: Update Model Values
» Phase 5: Invoke application
» Phase 6: Render Response
» A Working Example
» Let's Code it
» Use Case 1: Add a New CD
» Use Case 2: Edit a CD
» Use Case 3: Sort CDs
» Immediate Event Handling
» Conclusion
» Resources


First published by IBM DeveloperWorks


 | Bookmark
Related Tutorials:
» All about JAXP, Part 1
» Make Database Queries Without the Database
» Load List Values for Improved Efficiency
» 2 Ways To Implement Session Tracking
» A Simple Way to Read an XML File in Java
» Develop Aspect-Oriented Java Applications with Eclipse and AJDT

Advertise with Us!


Tutorials Scripts Web Hosting Developer Manuals
Resources