You are on page 1of 84

Essential JSF, Facelets & JBoss Seam

By Kent Ka Iok Tong Copyright 2008 TipTec Development

Publisher: Book website: Notice:

TipTec Development http://www.agileskills2.org All rights reserved. No part of this publication may be reproduced, stored in a retrieval system or transmitted, in any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior written permission of the publisher. 978-99937-929-?-? First edition April 2008

Author's email: freemant2000@yahoo.com

ISBN: Edition:

Essential JSF, Facelets & JBoss Seam

Foreword
How to learn JSF, Facelets and JBoss Seam easily?
If you're required to develop an application in JSF but are just learning it (JSF), this can be a daunting task. If you need to learn Facelets and JBoss Seam at the same time, it will quickly become unmanageable. With this book, you will have much better chances of hopping over the hurdles. How?

It has a tutorial style that walks you through in a step-by-step manner. It is concise. There is no lengthy, abstract description. Many diagrams are used to show the flow of processing and high level concepts so that you get a whole picture of what's happening. Free sample chapters are available on http://www.agileskills2.org. You can judge it yourself.

Products covered in the book


This book covers JSF 1.2 (reference implementation), Facelets 1.2, JBoss Seam 2.0, JBoss RichFaces 3.1, JBoss IDE Tools 2.0, Eclipse Europa for Java EE.

Target audience and prerequisites


This book is suitable for those learning how to develop web-based applications with JSF, along with Facelets and JBoss Seam. In order to understand what's in the book, you need to know Java and HTML. However, you do NOT need to know servlet, JSP or Tomcat.

Acknowledgments
I'd like to thank:

Helena Lei for proofreading this book. Eugenia Chan Peng U for doing book cover and layout design.

Essential JSF, Facelets & JBoss Seam

Table of Contents
Foreword.........................................................................................3 How to learn JSF, Facelets and JBoss Seam easily?...............3 Products covered in the book.....................................................3 Target audience and prerequisites.............................................3 Acknowledgments.......................................................................3 Chapter 1 Getting Started with JSF................................................7 What's in this chapter?...............................................................8 Developing a Hello World application with JSF.........................8 Installing Eclipse.........................................................................8 Installing Tomcat........................................................................9 Installing the JSF reference implementation............................10 Creating a Hello Word application............................................11 Generating dynamic content....................................................24 Retrieving data from Java code................................................31 How the JSP file generates the HTML code............................38 Debugging a JSF application...................................................40 Summary..................................................................................41 Chapter 2 Using Forms.................................................................43 What's in this chapter?.............................................................44 Developing a stock quote application.......................................44 Getting the stock quote symbol................................................44 Displaying the stock value........................................................52 Defining the page navigation....................................................54 Using a combo box...................................................................62 Inputting a date.........................................................................65 Handling conversion errors.......................................................70 Marking input as required.........................................................76 Using the calendar component.................................................77 Hooking up the managed beans..............................................80 Summary..................................................................................83 Chapter 3 Validating Input............................................................85 What's in this chapter?.............................................................86 Postage calculator....................................................................86 What if the input is invalid?......................................................93 Null input and validators...........................................................97 Validating the patron code........................................................99

Essential JSF, Facelets & JBoss Seam

Displaying the error messages in red.....................................102 Displaying the error message along with the field.................103 Validating a combination of multiple input values..................108 Summary................................................................................111 Chapter 4 Creating an e-Shop....................................................113 What's in this chapter?...........................................................114 Creating an e-shop.................................................................114 Listing the products................................................................115 Showing the product details...................................................124 Implementing a shopping cart................................................130 How Tomcat and the browser maintain the session..............139 The checkout function............................................................142 Implementing the login function.............................................144 Implementing the checkout function......................................151 Implementing logout...............................................................158 Summary................................................................................160 Chapter 5 Building Interactive Pages with AJAX......................163 What's in this chapter?...........................................................164 A sample AJAX application....................................................164 Refreshing the question only..................................................166 Refreshing the answer itself...................................................169 Giving rating to a question......................................................169 Using a modal panel to get the rating....................................172 Setting the look and feel with skins........................................176 Summary................................................................................177 Chapter 6 Using Facelets..........................................................179 What's in this chapter?...........................................................180 Setting up IDE support for Facelets.......................................180 Creating a Facelets project....................................................181 Creating your own tag............................................................188 Hiding JSF tags into HTML tags.............................................191 Forbidding direct access to xhtml files...................................193 Summary................................................................................195 Chapter 7 Providing a Common Layout with Facelets..............197 What's in this chapter?...........................................................198 Providing a common layout....................................................198 Having two abstract parts.......................................................202 Having page specific navigation cases..................................204 Summary................................................................................206

Essential JSF, Facelets & JBoss Seam

Chapter 8 Using JBoss Seam....................................................207 What's in this chapter?...........................................................208 Recreating the e-shop with Seam..........................................208 Creating the catalog page......................................................218 Displaying product details.......................................................223 Adding a product to the shopping cart...................................230 Confirming the checkout.........................................................237 Logging in...............................................................................239 Protecting the confirm page...................................................244 Implementing logout...............................................................245 Redirect vs render..................................................................247 Summary................................................................................249 Chapter 9 Supporting Other Languages....................................251 What's in this chapter.............................................................252 A sample application..............................................................252 Supporting Chinese................................................................253 Internationalize the date display.............................................259 Letting the user change the locale.........................................260 Localizing the full stop............................................................263 Displaying a logo....................................................................266 Making the locale change persistent......................................269 Localizing validation messages..............................................271 Summary................................................................................272 References..................................................................................273 Alphabetical Index......................................................................274

Chapter 1
Chapter 1

Getting Started with JSF

Chapter 1 Getting Started with JSF

What's in this chapter?


In this chapter you'll learn how to set up a development environment and develop a Hello World application with JSF.

Developing a Hello World application with JSF


Suppose that you'd like to develop an application like this:

Installing Eclipse
You need to make sure you have Eclipse v3.3 (or later) installed and it is the bundle for Java EE (the bundle for Java SE is NOT enough). If not, go to http://www.eclipse.org to download the Eclipse IDE for Java EE Developers (e.g., eclipse-jee-europa-fall-win32.zip). Unzip it into c:\eclipse. Then, create a shortcut to run "c:\eclipse\eclipse -data c:\workspace". This way, it will store your projects under the c:\workspace folder. To see if it's working, run it and make sure you can switch to the Java EE perspective:

BUG ALERT: If you're using Eclipse 3.3.1, there is a serious bug in it: When visually editing JSF pages Eclipse will frequently crash with an OutOfMemoryError. To fix it, modify c:\eclipse\eclipse.ini:

Chapter 1 Getting Started with JSF

-showsplash org.eclipse.platform --launcher.XXMaxPermSize 256m -vmargs -Xms40m -Xmx256m -XX:MaxPermSize=256m

Delete them This line must be put after -vmargs

Installing Tomcat
Next, you need to install Tomcat. Go to http://tomcat.apache.org to download a binary package of Tomcat 6.x (or later). Download the zip version instead of the Windows exe version. Suppose that it is apache-tomcat-6.0.13.zip. Unzip it into a folder, say c:\tomcat. Note that Tomcat 6.x works with JDK 5 or above. Before you can run it, make sure the environment variable JAVA_HOME is defined to point to your JDK folder (e.g., C:\Program Files\Java\jdk1.5.0_02):

If you don't have it, define it now. Now, open a command prompt, change to c:\tomcat\bin and then run startup.bat. If it is working, you should see:

10

Chapter 1 Getting Started with JSF

Open a browser and go to http://localhost:8080 and you should see:

Let's shut it down by changing to c:\tomcat\bin and running shutdown.bat.

Installing the JSF reference implementation


JSF stands for JavaServer Faces. It is just an API (some Java interfaces). To use it, you need an implementation (Java classes implementing those interfaces). There are mainly two implementations: the reference implementation from SUN and MyFaces from Apache. In this book, you'll use the former.

Chapter 1 Getting Started with JSF

11

So, go to https://javaserverfaces.dev.java.net to download a binary package of the JSF implementation which is called Mojarra. Suppose that it is jsf-1_2_07.zip. Unzip it into a folder, say c:\jsf. The JSF implementation in turn needs another library called JSTL. So, go to https://maven-repository.dev.java.net/repository/jstl/jars, download the jstl-1.2.jar file and put it into say c:\jstl.

Creating a Hello Word application


Now, in Eclipse, choose "Windows | Preferences | Web and XML | JavaServer Faces Tools | Libraries":

Click "New" and enter the information as below:

12

Chapter 1 Getting Started with JSF

The name doesn't really matter

It supports v1.2 of the JSF specification Click Add and browse to c:\jsf\lib to add these two jar files

Check this

Then while you're still in the Preferences window, choose "Server | Installed Runtimes":

Click "Add" and choose Apache Tomcat v6.0:

Chapter 1 Getting Started with JSF

13

Click "Next". Specify c:\tomcat as the Tomcat installation directory:

Click "Finish". Next, right click in the Package Explorer and choose "New |

14

Chapter 1 Getting Started with JSF

Dynamic Web Project":

Enter the information as below:

Chapter 1 Getting Started with JSF

15

The name doesn't really matter

Run this application in Tomcat

Eclipse will set some options such as compiling using Java 5

Keep clicking "Next" until you see the dialog below. Then choose your implementation:

16

Chapter 1 Getting Started with JSF

Choose it

Then, if you're on the Internet, Eclipse may try to download some XML files and may ask you to accept the licenses. Say yes. Finally, you should see the project structure:

Chapter 1 Getting Started with JSF

17

To make the jstl-1.2.jar file available to it, copy it into the WebContent/WEBINF/lib folder. Right click the project and choose "Refresh" so that Eclipse see the file. Next, you'll create the web page. To do that, right click the WebContent folder and choose "New | JSP":

Enter "hello" as the file name:

18

Chapter 1 Getting Started with JSF

Click "Finish". This will create a hello.jsp file in the WebContent folder with some initial content:

To edit it visually, right click the hello.jsp file and choose "Open With | Web Page Editor":

Chapter 1 Getting Started with JSF

19

Then you'll see:

This is the visual editing area

This is the source code

Next, in the visual editing area, type "Hello world". Note that the source code will change automatically:

20

Chapter 1 Getting Started with JSF

Alternatively, you could edit the source code and the visual display will change automatically. To run your application, you need to create a so-called "Tomcat instance". To do that, right click the "Servers" tab at the bottom and choose "New | Server":

Choose the Tomcat v6.0 runtime:

Chapter 1 Getting Started with JSF

21

Click "Next", then you'll see:

22

Chapter 1 Getting Started with JSF

Choose your Hello project and click "Add". This way it will be added to that Tomcat instance:

Chapter 1 Getting Started with JSF

23

Click "Finish". Then you should see this Tomcat instance in the "Servers" window:
To run it, just click here.

The instance is not running

Click the icon as shown above to run it (make sure you have indeed stopped the Tomcat you started from the command prompt!). Then you will see some messages in the Console window:

24

Chapter 1 Getting Started with JSF

If you see this line, it means your application was started successfully This is your project name

To run your hello.jsp page, open a browser and go to this URL:


This is called the context path. By default it is determined by the project name.
http://localhost:8080/Hello/faces/hello.jsp

It represents the JSF engine in your application

/hello.jsp is a relative path from WebContent. The JSF engine will use it to retrieve the hello.jsp file. In JSF such a relative path is called the view id. WebContent hello.jsp ...

Then you should see it working:

Generating dynamic content


Displaying static text is not particularly interesting. Next you'll output some dynamic text. Open hello.jsp. At the right hand side of the visual editing area, there is a collapsed palette:

Chapter 1 Getting Started with JSF

25

A palette is here

Move the mouse over there and the palette will appear:

Expand the "JSF Core" folder. It contains quite some items. Each item is called a tag and the folder is called a tag library (or tag lib):

26

Chapter 1 Getting Started with JSF

It is a tag lib

Each item is a tag

Each tag lib contains some tags in it and has a unique URL as its identifier, just like a Java package contains some classes in it and has a unique package name:
http://java.sun.com/jsf/core
<view> <param> <selectItem>

com.foo
class Product { ... } class Order { ... }

Now, drag the <view> tag and drop it onto the page (either before the "Hello World" text or after it. It doesn't matter):

Chapter 1 Getting Started with JSF

27

A <view> element will have been created. Why it is <f:view> instead of <view>? "f" here is used as a short hand (the "prefix") for the URL of the JSF Core tab lib, so <f:view> means the <view> tag in the JSF Core tag lib:
This is like an import statement in Java. It makes the tags in a tag lib available to this JSP file. The URL for the JSF Core tag lib

In the rest of the JSP file, you can use "f" as a short hand for the long URL.

Note that we said a <f:view> element had been created instead of a <f:view> tag. Here is the difference between a tag and an element:

28

Chapter 1 Getting Started with JSF

This is a tag. Or more specifically, it is a start tag.


<f:view> ... </f:view>

The whole thing is called an element

This is another tag (the end tag).

This <f:view> element is required whenever you need to use any JSF tag. You must put JSF tags inside it. Delete the existing "Hello world!" text. In the body of the <f:view> element, enter "Hello !":

Then on the palette, expand the "JSF HTML" tag lib. It contains JSF tags for generating HTML code. JSF can generate different markups such as HTML for normal web browsers or special markups for mobile phones. The JSF HTML tag lib contains tags that deal with HTML markup while those JSF tags having nothing to do with any specific markup are put into the JSF Core tag lib. Anyway, drag the "Output Text" tag and drop it before the exclamation mark:

Chapter 1 Getting Started with JSF

29

Note the "h" prefix. It is the short hand for the URL for the JSF HTML tag lib:
The URL for the JSF HTML tag lib

The <h:outputText> element will output some text. For example, if you like it to output the string "Paul", in the source code editor, add an attribute named "value". To do that, you use the auto-complete function in Eclipse:

30

Chapter 1 Getting Started with JSF

Choose "value" from the list:

Then input "Paul":

Note that the visual display is also updated automatically. Now, save the file, go to the browser and reload the page. You should see:

Chapter 1 Getting Started with JSF

31

Retrieving data from Java code


Next, you'll let the Output Text tag retrieve the string from Java code. First, create a Java class GreetingService in the hello package:

Input the content as below:


package hello; public class GreetingService { public String getSubject() { return "John"; } }

You'd like the JSF engine to create an instance of your GreetingService and then the Output Text tag retrieve the value of the "subject" property of that instance as the output:

32

Chapter 1 Getting Started with JSF

JSF Engine 1: Create

GreetingService

Output Text

3: Output it

2: Tell me the value of your "subject" property

To do that, the JSF engine maintains two tables (see the diagram below). Let's call them "instance table" and "definition table" respectively. Initially the instance table is empty, meaning that no object has been created yet. The definition table stores the class name for each object. If you have configured the Output Text tag to access the "subject" property of the "foo" object, then when it needs to find the text, it will ask the JSF engine for the "foo" object. The JSF engine will look up the instance table but can't such an entry for "foo". Then it will look up the definition table and find the class name (hello.GreetingService) for "foo". Then it creates a new GreetingService object and add an entry point to the instance table. Finally it tells the Output Text to use this object:
Instance table

2: Look it up in the table. Not found.

Object name ... ... ... foo


Definition table

Object instance ... ... ...

5: Add a new entry 3: Look up the class name

JSF Engine

Object name foo bar ...

Object class hello.GreetingService ... ...

1: Give me the object named "foo"

6: Here is your "foo" object 4: Create it

GreetingService

Output Text

Actually there are many such object tables in a single JSF application: For example, as shown in the diagram below, suppose that there are two browsers (client 1 and client 2) accessing the application. Assume that client 1 has sent totally two requests (request 1 and request 2) to the application and client 2 has sent one (request 3). Then there will have been an object table for each HTTP request. In addition, Tomcat will allocate a memory area for each client. Such an area is called a session. In each session, there is another object table,

Chapter 1 Getting Started with JSF

33

meaning that there is an object table for each client. Finally, there is an object table in the whole application. Which tables will be used by Output Text? Suppose that it is serving request 3, it will ask the JSF engine to find the "foo" object. The JSF engine will look up the object table associated with request 3 first. If it's there fine and it will be returned. Otherwise, it will look up the table for client 2 (because request 3 came from client 2). If it is still not found, it will look up the table for the whole application:
Output Text 1: Give me "foo" 1: Look up "foo" here Table for request 1 3: If still not found, try here.

JSF engine

Object name ... ... ...


Request 1 Client 1 Request 2

Object instance ... ... ...

2: If not found, try here. Table for client 1

Object name ... ... ...


Table for client 2

Object instance ... ... ...

Table for request 2

Object name ... ... ...


Table for request 3

Object instance ... ... ...

Object name ... ... ...

Object instance ... ... ...

Object name ... ... ...


Request 3 Client 2

Object instance ... ... ...

Table for the whole application

Object name ... ... ...

Object instance ... ... ...

As mentioned before, if the object is still not found, the JSF engine will check the definition table to find the class name and then create the object. But which table should the new object be put into? It is specified in the definition:

34

Chapter 1 Getting Started with JSF

It should go into the table for the current request (request 3 in this case) Definition table

Object name foo bar ...

Object class hello.GreetingService ... ...

Scope request session application

It should go into the table for the whole application

It should go into the table in the session for the client (client 2 in this case)

If the object is put into the request, after the request is handled, the table and that object will be discarded. If the object is put into the session, the table and that object will be discarded when there is a say 30 minutes of inactivity. Such named objects are officially called "managed beans" in JSF. They're called managed because it is JSF that manages (creates and discards) them, not you. They're called beans because they are Java beans (have a noargument constructor and provide properties):
public class GreetingService { public String getSubject() { return "Paul"; }
Getter for property "subject" No constructor defined. So the Java compiler will give one automatically. Such a constructor will have no argument:

public class GreetingService { public GreetingService() { } public String getSubject() { return "Paul"; } }

Now, let's implement this idea. To create the bean definition table, double click the faces-config.xml file:

Choose the "Managed Bean" tab at the bottom of the window:

Chapter 1 Getting Started with JSF

35

Choose this tab

Choose "request" and click "Add". Browse to choose the GreetingService class:

Click "Next". Enter "foo" as the bean name:

36

Chapter 1 Getting Started with JSF

Go ahead to finish it. Save the faces-config.xml file. This file is just an XML file. If you'd like to see the XML code, you can choose the "Source" tab at the bottom of the window:

The bean is defined here

Choose this tab

The next step is tell the Output Text tag to access the "foo" bean. To do that, edit hello.jsp. Enter "#{}" as the value as shown below. This #{} syntax tells the Output Text tag that it is not a static string. Instead, there will be a "EL expression" in it (EL stands for Expression Language):

Chapter 1 Getting Started with JSF

37

While the cursor is inside #{}, use auto-completion and choose the "foo" bean:

Then enter a dot and use auto-completion to choose the "subject" property:

38

Chapter 1 Getting Started with JSF

The result will be:

To get the real value, Output Text will evaluate the EL expression "foo.subject". It means it will look up the "foo" bean and call getSubject() on it. Save the file. Now, go to the browser and reload the page. It should work. Otherwise, run the Tomcat instance again.

How the JSP file generates the HTML code


How the JSP file generates the HTML code? When the JSF engine needs to display the hello.jsp file, it will ask the JSP (NOT JSF) engine in Tomcat to do that. First, the <%@...> lines are read by the JSP engine and are not output at all (see the diagram below). Then the normal HTML code is output as is. The JSP engine will only handle JSP tags such as <f:view> and <h:outputText> (yes, JSF tags are JSP tags). When it sees the <f:view> tag, it will ask the tag to generate HTML code. However, this tag, like all JSF tags, will not generate any HTML code. Instead, it will create a JSF component. For the case of <f:view>, it will create a so-called "View root" component which represents the root of the component tree. Then through some magical collaboration between the <f:view> tag and the <h:outputText> tag, they create an artificial UI Output component and put the text "Hello " into it so that it will output that text later. Note that if this "Hello " text appeared outside of <f:view>, it would have been output immediately and not turned into a component. The <h:outputText> will

Chapter 1 Getting Started with JSF

39

create a UI Output component. Finally the exclamation mark is put into another artificial UI Output component. At this point the JSF component tree is built but the tree hasn't generated any HTML code. Next, the JSP engine sees normal HTML again and outputs it:
These are read by the JSP engine and are not output at all

Normal HTML code is output as is

<%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <f:view>Hello <h:outputText value="#{foo.subject}"></h:outputText>!</f:view> </body> </html>
Normal HTML code is output as is 1: Create a "view root" JSF component 2: Plain HTML code is put into an artificial UI Output JSF component 3: Create a UI output JSF component 4: Plain HTML code again

View root

UI Output

value: "Hello "

UI Output

value: "!"
UI Output

At this point, the HTML output (generated by the JSP engine) is shown below and the JSP engine has finished its job. Next, the JSF engine will tell the view root to generate HTML output (tell it to "encode" itself in JSF terms). The view root will in turn tell its child components to generate HTML output. Their output will go into the marker left by the <f:view>:

40

Chapter 1 Getting Started with JSF

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> [JSF COMPONENT TREE WAS HERE] </body> </html>
Conceptually <f:view> left a marker here

JSF engine

1: Render

View root

"Hello "

2: Render

UI Output "Paul"

3: Render

UI Output

4: Render

UI Output

"!"

Debugging a JSF application


To debug your application in Eclipse, you can set a breakpoint in your Java code such as:

Then click the Debug icon in the Server window:

Chapter 1 Getting Started with JSF

41

This will start Tomcat in debug mode. If it is already running, it will be restarted.

Now go to the browser to load the page again. Eclipse will stop at the breakpoint:

Then you can step through the program, check the variables and whatever. To stop the debug session, just restart Tomcat.

Summary
In a JSF application, a page is defined by a JSP file and is identified by its view id, which is the relative path to it from the web content folder. Each JSP tag belongs to a certain tag lib. A tag lib is identified by a URL. To use a tag in a JSP file, you need to introduce a short hand (prefix) for the URL and then use the prefix to qualify the tag name. To define a JSF component tree in a JSP file, you need to have a <f:view> and put various JSF tags in it. Each JSF tag is also a JSP tag. When they're executed by the JSP engine, they will create their respective JSF components.

42

Chapter 1 Getting Started with JSF

The root of the component tree is always the view root. To generate HTML code from the component tree, the JSF engine will ask the view root to do that, which in turn will ask its child components to do the same. The process of generating markup in JSF is called encoding. The JSF Core tag lib contains JSF tags that have nothing to do with any specific markup. The JSF HTML tag lib contains JSF tags that knows about the HTML markup. Usually the former uses a prefix of "f" (standing for faces) while the latter uses a prefix of "h" (standing for HTML). The <h:outputText> tag will create an outputText component. That component will output the value its "value" attribute. That value can be static string or an EL expression in #{}. To find the value of a variable appearing in an EL expression, the JSF engine will try to find a managed bean with that name. It will try to find it in the beans associated with the request, in the session of the client and in the whole application, in that order. If it is not found, it will look up the class name and scope in the WebContent/WEB-INF/faces-config.xml file and create it, before putting it into the right location. For a class to be used as a managed bean class, it needs to be a Java bean, i.e., it has a no-argument constructor and provides getters and/or setters for certain properties.

43

Chapter 2
Chapter 2

Using Forms

44

Chapter 2 Using Forms

What's in this chapter?


In this chapter you'll learn how to use forms to get input from the user.

Developing a stock quote application


Suppose that you'd like to develop an application like this:

That is, the user can enter the stock id and click OK, then the stock value will be displayed.

Getting the stock quote symbol


Let's do it. Create a new Dynamic Web project (with JSF enabled) named StockQuote. Copy the jstl jar file into WEB-INF/lib. Then create a getquotesymbol.jsp file in WebContent. Locate the <form> tag in the JSF HTML tag lib. Drag and drop it onto the page:

Chapter 2 Using Forms

45

When you dropped the <h:form> tag, it noted that you didn't have a <f:view> element, so it created one for you.

The <h:form> tag will create a JSF Form component

For the text field, use the <Text Input> tag in the JSF HTML tag lib. Put it inside the form:

For the OK button, use the <commandButton> tag in the JSF HTML tag lib:

46

Chapter 2 Using Forms

It is displaying "Submit Query". To change it to "OK", set its "value" attribute:

Here is the component tree that will be built:

Chapter 2 Using Forms

47

UI View Root UI Form

UI Input

UI Command

To retrieve the symbol entered by the user, you can link the UI Input component to a property of a Java object:
UI View Root UI Form

class QuoteQuery { String sym; }


UI Input

UI Command

To do that, create such a QuoteQuery class in the stockquote package:


package stockquote; public class QuoteQuery { private String sym; public String getSym() { return sym; } public void setSym(String sym) { this.sym = sym; }

Then create a managed bean definition for it by modifying faces-config.xml:

48

Chapter 2 Using Forms

Save the file. Then in getquotesymbol.jsp, set the "value" attribute of the <inputText> tag:

This way, when the form is submitted, the symbol entered by the user will be stored into the "sym" property of this "quoteQuery" managed bean:

Chapter 2 Using Forms

49

class QuoteQuery { String sym; }

It will be set to "MSFT"

In fact, this linkage is bi-directional: When the UI Input component encodes itself, it will get the value of the "sym" property and display it in the HTML input field:
class QuoteQuery { String sym = "IBM"; }

It will display "IBM"

Let's look at the whole render and submit process in details. First, the JSP engine creates the component tree (see the diagram below). The JSF engine gets access to the tree and ask it to encode. It will ask its child components to encode and so on. For the UI Input component, it will try to read the "sym" property of the "quoteQuery" bean. As the bean doesn't yet exist, the JSF engine creates the bean. The UI Input component gets the value ("IBM") and outputs it in the HTML <input> element. In order to be able to handle the form submission, the JSF engine performs some extra action: It generates a unique request id, saves the component tree into the session indexed by the request id and includes this request id into the form as a hidden field. Finally the "quoteQuery" bean is destroyed along with the request. This is called the Render Response phase:

50

Chapter 2 Using Forms

JSP engine 1: Create the tree 6: Output the value ("IBM") UI View Root UI Form 5: Read its "sym" property UI Input 3: I need to access a bean named "quoteQuery" quoteQuery

9: Destroy

... 2: Encode JSF engine

4: Create 8: Output the request id into a hidden field Session for this client Request id: 123 ... ... ...

... <form> <input type="input" value="IBM"> <input type="hidden" value="123"> </form>

7: Generate a unique request id and save the tree under it

When the form is submitted (see the diagram below), the JSF engine will get the request id from the hidden field and use to look up the component tree and load it. This is called the Restore View phase:

Chapter 2 Using Forms

51

UI View Root UI Form

UI Input

MSFT 123
1: Form submission request arrives JSF engine ... 2: Use 123 to retrieve the tree

Session for this client Request id: 123 ... ... ...

Then the JSF engine asks the UI View Root to extract the values from the request (strings). It will in turn ask each child component to do that and store the value locally into itself. The purpose is that if later a value is found to be invalid (e.g., "abc" for an int), that invalid value will still be there and can be redisplayed to the user. The act of extracting the value and storing it locally is called decoding. The phase of decoding is called the Apply Request Values phase:
UI View Root UI Form

2: Extract the values from the request 3: Store it locally

MSFT 123

1: Extract the values from the request JSF engine

UI Input

raw value: MSFT ...

...

Next, the JSF engine will ask the UI View Root to set the locally stored values into the managed beans. For the UI Input component, it will set the locally stored value into the "sym" property of the "quoteQuery" bean. As the bean doesn't yet exist, the JSF engine creates the bean. Therefore, this bean is NOT the same bean used in rendering. The phase of setting the locally stored values into the managed beans is called the Update Model Values phase:

52

Chapter 2 Using Forms

UI View Root UI Form 2: I need to access a bean named "quoteQuery"

UI Input

raw value: MSFT ...


4: Set the locally stored value into the bean

JSF engine

1: Set the values into the beans

...

3: Create it. It is NOT the same bean used in rendering!

quoteQuery

Displaying the stock value


The next step is to display the stock value in a result page. Let's call it quoteresult.jsp. Create it in WebContent. By the way, if you'd like to open all JSP files using the Web Page Editor, you can set it as the default. To do that, choose "Window | Preferences", choose "General | Editors | File Associations" on the left hand side, choose *.jsp in the upper half of the window, choose the Web Page Editor in the lower half and set it as the default:

Chapter 2 Using Forms

53

1: Choose it

2: Choose it

3: Choose it

4: Click here

Modify quoteresult.jsp like:

Warning

You may notice a yellow line here: It is warning that it can't find a "stockValue" property in the bean. This is correct. It doesn't have such a property now. You will create a getStockValue() method in the Java class in the next step.

Create the getStockValue() method:

54

Chapter 2 Using Forms

public class QuoteQuery { private String sym; public String getSym() { return sym; } public void setSym(String sym) { this.sym = sym; } public int getStockValue() { return sym.hashCode() % 100; }
Normally you should find out the stock value for the given symbol. Here, you just get a fake value: the hash code of the symbol modulo 100.

Now the result page is ready. The only missing question is how to display it after the form is submitted?

Defining the page navigation


To do that, you need to tell the JSF engine something like this:
The current view id /getquotesymbol.jsp Each branch is called a navigation case /quoteresult.jsp

The next view id

If outcome is "ok"

If outcome is "..."

another view id

The whole thing is called a navigation rule

Usually you'll tell the JSF engine the outcome in a new phase called Invoke Application phase (see the diagram below), which occurs after the Update Domain Values phase. Then it will use the current view id and the outcome to look up the navigation rules to determine the next view id, which will be rendered in the Render Response phase:

Chapter 2 Using Forms

55

2: Use the current view id and outcome to find the next view id Navigation rules

JSF engine

1: Set the outcome Restore view Apply request values Update domain values Invoke application

Render response

3: Render the next view in the Render Response phase

Now, let's define the navigation rules. To do that, open faces-config.xml and choose the "Navigation Rule" tab at the bottom of the window:

Choose this tab

On the palette on the right edge, choose the "Page" tool:

56

Chapter 2 Using Forms

Then click on the white area in the window. It will pop up a window to let you choose a JSP file (see below). Choose getquotesymbol.jsp:

Then the page will appear in the window:

Chapter 2 Using Forms

57

Now do the same thing for the quoteresult.jsp page:

To link them up, choose the "Link" tool on the palette:

Click on the getquotesymbol page and then on the quoteresult page. A link will

58

Chapter 2 Using Forms

be created:

To specify the outcome for the link, choose the "Select" tool on the palette (or just press Escape):

Then choose the link and choose the "Properties" tab. Enter the outcome there:

Chapter 2 Using Forms

59

Enter the outcome

If you're curious, you can see its XML source in the "Source" tab:
<faces-config ...> <managed-bean> <managed-bean-name>quoteQuery</managed-bean-name> <managed-bean-class>stockquote.QuoteQuery</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> <navigation-rule> <display-name>getquotesymbol</display-name> <from-view-id>/getquotesymbol.jsp</from-view-id> <navigation-case> <from-outcome>ok</from-outcome> <to-view-id>/quoteresult.jsp</to-view-id> </navigation-case> </navigation-rule> </faces-config>

Save the file. Finally, modify getquotesymbol.jsp to specify the outcome:


... <f:view> <h:form> <h:inputText value="#{quoteQuery.sym}"></h:inputText> <h:commandButton value="OK" action="ok"></h:commandButton> </h:form> </f:view> ... This is the outcome

If the button is clicked, it will note that in the Apply Request Values phase (see the diagram below) and will register a listener to be invoked in the Invoke Application phase. That listener will set the outcome when it is executed:

60

Chapter 2 Using Forms

Request ... JSF engine 1: Was I clicked? 2: Schedule a listener to be executed 4: Set the outcome Listener 3: Execute

UI Command

Restore view

Apply request values

Update domain values

Invoke application

Render response

Why it doesn't simply execute the listener in the Apply Request Values phase? It is because it would like to update the beans (Update Domain Values) first before performing other any actions. Now, you're about to run it. To do that, you need to add this project to the Tomcat instance. So, choose the "Servers" tab and double click on the Tomcat instance, you'll see its settings:

Double click on it

Choose the "Modules" tab at the bottom of the window. It will display all the web applications that it is hosting. Currently it should contain only the Hello project:

Chapter 2 Using Forms

61

Click "Add Web Module" to add the StockQuote project to it:

The path determines this part of the URL http://localhost:8080/StockQuote/faces/getquotesymbol.jsp

Save the file. Now, start the Tomcat instance and go to http://localhost: 8080/StockQuote/faces/getquotesymbol.jsp in a browser. It should work:

62

Chapter 2 Using Forms

Using a combo box


Suppose that you'd like to change the application so that the user will choose from a list of stock symbols instead of typing in one:

To do that, delete the <h:inputText> in getquotesymbol.jsp and put a <h:selectOneMenu> there:

Chapter 2 Using Forms

63

This will create a UI Select One component which will allow a single item to be selected only. It should still link to the "sym" property of the bean. So, set its "value" attribute just like before:

To specify the available items in the combo box, choose the <selectItems> tag in the JSF Core tag lib. Note that it is in the JSF Core tag lib instead of the JSF HTML tag lib because selection items in JSF are generic and have nothing to do with HTML markup. You'd like drop the <selectItems> element into the body of the <selectOneMenu> element, but in the visual editor you can only drop it before the <selectOneMenu> element or after it but not inside it. Fortunately, you can do that in the text editing area. Just make sure that you click the <selectItems> tag and release the mouse right away, then click inside the <selectOneMenu> element:

64

Chapter 2 Using Forms

Click here to drop

The <selectItems> element will retrieve the items from a managed bean (again, using its "value" attribute). To do that, create a StockService class in the same package:
... import java.util.List; import javax.faces.model.SelectItem; public class StockService { an item for the user's selection. private List<SelectItem> symbols; public StockService() { symbols = new ArrayList<SelectItem>(); symbols.add(new SelectItem("MSFT")); symbols.add(new SelectItem("IBM")); symbols.add(new SelectItem("RHAT")); } public List<SelectItem> getStockSymbols() { return symbols; } }
It can return a List or an array This class is provided by JSF. It represents

This string will be displayed to the user

Make a managed bean from it. As it is a global thing, put it into the application scope:

Chapter 2 Using Forms

65

Set the "value" attribute of the <selectItems> tag:


<f:view> <h:form> <h:selectOneMenu value="#{quoteQuery.sym}"> <f:selectItems value="#{stockService.stockSymbols}"/> </h:selectOneMenu> <h:commandButton value="OK" action="ok"></h:commandButton> </h:form> </f:view>

Now run the application and it should work. However, you may wonder why you need to provide it with a List<SelectItem> instead of just a List<String>? The reason is, for example, instead of displaying short codes like "MSFT" to the user, you'd like to display a longer description such as "Microsoft". Internally all your processing will still use "MSFT" though. To do that, modify the code:
This string will be set into the bean

class QuoteQuery { String sym; }


This string will be displayed to the user

public class StockService { private List<SelectItem> symbols;

public StockService() { symbols = new ArrayList<SelectItem>(); symbols.add(new SelectItem("MSFT", "Microsoft")); symbols.add(new SelectItem("IBM", "IBM")); symbols.add(new SelectItem("RHAT", "Red Hat")); } public List<SelectItem> getStockSymbols() { return symbols; }

Inputting a date
Suppose that you'd like to allow the user to query the stock value on a particular

66

Chapter 2 Using Forms

date:

To do that, modify getquotesymbol.jsp:


<f:view> <h:form> <h:selectOneMenu value="#{quoteQuery.sym}"> <f:selectItems value="#{stockService.stockSymbols}"/> </h:selectOneMenu> on <h:inputText value="#{quoteQuery.quoteDate}"></h:inputText> <h:commandButton value="OK" action="ok"></h:commandButton> </h:form> </f:view>

Provide the "quoteDate" property in the bean and use it to calculate the stock value:
public class QuoteQuery { private String sym; private Date quoteDate = new Date(); public Date getQuoteDate() { return quoteDate; } public void setQuoteDate(Date quoteDate) { this.quoteDate = quoteDate; } public String getSym() { return sym; } public void setSym(String sym) { this.sym = sym; } public int getStockValue() { return (sym + quoteDate.toString()).hashCode() % 100; }

The UI Input component knows about a few common types such as java.lang.Integer and java.lang.Double and can convert between a value of such types and a string. Unfortunately, it doesn't know java.util.Date. To solve this problem, you need to tell it to use a Date converter (see the diagram below). When it needs to encode itself, it will get the value of its "value" attribute. Here it will get a Date object. Then it will ask the converter to convert this value into a string. Finally it will output the string into the HTML <input> field:

Chapter 2 Using Forms

67

<input type="text" value="6/20/2007" ...>


Date 3: The string is "6/20/2007" converter Year: 2007 Month: 6 Day: 20 2: Convert the object (a Date) into a string for me UI Input 1: Call getQuoteDate() to get the value (a Date, but it doesn't need to know)

4: Output the string into the <input> field

class QuoteQuery { ... Date getQuoteDate() { ... } void setQuoteDate(Date d) { ... } }

When the user submits the form (see the diagram below), the JSF engine will initiate the Apply Request Values phase. As a result, the UI Input component will store the raw input string stored locally. Before the JSF engine starts the Update Domain Values phase, it will initiate a new phase called Process Validations phase. In this phase, it will ask the UI View Root to convert the raw input string into the desired data type (any Object) and optionally validate the converted object. For the UI Input component, it will ask the converter to convert its locally stored raw string to an object (a Date) and store the result locally. Finally, the JSF engine will initiate the Update Domain Values phase to update the beans:
Request

quote date: "7/28/2007" ...

UI View Root UI Form UI Text

2: Apply request values

Date converter

Raw: "7/28/2007" Converted:

1: Restore view

3: Convert the string into an Object

Year: 2007 Month: 7 Day: 28

class QuoteQuery { ... void setQuoteDate() { ... } }


4: Update domain values

Restore view

Apply request values

Process validations

Update domain values

Therefore, all you need to do is to setup a Date converter. To do that, drop a <convertDateTime> tag from the JSF Core tag lib into the <inputText> element (see the diagram below). When this <convertDateTime> tag is executed by the

68

Chapter 2 Using Forms

JSP engine, it will create a Date converter. Then it will ask its parent tag (<inputText>) to find out the JSF component its parent has created (here, it's the UI Input component). Then it will tell the UI Input component to use that Date converter:
<f:view> that you created? Oh, it's that <h:form> UI Input. <h:selectOneMenu value="#{quoteQuery.sym}"> <f:selectItems value="#{stockService.stockSymbols}"/> </h:selectOneMenu> on <h:inputText value="#{quoteQuery.quoteDate}"> <f:convertDateTime/> </h:inputText> <h:commandButton value="OK" action="ok"></h:commandButton> </h:form> </f:view>
1: Create a Date converter 2: What is the JSF component

Date converter 3: Tell it to use this converter

UI Input

Now run it and it should work:

Why it shows "Jan 19, 2008" instead of say 1/19/2008 or 19/1/2008? This is controlled by two factors: the most preferred language set in the browser and the style used by the converter. Here are some examples: Short style Medium style US English 1/19/2008 Jan 19, 2008 Long style Full style

January 19, 2008 Saturday, January 19, 2008 ... ...

UK English

19/1/2008

...

... ... ... ... ... As you can see, by default it uses the medium style. To tell it to use say the

Chapter 2 Using Forms

69

short style, do it this way:


<f:view> <h:form> <h:selectOneMenu value="#{quoteQuery.sym}"> <f:selectItems value="#{stockService.stockSymbols}"/> </h:selectOneMenu> on <h:inputText value="#{quoteQuery.quoteDate}"> <f:convertDateTime dateStyle="short" /> </h:inputText> <h:commandButton value="OK" action="ok"></h:commandButton> </h:form> </f:view>

Now, run it and it should be like:

To change the most preferred language, you can change it in the browser. For example, in Firefox, it is set in "Tools | Options | Advanced":

Click "Choose":

70

Chapter 2 Using Forms

Handling conversion errors


What if the user enters some garbage like "abc" as the date? In the Process Validations phase, the Date converter will try convert "abc" to a Date object but it will fail. Then it will log an error message into a list of messages associated with the request and tell the JSF engine to jump to the Render Response phase, skipping any phases in between (i.e., the Update Domain Values phase and the Invoke Application phase):
Request

abc

2: Log an error Message list message

abc is invalid

UI Text

Date converter

Raw: "abc"

1: Try to convert it to a Date but fails

Restore view

Apply request values

Process validations

Update domain values

Render response

3: Jump to the render response phase directly

Invoke application

Chapter 2 Using Forms

71

This is good, because if anything is wrong, you don't want to update the beans (Update Domain Values) and don't want to change the view id (Invoke Application) so that the original page is redisplayed. What else would you like to do? To display an error message in the original page. To do that, modify getquotesymbol.jsp:
<f:view> <h:messages></h:messages> <h:form> <h:selectOneMenu value="#{quoteQuery.sym}"> <f:selectItems value="#{stockService.stockSymbols}"/> </h:selectOneMenu> on <h:inputText value="#{quoteQuery.quoteDate}"> <f:convertDateTime dateStyle="short" /> </h:inputText> <h:commandButton value="OK" action="ok"></h:commandButton> </h:form> </f:view>
UI View Root It will create a UI Messages component

UI Messages

UI Form

...

UI Input

...

The UI Messages component will display all the messages in the message list (if there is no message, it will render nothing). Now, run the application, enter "abc" as the date and click OK, you'll see:

72

Chapter 2 Using Forms

The whole path is called the client id of the UI Input component

UI View Root UI Messages

The id of the UI Form component

Form

The id of the UI Input component ...

UI Input

...

The client id is mainly used as the value of the id or name attribute of the HTML element generated. If you view the source of the HTML page, you'll see how various client ids are used:

Chapter 2 Using Forms

73

Anyway, displaying the client id is quite confusing to users. Instead, you should display a user friend description for the text field. To do that, modify getquotesymbol.jsp:
<f:view> <h:messages></h:messages> <h:form> <h:selectOneMenu value="#{quoteQuery.sym}"> <f:selectItems value="#{stockService.stockSymbols}"/> </h:selectOneMenu> on <h:inputText value="#{quoteQuery.quoteDate}" label="quote date"> <f:convertDateTime dateStyle="short" /> </h:inputText> <h:commandButton value="OK" action="ok"></h:commandButton> </h:form> </f:view>

Run it again and it will display label instead of the client id:

If you don't like this error message, you can provide your own. To do that, create a text file named messages.properties in the stockquote package (the name is not really significant as long as it has a .properties extension):

74

Chapter 2 Using Forms

This is called the resource key

You may specify TIME here when you use the converter it to convert a time

When the line is too long, you can use a backslash to tell Java to continue to the next line.

javax.faces.converter.DateTimeConverter.DATE={0} is an invalid {2}. \ Try something like {1}


The label ("quote date") An example string that is valid such as "12/20/08" JSF will fill in the user input ("abc")

Then open faces-config.xml, choose the "Others" tab, click "Message Bundle" and then click "Add":

3: Click here 2: Click here

1: Click here

Browse to select the messages.properties file:

Chapter 2 Using Forms

75

BUG ALERT: Due to a bug in Eclipse the screen may not be updated even though the code has been modified. In the source, you should see:
<faces-config ...> <application> <message-bundle>stockquote.messages</message-bundle> </application> <managed-bean> <managed-bean-name>quoteQuery</managed-bean-name> <managed-bean-class>stockquote.QuoteQuery</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>stockService</managed-bean-name> <managed-bean-class>stockquote.StockService</managed-bean-class> <managed-bean-scope>application</managed-bean-scope> </managed-bean> <navigation-rule> <display-name>getquotesymbol</display-name> <from-view-id>/getquotesymbol.jsp</from-view-id> <navigation-case> <from-outcome>ok</from-outcome> <to-view-id>/quoteresult.jsp</to-view-id> </navigation-case> </navigation-rule> </faces-config>

Now the JSF engine will load messages from this file and use them to override the default messages. Run the application and it should work:

76

Chapter 2 Using Forms

If you'd like to specify the error message for that UI Input component only, you can do it this way:
<f:view> <h:messages></h:messages> <h:form> <h:selectOneMenu value="#{quoteQuery.sym}"> <f:selectItems value="#{stockService.stockSymbols}" /> </h:selectOneMenu> on <h:inputText value="#{quoteQuery.quoteDate}" label="quote date" converterMessage="the quote date is invalid"> <f:convertDateTime dateStyle="short" /> </h:inputText> <h:commandButton value="OK" action="ok"></h:commandButton> </h:form> </f:view> This will override the message provided
by the converter. As it is the converter that is providing values for {0}, {1} and {2}, you can't use such placeholders in this string.

Marking input as required


Now the UI Input component will not accept garbage. But what if the user enters an empty string? By default the UI Text assumes that you're allowing the input to be optional. If the target data type is a string, it will remain as an empty string. If the target data type is not a string, it will convert be converted to null (in this case as the Date object). Then your code will crash at the code below:
public class QuoteQuery { private String sym; private Date quoteDate = new Date(); public Date getQuoteDate() { return quoteDate; } public void setQuoteDate(Date quoteDate) { this.quoteDate = quoteDate; } public String getSym() { return sym; } public void setSym(String sym) { this.sym = sym; } public int getStockValue() { return (sym + quoteDate.toString()).hashCode() % 100; }

To mark it as required, do it this way:


<f:view> <h:messages></h:messages> <h:form> <h:selectOneMenu value="#{quoteQuery.sym}"> <f:selectItems value="#{stockService.stockSymbols}" /> </h:selectOneMenu> on <h:inputText value="#{quoteQuery.quoteDate}" label="quote date" converterMessage="the quote date is invalid" required="true"> <f:convertDateTime dateStyle="short" /> </h:inputText> <h:commandButton value="OK" action="ok"></h:commandButton> </h:form>

Chapter 2 Using Forms

77

Now, run it while setting the date to empty, you'll see:

</f:view>

Again, if you don't like the error message, you can override it in the messages.properties file:
javax.faces.converter.DateTimeConverter.DATE={0} is an invalid {2}. \ Enter something like {1} javax.faces.component.UIInput.REQUIRED=You must input {0}!
The label

If you'd like to set it just for this UI Input component, you can do it this way:
<f:view> <h:messages></h:messages> <h:form> <h:selectOneMenu value="#{quoteQuery.sym}"> <f:selectItems value="#{stockService.stockSymbols}" /> </h:selectOneMenu> on <h:inputText value="#{quoteQuery.quoteDate}" label="quote date" converterMessage="the quote date is invalid" required="true" requiredMessage="Input is missing!"> <f:convertDateTime dateStyle="short" /> </h:inputText> <h:commandButton value="OK" action="ok"></h:commandButton> </h:form> </f:view>

Using the calendar component


In fact, you can also allow the user to choose a date:

78

Chapter 2 Using Forms

Clicking on the calendar icon will display a calendar:

To do that, you can use a JSF component library called RichFaces from JBoss. Go to http://labs.jboss.com/jbossrichfaces to download it. Suppose that it is richfaces-ui-3.1.3.GA-bin.zip. Unzip it into say c:\richfaces-ui. To use it, copy all the jar files in c:\richfaces-ui\lib into your WEB-INF/lib. RichFaces in turn needs a few third party jar files. You can go to http://agileskills2.org/EssentialJSF/richfaces to download them and put them into WEB/lib. Finally refresh the project in Eclipse. Next, modify WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app ...> <display-name>StockQuote</display-name> <welcome-file-list> ... </welcome-file-list> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup>

Chapter 2 Using Forms

79

You don't need to know the exact meaning of this code. Basically it is used to enable the RichFaces engine to intercept requests so that it can deliver Javascript to the browser. Close the getquotesymbol.jsp and open it again. Then you should see some new tag libs such as RichFaces available on the palette:

</servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <context-param> <param-name>org.richfaces.SKIN</param-name> <param-value>blueSky</param-value> </context-param> <filter> <display-name>RichFaces Filter</display-name> <filter-name>richfaces</filter-name> <filter-class>org.ajax4jsf.Filter</filter-class> </filter> <filter-mapping> <filter-name>richfaces</filter-name> <servlet-name>Faces Servlet</servlet-name> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping> </web-app>

Next, choose the <calendar> tag from the RichFaces tag lib and drop it into the getquotesymbol.jsp file and modify the file like this:

80

Chapter 2 Using Forms

<f:view> <h:messages></h:messages> <h:form> <h:selectOneMenu value="#{quoteQuery.sym}"> <f:selectItems value="#{stockService.stockSymbols}" /> </h:selectOneMenu> on <h:inputText value="#{quoteQuery.quoteDate}" label="quote date" converterMessage="the quote date is invalid" required="true" requiredMessage="Input is missing!"> <f:convertDateTime dateStyle="short" /> </h:inputText> <rich:calendar value="#{quoteQuery.quoteDate}" The same attributes converterMessage="the quote date is invalid" are supported except the "label" required="true" requiredMessage="Input is missing!"> </rich:calendar> <h:commandButton value="OK" action="ok"></h:commandButton> </h:form> </f:view>

Now, run it and it should work:

Hooking up the managed beans


For the moment, the stock value calculation is done in the QuoteQuery class:
public class QuoteQuery { private String sym; private Date quoteDate = new Date(); public Date getQuoteDate() { return quoteDate; } public void setQuoteDate(Date quoteDate) { this.quoteDate = quoteDate;

Chapter 2 Using Forms

81

In a real implementation, you will need to look up a database or connect to a network service provider to get the stock value. This kind of work is best done in the StockService class. So, to make the code more realistic, let move the calculation logic into the StockService class:
public class StockService { private List<SelectItem> symbols; public StockService() { symbols = new ArrayList<SelectItem>(); symbols.add(new SelectItem("MSFT", "Microsoft")); symbols.add(new SelectItem("IBM", "IBM")); symbols.add(new SelectItem("RHAT", "Red Hat")); } public List<SelectItem> getStockSymbols() { return symbols; } public int getStockValue(QuoteQuery q) { return (q.getSym() + q.getQuoteDate().toString()).hashCode() % 100; }

} public String getSym() { return sym; } public void setSym(String sym) { this.sym = sym; } public int getStockValue() { return (sym + quoteDate.toString()).hashCode() % 100; }

Then the code in the QuoteQuery class should call the StockService to get the stock value. But how to get access to it?
public class QuoteQuery { private String sym; private Date quoteDate = new Date(); public Date getQuoteDate() { return quoteDate; } public void setQuoteDate(Date quoteDate) { this.quoteDate = quoteDate; } public String getSym() { return sym; } public void setSym(String sym) { this.sym = sym; } public int getStockValue() { How to get access to StockService stkSrv = ???; the "stockService" return stkSrv.getStockValue(this); bean? }

To let the "quoteQuery" bean get access to the "stockService" bean, you can say so in the bean definition table. Each row in the definition table can refer to a property initialization table (see the diagram below). When the JSF engine creates the "quoteQuery" bean, it will check its property initialization table. It notes that it needs to initialize the "stkSrv" property of the "quoteQuery" bean.

82

Chapter 2 Using Forms

The value is specified as an EL expression #{stockService}. So it evaluates it (the result is the "stockService" bean) and stores the result using the setStkSrv() setter:
Definition table

Object name stockService quoteQuery ...

Object class ... ... ...

Scope application request ...


Property initialization table

Property stkSrv ... ...


public class QuoteQuery { private String sym; private Date quoteDate = new Date(); private StockService stkSrv;

Initial value #{stockService} ... ...


It will be evaluated and set using this setter

public void setStkSrv(StockService stkSrv) { this.stkSrv = stkSrv; } ... public int getStockValue() { StockService stkSrv = null; return stkSrv.getStockValue(this); }

To specify the property initialization table, select the "quoteQuery" bean in faces-config.xml:

Click here to add an entry

This is the property initialization table

Chapter 2 Using Forms

83

Click "Add" and enter the information:

You also specify the property class so that JSF engine can double check the data type. Save the file. If you're curious, you can check the source:
<faces-config ...> <application> <message-bundle>stockquote.messages</message-bundle> </application> <managed-bean> <managed-bean-name>quoteQuery</managed-bean-name> <managed-bean-class>stockquote.QuoteQuery</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> <managed-property> <property-name>stkSrv</property-name> <property-class>stockquote.StockService</property-class> <value>#{stockService}</value> </managed-property> </managed-bean> <managed-bean> <managed-bean-name>stockService</managed-bean-name> <managed-bean-class>stockquote.StockService</managed-bean-class> <managed-bean-scope>application</managed-bean-scope> </managed-bean> <navigation-rule> <display-name>getquotesymbol</display-name> <from-view-id>/getquotesymbol.jsp</from-view-id> <navigation-case> <from-outcome>ok</from-outcome> <to-view-id>/quoteresult.jsp</to-view-id> </navigation-case> </navigation-rule> </faces-config>

You can see that such a property is called a managed property because it is the JSF engine that initializes it. Anyway, run the application and it should continue to work. Note that you can let the "quoteQuery" bean access the "stockService" bean but not vice versa because the scope of the former (request) is shorter (the same is also fine) than the latter (application). In the life time of the "stockService" bean, there will be multiple "quoteQuery" beans (one for each request). It just doesn't know which one to refer to.

Summary
To handle a form submission, the JSF engine will go through the following

84

Chapter 2 Using Forms

phases: Restore View, Apply Request Values, Process Validations, Update Domain Values, Invoke Application and Render Response. If there is any error in the Process Validations phase or the Update Domain Values phase, the JSF engine will jump to the Render Response phase directly. In order to be able to restore the view, it saves the component tree along with a unique request id in the Render Response phase. Although the component tree is restored, if you're accessing request-scoped managed beans, the bean you use on form submission will not be the same as the one you used to render the page. To let the user edit a string in a text field, use the UI Input component and set its "value" attribute to link it to the property of a managed bean. To let the user choose an entry from a combo box, use the UI Select One component. You need to provide a list of SelectItem to it. Each SelectItem contains an object and its string presentation. To let the user edit an Object in a text field, provide a converter to the UI Input component. If there is a conversion error, it will log an error message. To display error messages, use the UI Messages component. To let the user click a button, use a UI Command component. Specify the outcome in its "action" attribute. The JSF engine will use the current view id to look up the right navigation rule and use the outcome to look up the right navigation case to find the next view id. The UI Command will set the outcome in the Invoke Application phase so that if there is any conversion or validation error, it will not set the outcome and the original page is redisplayed. You can customize the error messages using a resource bundle. This will affect the whole application. To customize it for a particular component, simply set the right attribute of the component. You can let one managed bean get access to another using a managed property. Make sure the referring bean has a shorter (or the same) life time (scope) than the referred one.

You might also like