In this chapter, I’ll introduce you to JSF and show you how to use it to create user interfaces for web-based applications. Within the MVC application architecture I described in Chapter 3 (refer to Figure 3-2), JSF takes the place of the controller, thereby mediating every interaction between JSP (the View) and the Model, which encapsulates the application data. JSF makes the development of web applications easier by:
- Letting you create user interfaces from a set of standard UI components wired to server side objects
- Making available four custom tag libraries to handle those UI components
- Providing a mechanism for extending the standard UI components
JSF transparently saves state information of the UI components and repopulates forms when they redisplay. This is possible because the states of the components live beyond the lifespan of HTTP requests. JSF operates by providing a controller servlet and a component model that includes event handling, server-side validation, data conversion, and component rendering. Not surprisingly, JSF doesn’t change the basic page life cycle that you already know from JSP: the client makes an HTTP request, and the server replies with a dynamically generated HTML page.
The user interface of a JSF application, called a view, consists of a tree of UI component objects of types based on the javax.faces.component.UIComponent
class. Some components are simple, such as a button or a text field. Others are complex, such as a table or a tree control element.
Be warned that JSF isn’t very easy to use, and it requires a non-negligible initial effort to get it going. However, the reward comes once you’ve familiarized yourself with JSF and can then develop user interfaces more quickly and efficiently. You will find the latest version of JSF in the master Project Object Model (POM) file for Oracle's JSF Implementation, at http://mvnrepository.com/artifact/org.glassfish/javax.faces/
. The file includes binaries, documentation, and dependencies of JSF’s recent releases. To be able to use JSF, you will need to copy javax.faces-2.1.7.jar
(or a newer version) to Tomcat’s lib
folder and restart Tomcat.
You can download the latest JSF specification (JSR-344 – JSF 2.2) by going to http://jcp.org/en/jsr/detail?id=344
and clicking on the download page
link.
Let’s begin with a simple JSF application, so that you can see how JSF works in practice.
You should start by copying into Tomcat’s webapps
the folder named simplef
you will find in the software package for this chapter. You can try it out by typing http://localhost:8080/simplef/
in your web browser. Figure 7-1 is an example of what you’ll see.
As you can see, there isn’t much to it. If you type, say, “qwerty,” and click Submit
, you will see the page shown in Figure 7-2.
Apart from the URL, which is not what you might expect, everything is pretty boring. If you click on Another
, you go back to the first page, as shown in Figure 7-3.
Again, nothing to get excited about. But notice that the string you typed in the first page appeared in the second one and again in the first one as the default for the input field. What is exciting in this example is how easily this was accomplished with JSF. Listings 7-1 and 7-2 show the two JSP pages of the example.
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<html><head><title>First Page</title></head><body>
<f:view>
<h:form>
<h:outputText value="Type something here: "/>
<h:inputText value="#{aStringBean.str}" />
<h:commandButton action="goOn" value="Submit" />
</h:form>
</f:view>
</body></html>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<html><head><title>Second page</title></head><body>
<f:view>
<h:form>
<h:outputText value=""#{aStringBean.str}" "/>
<h:commandButton action="goBack" value="Another" />
</h:form>
</f:view>
</body></html>
The first two lines of both JSP pages load two of the JSF libraries I mentioned at the beginning of the chapter. The two libraries, core
and html
, contain all custom-tag definitions that implement JSF.
The first JSF element you encounter in both pages is f:view
, which is a container for all JSF actions. The next one is h:form
, the JSF element that generates the pair <form>
..</form>
of HTML tags. The three JSF elements h:outputText
, h:inputText
, and h:commandButton
generate respectively the three HTML elements <span>
..</span>
, <input type="text"
../>
, and <input type="submit"
../>
. If you had used h:commandLink
instead of h:commandButton
, JSF would have generated a hyperlink with the HTML-tag a
and the attribute href
instead of a submit
button.
Notice that the value
attributes of h:inputText
in first.jsp
and h:outputText
in second.jsp
contain the EL expression #{aStringBean.str}
. This is the first time you encounter a practical example of an EL expression representing an lvalue (see the Expression Language section in Chapter 4).
The expression ${aStringBean.str}
(for the record: illegal in this case) would have been evaluated by Tomcat immediately. Tomcat would have replaced it with the value obtained by executing the method aStringBean.getStr()
.
But, with the #
replacing the $
, the only thing that happens is that JSF assigns an identifier to the attribute str
of the object aStringBean
.
Listing 7-3 shows the HTML page that first.jsp
generates (reformatted by me for easy reading).
<html><head><title>First Page</title></head><body>
<form id="id_1" name="id_1" method="post"
action="/simplef/first.jsf;jsessionid=E48B69EEB4C81EB74C85C1ABCFBB8AE0"
enctype="application/x-www-form-urlencoded"
>
<input type="hidden" name="id_1" value="id_1"/>
Type something here: <input type="text" name="id_1:id_3"/>
<input type="submit" name="id_1:id_4" value="Submit"/>
<input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState"
value="5073854143807380359:-1196606070653851981" autocomplete="off"
/>
</form>
</body></html>
Whenever you see id
, the generated code actually contained j_id_jsp_58993504
, but I did a global replace with id
because I found the long automatically generated strings somewhat distracting.
The two lines in bold are the result of the three JSF elements h:outputText
, h:inputText
, and h:commandButton
.
JSF assigned to #{aStringBean.str}
the identifier j_id_jsp_58993504_1:j_id_jsp_58993504_3
. When processing on the server the request your browser sends when you click on Submit
, JSF will assign the value you have typed (e.g., the string "qwerty"
) to the str
attribute of the object aStringBean
. This is the delayed evaluation I mentioned in Chapter 4. By saving the string in this way, JSF will have it available for the value
of h:outputText
in second.jsp
and as the default value for h:inputText
in first.jsp
when it will need to render that page again.
To continue the explanation of how JSF works, I would like to direct your attention to the fact that the URLs that appear in the browser do not match the names of the JSP pages. For example, you start the application by typing in your browser http://localhost:8080/simplef/
. What trick then takes you to first.jsp
? If you open the default JSP page index.jsp
that you find inside the simplef
folder, you will see the one-liner shown in Listing 7-4.
<html><body><jsp:forward page="/first.jsf"/></body></html>
But in the same folder there is no file named first.jsf
! To begin understanding what happens, you have to look at the web.xml
file (see Listing 7.5).
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-
app_2_5.xsd">
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
</web-app>
It defines a servlet of type javax.faces.webapp.FacesServlet
. It is the JSF servlet, which I have informally called “JSF”. It is that servlet that assigns IDs to attributes and transfers data between pages. web.xml
also maps the extension jsf
to the servlet, thereby forcing all requests for pages with extension jsf
to be sent to it.
This reveals part of the mystery: when you type http://localhost:8080/simplef/
in your browser, Tomcat executes index.jsp
, which forwards the request to first.jsf
(which actually doesn’t exist). But, because of the servlet mapping in web.xml
, Tomcat diverts your request to the JSF servlet.
The rest of the mystery is easily explained: JSF replaces the extension jsf
with jsp
, which means that the request can finally reach first.jsp
. The extension jsp
is the default, but you can replace it by inserting in the web-app
element of web.xml
an element like that shown in Listing 7-6.
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.jspx</param-value>
</context-param>
The next mystery that we have to solve is how the request generated by the form in first.jsp
reaches second.jsp
. In other words, how does the action "goOn"
cause a request to reach second.jsp
?
To solve this second mystery, you have to look at another file you find in WEB-INF
: faces-config.xml
(see Listing 7-7).
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ~CCC
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0"
>
<managed-bean>
<managed-bean-name>aStringBean</managed-bean-name>
<managed-bean-class>AString</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>str</property-name>
<property-class>java.lang.String</property-class>
<null-value></null-value>
</managed-property>
</managed-bean>
<navigation-rule>
<from-view-id>/first.jsp</from-view-id>
<navigation-case>
<from-outcome>goOn</from-outcome>
<to-view-id>/second.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/second.jsp</from-view-id>
<navigation-case>
<from-outcome>goBack</from-outcome>
<to-view-id>/first.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
Concentrate for the time being on the part I have highlighted. It tells JSF that, when the page first.jsp
ends with outcome goOn
(i.e., executes h:commandButton
with action goOn
), control should go to second.jsp
. In a more complex application, first.jsp
would include different actions, which would correspond to different navigation-case
elements. Then, the JSF servlet would have a function analogous to that of a Java switch statement.
We are almost there. The next thing that needs some explanation is the managed-bean
element that you see in faces-config.xml
immediately above the first navigation rule. It tells JSF to manage a session-scoped object named aStringBean
of type AString
, and to manage its attribute named str
, which should be initialized to null
. This also means that the JSF servlet will instantiate the object automatically.
This is where the name aStringBean
you saw in the EL expressions of both first.jsp
and second.jsp
comes from. I could have chosen any name, but it is good practice to end the names of such managed beans with Bean
.
Also, the default scope is request
. But by specifying session
, I ensured that the aStringBean
is not destroyed after the first request. In the example, it would have meant that the input element in the second execution of first.jsp
would have been without default. The request
scope would have been sufficient to “remember” the default if first.jsp
had executed itself instead of second.jsp
. Note that you should be careful not to go overboard with storing information in the session, because you could affect the performance of your application. Remember that every new user causes a new session to be created.
The last piece that you need in order to complete the resolution of the JSF puzzle is the definition of the class AString
. For this see Listing 7-8.
import java.io.Serializable;
public class AString implements Serializable {
String str;
public String getStr() { return str; }
public void setStr(String s) { str = s; }
}
For simplef
to work, AString.class
should be in the classes
sub-directory of WEB-INF
.
AString
is the simplest possible bean that you need for JSF. Actually, you could drop the import
statement and remove the implementation of Serializable
. They are there because it makes possible for Tomcat to save the object to disk and to retrieve it from disk. The server possibly uses a hard disk to park session data when it is under a heavy load or when it is restarted. This is one more reason for keeping the session’s size as contained as possible. Note that Tomcat can only save objects that it is able to convert to output streams of data, and that requires the objects to be serializable.
The bottom line is that, to be completely safe, your managed beans should be serializable when defined to be in the session
scope. But you don’t absolutely need to do it. It means that under heavy load conditions, some sessions might be abruptly terminated.
Tip You will find that sometimes, if you make a mistake when developing a JSF application that causes it to fail, the application will not work again when you revert back to the version you had before making a mistake. It has to do with caching. In a development environment, the simplest way to fix it is to restart your browser and Tomcat.
Java annotations are a way of providing information about classes or objects. You saw an example of an annotation in Chapter 6 (see Listing 6.17), where I used @SuppressWarnings
("unchecked")
to tell the Java compiler how to behave when processing the statement that followed.
JSF supports annotations that you can use in a Java bean to replace the <managed-bean>
element of faces-config.xml
. In other words, if you use an annotated version of AString.java
as shown in Listing 7-9, you can completely remove the <managed-bean>
element from the faces-config.xml
shown in Listing 7-7.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.bean.ManagedProperty;
@ManagedBean(name="aStringBean")
@SessionScoped
public class AString {
@ManagedProperty(value="#{AString.str}")
String str;
public String getStr() { return str; }
public void setStr(String s) { str = s; }
}
I think it is pretty self-explanatory. If you remove the parenthesized assignment following @ManagedBean
, in JSP you have to use as bean-object name the class name with its first letter changed from uppercase to lowercase.
For simplicity, I have included in the software package for this chapter a separate folder with the annotated version of simplef
. You will find in there the WAR file, which you can easily import into Eclipse or drop into Tomcat’s webapps
folder, and an already expanded folder (which you can also drop into webapps
).
In the previous section, I showed you how to build a simple JSF application with JSP pages. To use JSF with JSP documents (i.e., in XML format), you only have to make minimal changes. To convert first.jsp
(Listing 7.1) to first.jspx
, you only need to make the standard changes described in the last section of Chapter 5 and replace the two JSF taglib
actions with the corresponding namespace declarations, as shown in Listing 7-10.
<?xml version="1.0" encoding="UTF-8"?>
<jsp:root
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
version="2.1"
>
<jsp:directive.page
language="java"
contentType="application/xhtml+xml;charset=UTF-8"
/>
<jsp:output omit-xml-declaration="false"/>
<jsp:output
doctype-root-element="html"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
/>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>First Page</title></head>
<body>
<f:view>
<h:form>
<h:outputText value="Type something here: "/>
<h:inputText value="#{aStringBean.str}"/>
<h:commandButton action="goOn" value="Submit"/>
</h:form>
</f:view>
</body>
</html>
</jsp:root>
After converting second.jsp
to second.jspx
in the same way, you also need to insert into web.xml
the context-param
element shown in Listing 7-6, otherwise JSF will keep looking for files with extension jsp
. Finally, to complete the conversion to XML you will need to make a global replace from jsp
to jspx
in faces-config.xml
, so that the navigation rules will keep working. You will find all the updated sources in the folder simplefx
as part of the software package for this chapter.
Notice that we didn’t need to do any conversion inside the body
elements of the JSP pages. This is because there were no scripting elements to convert. With JSTL, JSF, and other custom actions that you acquire or develop yourself, you can write JSP in XML format without much effort.
There is another reason for switching from JSP pages to JSP documents: it will unlock for you pieces of JSF 2.0 functionality that otherwise you wouldn’t be able to use. One example is implicit navigation.
You saw that in faces-config.xml
you need to specify to which document you want the control to move when you request a particular action from within a particular document. The navigation elements for the simplexf
applications are those shown in Listing 7-11.
<navigation-rule>
<from-view-id>/first.jspx</from-view-id>
<navigation-case>
<from-outcome>goOn</from-outcome>
<to-view-id>/second.jspx</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/second.jspx</from-view-id>
<navigation-case>
<from-outcome>goBack</from-outcome>
<to-view-id>/first.jspx</to-view-id>
</navigation-case>
</navigation-rule>
In particular, the first navigation rule tells JSF that when it executes the element <h:commandButton action="goOn" value="Submit"/>
in first.jspx
, it should transfer control to second.jspx
(which JSF renames second.jsf
so that a subsequent request from the user goes back to the JSF servlet).
From release 2.0 of 2009, JSF lets you navigate without defining navigation rules in faces-config.xml
, provided that:
- the action’s value (i.e., what you write in the
from-outcome
element offaces-config.xml
) is identical to the name of the destination document (without its extension and the dot), and- the extension of the destination document is
xhtml
.
Pity that the JSF Expert Group didn’t provide the choice of other extensions. Isn’t it? But you don’t need to worry, because JSP documents don’t need the extension jspx
!
In the software package for this chapter, you will find yet another version of what originally was the simplef
application. I named it simpleh
. The only differences from the previous version (simplefx
) are:
first.jspx
has becomefirst.xhtml
second.jspx
has becomesecond.xhtml
- In first.xhtml, the action
"goOn"
has become"second"
- In second.xhtml, the action
"goBack"
has become"first"
- In
web.xml
, the elementcontext-param
is no longer there, because the extensionsjspx
have gone- The file
faces-config.xml
has disappeared, because it no longer serves any purpose.
XHTML pages used to develop JSF applications are called facelets. Giving the xhtml
extension to JSP documents is only a way of generating the XHTML pages with JSP rather than coding them by hand.
Note If somebody tells you that JSP is out and facelets are in, tell them that things are not as black-and-white as they think! But please be careful when mixing JSF and JSP/JSTL, because it can be confusing. Also, before implementing complex pieces of code with JSP, you might like to investigate whether you can do it more simply with JSF.
Now that you have seen an example of JSF, let’s have a closer look at how JSF does its job. For that, refer to Figure 7-4. Note that the figure only shows what JSF does when the user types valid values into the input fields of the page that sends the request. Read on for more details.
- Restore View: The JSF servlet builds the view of the requested page as a component tree that contains the information associated with all components of the page. If the page is requested for the first time, JSF creates an empty view, wires event handlers and validators (if any) to its components, and saves it in a
FacesContext
object, before jumping directly to Render Response. By saving the view, JSF makes it possible to repopulate the page if necessary—for example, when the user doesn’t fill out a form as required. If the same page was displayed before and component states were saved, JSF uses that information to restore the page to its current state.- Apply Request Values: JSF goes through the component tree and executes each component’s
decode
method, which extracts values from the request parameters, or possibly from cookies or headers. It also automatically converts the parameters that are associated with object properties of nonstring types. Conversion errors cause error messages to be queued to theFacesContext
object. In some cases, typically when the user clicks on controls, the servlet also generates request events and queues them toFacesContext
. For components that have theimmediate
event-handling property set totrue
, JSF also validates them and saves them in their component instances withinFacesContext
.- Process Validation: The servlet invokes the
validate
methods for all components of the validators that had been registered during Restore View. The validation rules are those you define or, by default, those predefined by JSF. For eachvalidate
method that returnsfalse
, the servlet marks the component as invalid and queues an error message to theFacesContext
. At the end of this phase, if there are validation errors, JSF jumps directly to Render Response, so that error messages can be displayed to the user.- Update Model Values: During this phase, the values of the components are copied to the corresponding properties of the managed beans that are wired to them. JSF does it by executing the component method
updateModel
, which also performs type conversions when necessary. Conversion errors cause error messages to be queued toFacesContext
.- Invoke Application: During this phase, the servlet processes the application-level events by executing the corresponding handlers. When the user submits a form or clicks on a link of a JSF application, the JSF servlet generates a corresponding application-level event. One of the tasks you have to do when developing a JSF application is to assign a handler to each one of the possible application events. This is where you also specify what should happen next, by returning outcomes that you have linked to possible next pages, either with a navigation case or implicitly, as I showed you in the previous section.
- Render Response: The servlet creates a response component tree and delegates the rendering of the page to Tomcat. Each component renders itself as Tomcat goes through the corresponding JSF tags. At the end of this phase, the state of the response is saved so that the servlet can access it during the Restore View phase of subsequent requests to the same page.
Before looking at an application, I need to spend a few words on the JSF mechanism to handle events, because you cannot really understand how JSF works unless you know a thing or two about event handling.
As an example, let’s see what role the event handling plays when a user clicks on a Submit
button. The JSF UI components used to represent button HTML elements are objects of type javax.faces.component.html.HtmlCommandButton
, which is a class extending the more general javax.faces.component.UICommand
. As with any other HTML page, by clicking on the Submit
button in a JSF application, the user triggers the sending to the server of an HTTP request that contains the ID of the button as a parameter name.
As I’ve already mentioned, during the Apply Request Values phase, JSF executes the decode
method of each component of the page. First, the decode
method scans the parameter names to see whether one matches the ID of the component the method belongs to. In our example, the decode
method of the UICommand
object associated with the button clicked by the user finds the component ID among the request parameters, precisely because the user clicked the button. As a result of finding its own ID, the component instantiates an event object of type javax.faces.event.ActionEvent
and queues it up.
At this point, you have to distinguish between situations in which all the input fields of a form need to be validated and those in which only a partial validation is appropriate. For example, in an online shop such as the eshop
application, the shopper must be able to add further books to the shopping cart even after reaching the checkout page, where the shopper is asked to provide payment information. To make that possible, you must ensure that the validation of the payment data is skipped if the user selects a book category or searches for new titles. If you allowed the validation of empty or partially filled payment fields to proceed, the application would report one or more errors and prevent the shopper from going back to look for new books.
You solve this issue by specifying that the handling of both the book search and the category selection be done during Apply Request Values, while leaving the handling of the payment data to follow the normal life cycle. If it turns out that the user wants to shop for new books rather than complete the checkout, control then jumps directly to the Render Response phase, thereby skipping the intermediate phases where payment data would have been validated and processed.
In the next chapter, you will see in detail how this is done in the JSF version of eshop
.
The first two sections of this chapter showed you examples of simple JSF applications that used a handful of elements: f:view
, h:form
, h:outputText
, h:inputText
, and h:commandButton
. You will recall that the prefix h
was associated with the HTML component library, and the prefix f
with the JSF core library. Besides those two libraries, JSF 2 consists of two additional custom-tag libraries: facelets
, normally associated with the prefix ui
, and composite
, with prefix composite
.
In the rest of this chapter, I will briefly describe the four libraries and show you more examples. In the next chapter, I will describe how to use more of the tags by referring to a JSF-version of the eshop
application.
You can find a complete list of tags with associated documentation at http://java.sun.com/javaee/javaserverfaces/reference/api/
.
html
LibraryAs its name suggests, JSF’s HTML library collects the tags associated with rendering HTML components. As you have already seen in the examples (e.g., with h:inputText
), you associate objects of your data model to the corresponding components by assigning value expressions that refer to the objects to specific attributes of the component tags (e.g., <h:inputText value="#{aStringBean.str}"/>
).
Although in most cases the names of the tags should already tell you their purpose, I have summarized the correspondence between tags and HTML elements in Table 7-1.
Caution The elements h:head
and h:body
are only valid in documents with extension xhtml
There are seven JSF HTML tags to render selections. To show how they differ from each other, I created in Eclipse the small project testf
. You will find it in the testf project
subfolder of the software package for this chapter. If you copy testf.war
to Tomcat’s webapps
folder, after a few seconds, you will be able to try it out by typing http://localhost:8080/testf/
in your web browser. Figure 7-5 shows you what you will see in your browser after selecting values in the controls (and hitting the Submit
button, although it is not necessary to do so).
Listing 7-12 shows the JSP document.
<?xml version="1.0" encoding="UTF-8"?>
<jsp:root
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
version="2.1"
>
<jsp:directive.page
language="java"
contentType="application/xhtml+xml;charset=UTF-8"
/>
<jsp:output omit-xml-declaration="false"/>
<jsp:output
doctype-root-element="html"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
/>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Test</title></head>
<body><f:view><h:form id="form">
<h:panelGrid columns="2" border="1" cellpadding="5">
<h:outputText value="h:selectBooleanCheckbox"/>
<h:panelGroup>
<h:selectBooleanCheckbox id="checkbox" value="#{myBean.oneValue}"/>
<h:outputText value=" just a checkbox"/>
</h:panelGroup>
<h:outputText value="h:selectManyCheckbox"/>
<h:selectManyCheckbox id="checkboxes" value="#{myBean.choices1}">
<f:selectItems value="#{myBean.selects}"/>
<f:selectItem itemLabel="everything" itemValue="42"/>
</h:selectManyCheckbox>
<h:outputText value="h:selectManyListbox"/>
<h:selectManyListbox id="listboxes" value="#{myBean.choices2}">
<f:selectItems value="#{myBean.selects}"/>
<f:selectItem itemLabel="too much" itemValue="999"/>
</h:selectManyListbox>
<h:outputText value="h:selectManyMenu"/>
<h:selectManyMenu id="menus" value="#{myBean.choices3}"
style="min-height:48px">
<f:selectItems value="#{myBean.selects}"/>
<f:selectItem itemLabel="ninenty-nine" itemValue="99"/>
</h:selectManyMenu>
<h:outputText value="h:selectOneListbox"/>
<h:selectOneListbox id="listbox" value="#{myBean.choice1}">
<f:selectItems value="#{myBean.selects}"/>
<f:selectItem itemLabel="nine" itemValue="9"/>
</h:selectOneListbox>
<h:outputText value="h:selectOneMenu"/>
<h:selectOneMenu id="menu" value="#{myBean.choice2}">
<f:selectItem itemLabel="zero" itemValue="0"/>
<f:selectItems value="#{myBean.selects}"/>
</h:selectOneMenu>
<h:outputText value="h:selectOneRadio"/>
<h:selectOneRadio id="radio" value="#{myBean.choice3}">
<f:selectItem itemLabel="nothing" itemValue="-1"/>
<f:selectItems value="#{myBean.selects}"/>
</h:selectOneRadio>
</h:panelGrid>
<h:commandButton value="Submit"/>
</h:form></f:view></body>
</html>
</jsp:root>
I have highlighted in bold the selection components. h:selectBooleanCheckbox
renders a single checkbox; h:selectManyCheckbox
, h:selectManyListbox
, and h:selectManyMenu
render multiple selections; and h:selectOneListbox
, h:selectOneMenu
, and h:selectOneRadio
render single selections.
In all cases in which you can select one or more of several items, I have included a hard-coded item in addition to a list of items provided by the managed bean through an attribute I chose to name selects
:
<f:selectItems value="#{myBean.selects}"/>
The tags wire to each HTML control a different property of the managed bean. Notice the use of the core JSF tags f:selectItem
and f:selectItems
to provide the information needed for the options of the HTML select elements.
From this example, you can also see how to use h:panelGrid
and h:panelGroup
to render an HTML table
. Differently from HTML, where you need to identify rows with tr
elements and cells within rows with td
elements, with h:panelGrid
you specify at the beginning the number of columns, and all the components between its begin and end tags “flow” from left to right into the table. If you need more than one component within the same cell, you group them together with h:panelGroup
.
Listing 7-13 shows the managed bean used to hold the items you select in the browser.
package myPkg;
import java.util.ArrayList;
import javax.faces.model.SelectItem;
public class MyBean {
@SuppressWarnings("unchecked")
private ArrayList<String>[] choices = new ArrayList[3];
private String choice1, choice2, choice3;
private Object oneValue;
private SelectItem[] selects;
public MyBean() {
selects = new SelectItem[3];
selects[0] = new SelectItem("1", "one");
selects[1] = new SelectItem("2", "two");
selects[2] = new SelectItem("3", "three");
for (int kC = 0; kC < choices.length; kC++) {
choices[kC] = new ArrayList<String>();
}
}
// ---------- Getters
public Object[] getChoices1() { return choices[0].toArray(); }
public Object[] getChoices2() { return choices[1].toArray(); }
public Object[] getChoices3() { return choices[2].toArray(); }
public String getChoice1() { return choice1; }
public String getChoice2() { return choice2; }
public String getChoice3() { return choice3; }
public Object getOneValue() { return oneValue; }
public SelectItem[] getSelects() { return selects; }
// ---------- Setters
public void setChoices(Object[] cc, int kC) {
int len=0;
if (cc != null) len = cc.length;
if (len != 0) {
choices[kC].clear();
choices[kC] = new ArrayList<String>(len);
for (int k = 0; k < len; k++) {
choices[kC].add((String)cc[k]);
}
}
}
public void setChoices1(Object[] cc) { setChoices(cc, 0); }
public void setChoices2(Object[] cc) { setChoices(cc, 1); }
public void setChoices3(Object[] cc) { setChoices(cc, 2); }
public void setChoice1(String c) { choice1 = c; }
public void setChoice2(String c) { choice2 = c; }
public void setChoice3(String c) { choice3 = c; }
public void setOneValue(Object v) { oneValue = v; }
}
There isn’t really much to explain. JSF takes care of executing the initialization method of the bean, which initializes three values to be provided for selection through the select
attribute and sets up the arrays needed to save the user’s choices.
Notice that I haven’t written a setter method for select
. This is because I didn’t need to modify the values stored there. What you should never do is to omit the getter methods, because JSF expects to be able to read the properties.
core
LibraryJSF’s core
library gives you access to APIs that are independent of a particular render kit:
- Converters. Converters let you convert between the data types of the components and those of your application objects.
- Listeners. Based on the JavaBean version 1.0.1 mechanism, you register a listener with a component to handle events that the component generates.
- Events. After the listener is registered with a component, the
FacesServlet
fires the events by invoking an event notification method of the corresponding listener.- Validators. Validators examine the value of a component and ensure that it conforms to a set of predefined rules.
In the previous examples, you have already encountered f:view
, f:selectItem
, and f:selectItems
. Most of the core tags perform operations on components. Table 7-2 provides the list of all core tags and the corresponding operations. In the table, I have highlighted in italics the few operations that do not apply to individual components. As for the HTML library, you will find more information about the core in Chapter 9.
I expect that you will find many of the tags listed in Table 7-2 obscure. You will be able to understand most of them after the next sections and chapters, but the use of some of them definitely falls outside the scope of this book.
If you are curious about what a facet is, I can tell you that it is a named sub-component specific to a particular component. For example, h:gridPanel
(which renders an HTML table) supports the two facets header
and footer
. If you include <f:facet "header"><h:outputText value="Whatever"/></f:facet>
anywhere within the body of h:gridPanel
, the rendered table will have the header “Whatever”.
I will talk about converters and validators in the next chapter, where I will describe a JSF version of the eshopx
project I introduced in Chapter 6. In this chapter, as an interesting example of core tags, I will describe how to use f:ajax
, which was first added to the core library with release 2.0. In order to do that, I will first tell you about Ajax in general, and show you how it was used before the introduction of f:ajax
.
Asynchronous JavaScript and XML (Ajax) is a mechanism for letting JavaScript communicate with the server asynchronously—that is, without reloading the page. This is possible by means of the JavaScript built in object XMLHttpRequest
. For those who are not familiar with JavaScript, I have added some notes about it in Appendix A.
In practical terms, it works like this: you create an XMLHttpRequest
object within JavaScript, use it to send a request to the server, get the response, and, presto, you have fresh data for your web page without having to reload it. Well, it sounds easy, but it’s not obvious how to do it, and it’s even more tricky to maintain. To explain how to use Ajax, I’ll show you a simple example of a page that displays the server time. First, you need to write a JSP page to return the time (see Listing 7-14).
<%@page language="java" contentType="text/html"
%><%@page import="java.util.*"
%><% out.print(new GregorianCalendar().getTime()); %>
I’ve removed all the spaces and newlines before and after the print statement, including a newline at the end. This ensures that only the time is returned. If you type the URL of this script in a browser, you’ll get something like this:
Sat Jun 23 21:56:27 EST 2012
You’ll perhaps see some other time zone, but the format will be identical. A good place to check out the abbreviation for your time zone is http://www.timeanddate.com/library/abbreviations/timezones/
.
Now that you have a way of getting the server time, you can write the page to display it with Ajax, as shown in Listing 7-15.
<?xml version="1.0" encoding="UTF-8"?>
<!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">
<head>
<title>Example of Ajax</title>
<script type="text/javascript" src="ajax.js"></script>
</head>
<body>
<form name="tForm" action="">
<span>The time on the server is:</span>
<input type="text" name="tElement" readonly="readonly" size="30"/>
<input type="button" value="Update"
onclick="ajaxFun('tForm', 'tElement'),"
/>
</form>
</body>
</html>
As you can see, I’ve highlighted two lines. The first is where you load the file ajax.js
, which contains the JavaScript code to support the Ajax operation. The second line is where you execute the ajaxFun
JavaScript function whenever you click the Update
button. Notice that you pass to ajaxFun
the names of the form and of the input element to be updated. You could have hard-coded the string "tForm.tElement"
within JavaScript, but it would have been bad programming practice to use within ajax.js
identifiers defined elsewhere. Global variables invariably lead to code that’s a nightmare to maintain and should be avoided whenever possible.
To complete this brief introduction to Ajax, I still need to show you the JavaScript code. However, before I do that, check out Figure 7-6 to see how the browser renders the page. To test the application, copy the ajax
folder from the software package for this chapter to Tomcat’s webapps
folder and type in your browser http://localhost:8080/ajax/
.
Listing 7-16 shows the JavaScript code.
function ajaxFun(tf, te){
var tElem = eval("document." + tf + "." + te)
var ajaxReq;
try { // Firefox, Opera, IE 9, Chrome
ajaxReq = new XMLHttpRequest();
}
catch (e) { // older IEs
try{
ajaxReq = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try{ // still older IEs
ajaxReq = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
alert("Your browser does not support Ajax!");
return false;
}
}
}
ajaxReq.open("GET", "time.jsp");
ajaxReq.send(null);
ajaxReq.onreadystatechange = function() {
if(ajaxReq.readyState == 4) {
tElem.value = ajaxReq.responseText;
}
}
}
First, you instantiate an object of type XMLHttpRequest
. This works with Firefox, Chrome, Opera, and IE 9; I’m not sure whether it works with IE 7 and 8; and I know that it doesn’t work with IE 6. That’s why, to be on the safe side, I have added the code that instantiates the correct ActiveXObject
in case the instantiation of XMLHttpRequest
fails.
In any case, when ajaxReq “holds” an object of the correct type, you set up the HTML request method (e.g., GET
) and the target URL (in this case, the JSP module time.jsp
). At this point, you can send off the request.
Tip The caching of IE prevents Ajax from updating the date subsequent to the first clicking of the Update
button. To avoid this problem, you can click on IE 9’s toothed-wheel button, select Internet Options
, click on the Settings
button of the Browsing History
section, and, under Check for newer versions of stored pages
, select every time I visit the web page
. This will disable browser caching and solve the problem. You could also disable caching of a particular page by adding one of the following elements to its head
:
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
The control comes immediately back to JavaScript (the first letter of Ajax stands for asynchronous, remember?). In general, you don’t want the browser to wait for the response, and you want your page to be able to do other things. This asynchronicity makes Ajax more useful than if its operations had to be done in sequence. When the state of the request changes, the browser executes the function ajaxReq.onreadystatechange
. In that function you need to check that the request has been completed: in which case, you can then display the content of the response in the time field. Cool! In case you are curious to know the possible status codes, check out Table 7-3.
I’ve taken a minimalist approach for this example. The idea is for your server to send back an XML document, which you can then parse on the client side. You can find the latest version of the Ajax standard at the following URL: http://www.w3.org/TR/XMLHttpRequest/
.
One last thing: Listing 7-17 shows the deployment descriptor for this application.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ~CCC
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Ajax example</display-name>
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
As you can see, it is almost empty. I have only added a couple of welcome-file elements so that Tomcat tries index.html
(which is the default) only if index.xhtml
is not there.
Now that you know how Ajax works without JSF, let’s see how to use f:ajax
to achieve the same result.
Using f:ajax
instead of the mechanism I described in the previous section has several advantages, the most important of which, in my opinion, is that you no longer need to write code in JavaScript, which adds another flavor of Java to the mix (and some people also disable this on their browser). Further, f:ajax
is fully integrated with the other JSF libraries.
Figure 7-4 showed the six phases of the JSF life cycle. With f:ajax
you can selectively execute components on the server by processing them through the first five phases, or render them, by passing them through the last phase. You ajaxify a component by enclosing it within the body of f:ajax
or by passing to f:ajax
the component id.
To convert the Ajax example of the previous section to JSF’s Ajax, let’s start from ajaxf.xhtml
, shown in listing 7-18. The interesting bits are those highlighted in bold.
To test the application, copy the folder ajaxf
from the software package for this chapter to Tomcat’s webapps
folder, and type http://localhost:8080/ajaxf
in your web browser.
<?xml version="1.0" encoding="UTF-8"?>
<!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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
>
<h:head><title>Example of Ajax with JSF</title></h:head>
<h:body>
<h:form>
<h:outputText value="The time on the server is: "/>
<h:outputText id="timeField" value="#{serverTimeBean.when}"/>
<h:outputText value=" "/>
<h:commandButton value="Update">
<f:ajax render="timeField"/>
</h:commandButton>
</h:form>
</h:body>
</html>
The first highlighted line simply displays the value of the property when
of the managed bean serverTimeBean
. It is almost identical to the line
<h:outputText value=""#{aStringBean.str}" "/>
of second.jsp
(Listing 7-2) that you encountered at the very beginning of this chapter.
But this time, I have added to h:outputText
the setting of the id
attribute. This is because we need to pass it to f:ajax
, in the second group of highlighted lines.
The h:commandButton
element, contrary to what you saw in previous examples, doesn’t transfer control to another page. Its purpose is only to create an event that triggers f:ajax
. Accordingly, the action
attribute is not there and, if you look at the WEB-INF
folder of the application, you will see that no faces-config.xml
to handle navigation is present.
Every time the user clicks on the Update
button, f:ajax
sends a request to the server to obtain the value of serverTimeBean.when
, which then the h:outputText
element with id
timeField
displays. You don’t need to write JavaScript because JSF automatically generates the little script that sends the Ajax request.
But you do need a Java bean like that shown in Listing 7-19.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.bean.ManagedProperty;
import java.util.GregorianCalendar;
@ManagedBean(name="serverTimeBean")
@SessionScoped
public class ServerTime {
@ManagedProperty(value="#{ServerTime.when}")
private String when;
public ServerTime() { when = new GregorianCalendar().getTime().toString(); }
public String getWhen() { return new GregorianCalendar().getTime().toString(); }
public void setWhen(String w) { when = w; }
}
The code is almost identical to that of AString.java (Listing 7-9), the major differences being that it has an initialization method and, obviously, generates a string with the current server time. In the software package you will also find the files that complete the application, index.jsp
and web.xml
, but they are very similar to the equivalent files you already encountered with other applications.
You will obtain the same result if you replace in ajaxf.html
the content of the h:body
with the code shown in Listing 7-20.
<h:form>
<f:ajax render="@form" event="click"/>
<h:outputText value="The time on the server is: "/>
<h:outputText value="#{serverTimeBean.when} "/>
<h:commandButton value="Update"/>
</h:form>
With this settings, you ajaxify all components of the form. As a result, when you click on the Update
button, JSF sends an Ajax request, as it did before, and because the render
attribute is set to @form
, serverTimeBean.when
is updated, as before. Events applicable to whole forms are click
, dblclick
, keydown
, keypress
, keyup
, mousedown
, mousemove
, mouseout
, mouseover
, and mouseup
.
With input elements in the form, when the user changes the content in any of them, that also triggers an Ajax request. To test it, replace h:commandButton
with an h:inputText
element as shown in Listing 7-21.
<h:form>
<h:outputText value="The time on the server is: "/>
<h:outputText id="timeField" value="#{serverTimeBean.when} "/>
<h:inputText value="#{serverTimeBean.when}" size="30">
<f:ajax render="@this timeField" event="blur"/>
</h:inputText>
</h:form>
The resulting page is shown in Figure 7-7.
As long as you remain within the input field, nothing happens. When you hit enter
or click outside it, Ajax sends a request to the server to update the property specified in h:inputText
. In the example, it sends a request to set serverTimeBean.when
to “Sun Jun 24 012”. JSF does it in the Update Model Value phase. Then, during Render Response, Tomcat prepares the Javax response with two values obtained from serverTimeBean.when
, one for h:outputText
and one for h:inputText
. As ServerTime.java
always produces a fresh time string, that’s what is returned to the browser, and what you typed in the input field remains unused in the bean’s variable when
.
Possible events for input fields are: blur
, change
, click
, dblclick
, focus
, keydown
, keypress
, keyup
, mousedown
, mousemove
, mouseout
, mouseover
, mouseup
, select
, and valueChange
. The default is valueChange
.
The value of the render
attribute can be a single identifier, a space-delimited list of identifiers, or one of the special strings @all
, @this
, @form
, and @none
. One interesting thing, which I don’t necessarily recommend, is that you can specify in a single f:ajax
element the identifiers of components in more than one form. For example,
<f:ajax render=":form1:id3 id1 @this"/>
means that JSF fires a single Ajax request for the component id3
of the form with id
set to form1
, the component id1
of the form enclosing the f:ajax
element, and the component enclosing the f:javax
element.
Before we move on, I would like to show you another example of f:ajax
. Check out Figure 7-8.
You find the application in the loginf
folder of the software package for this chapter. It is very similar to ajaxf
. Listing 7-22 shows the managed bean and Listing 7-23 shows loginf.xhtml
.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="loginBean")
@SessionScoped
public class Login {
private String user = "";
public String getUser() { return user; }
public void setUser(String u) { user = u; }
private String pass = "";
public String getPass() { return pass; }
public void setPass(String p) { pass = p; }
public String getMess() {
String mess = "";
if (user.length() * pass.length() > 0) {
mess = "Welcome " + user + "!";
}
else if (pass.length() > 0) {
if (user.length() == 0) mess = "Who the %@$# are you?";
}
else {
if (user.length() > 0) mess = "No password " + user + "?";
}
return mess;
}
}
Nothing special here: a property to store the user ID, one for the password, and a read-only property to provide feedback to the user.
<?xml version="1.0" encoding="UTF-8"?>
<!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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
>
<h:head><title>Example of login with f:ajax</title></h:head>
<h:body>
<h:form>
<h:panelGrid columns="2">
<h:outputText value="User ID:"/>
<h:inputText id="user" value="#{loginBean.user}"/>
<h:outputText value="Password:"/>
<h:inputSecret id="pass" value="#{loginBean.pass}"/>
</h:panelGrid>
<h:commandButton value="Submit">
<f:ajax execute="user pass" render="mess"/>
</h:commandButton>
<br/>
<h:outputText id="mess" value="#{loginBean.mess}"/>
</h:form>
</h:body>
</html>
The two input components accept user ID and password from the user, and the last h:outputText
displays the feedback. The interesting bit is the f:ajax
element. You have already encountered the render
attribute, but the execute
attribute is new. This is how f:ajax
sends data to be processed on the server. Most of what I explained about render
applies to execute
, including the availability of special @
-values.
No more reloading of login
pages.
facelet
LibraryFacelets were originally developed as a view-handling technology in alternative to JSP. With release 2.0 of JSF, facelets have become its default view technology. But that doesn’t mean that, with the necessary care, you cannot use them together with JSP and JSTL. What makes JSF’s facelet
library interesting is that it supports templating. That is, a mechanism that allows you to minimize duplication of code when developing pages with the same layout or common content.
While JSP with jsp:include
provides an easy mechanism to re-use content, it doesn’t provide any easy way to define the same layout for different pages. It is up to you to ensure that the pages look identical when viewed in a browser.
The JSF facelet
library lets you form a page by defining a layout in an XHTML file and then filling it up with content defined in one or more other XHTMLs. I will show you an example shortly, but first, have a look at Table 7-4, which lists all tags of the facelet
library. To help you make sense of the tags, I have flagged those that are part of the templating mechanism.
In this section, I will describe templ
, an application that uses facelet templating.
To create it, I started from the example simplefx
I explained in a previous section of this chapter. You will recall that it essentially consisted of two JSP documents that invoked each other: first.jspx
asked you to type something into a text field, and second.jspx
displayed what you had typed.
To make an example of templating, I added a third page almost identical to the second one, so that I could show you how to define a template for them. To get started, let’s look at how the first two pages appear in a web browser (Figures 7-9 and 7-10).
Notice that the header of the second page is gray instead of black. The third page is identical to the second one, but its title is “Third page” and the text before the button starts with “Page 3”. To try it out, copy the folder templ
from the software package for this chapter to Tomcat’s webapps
folder, and then type in a browser http://localhost:8080/templ/
.
The application consists of the following folders and files (the folders are in bold for easy reading):
templ
first.xhtml
index.jsp
page2.xhtml
page3.xhtml
resources
css
styles.css
templates
defaults
header.xhtml
layout.xhtml
WEB-INF
classes
AString.class
AString.java
faces-config.xml
web.xml
Listing 7-24 shows the code of the first page.
<?xml version="1.0" encoding="UTF-8"?>
<jsp:root
xmlns:jsp="http://java.sun.com/JSP/Page"
version="2.1"
>
<jsp:directive.page
language="java"
contentType="application/xhtml+xml;charset=UTF-8"
/>
<jsp:output omit-xml-declaration="false"/>
<jsp:output
doctype-root-element="html"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
/>
<html 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:head><title>First Page</title></h:head>
<h:body>
<f:view>
<ui:include src="/templates/defaults/header.xhtml"/>
<h:form>
<h:outputText value="Type something here: "/>
<h:inputText value="#{aStringBean.str}"/>
<h:commandButton action="go2" value="Page 2"/>
<h:commandButton action="go3" value="Page 3"/>
</h:form>
</f:view>
</h:body>
</html>
</jsp:root>
First of all, notice that I renamed the file first.xhtml
. This is because facelet elements (i.e., those with prefix ui
) only work inside h:body
. This means that you can no longer use the HTML body
tag. As h:body
requires the extension of the document to be xhtml
, I had to ditch the extension jspx
. Old Will Shakespeare said through Juliet’s lips, “What's in a name? That which we call a rose by any other name would smell as sweet.” The same applies to first.xhtml
, which remains a valid JSP document despite the change of name.
Another difference from first.jspx
is that I moved the namespace declarations for the core and HTML JSF libraries from jsp:root
to the html
tag, and then added to them the declaration for the JSF facelet library. As none of the JSF tags are used outside the html
element, it makes sense to keep them there, which is where they normally are in XHTML documents.
Finally, notice that first.xhtml
includes a standard header with ui:include
.
So far so good. Nothing too exciting. You could have done the same with jsp:include
, without need for facelets. But now let’s look at page2.xhtml (Listing 7-25), and in particular to its h:body
element. Incidentally, I didn’t have any technical reason for renaming second.jspx
to page2.xhtml
. I just found page2
and page3
more appealing than second
and third
.
<?xml version="1.0" encoding="UTF-8"?>
<jsp:root
xmlns:jsp="http://java.sun.com/JSP/Page"
version="2.1"
>
<jsp:directive.page
language="java"
contentType="application/xhtml+xml;charset=UTF-8"
/>
<jsp:output omit-xml-declaration="false"/>
<jsp:output
doctype-root-element="html"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
/>
<html 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:body>
<ui:composition template="/templates/layout.xhtml">
<ui:define name="title">Second page</ui:define>
<ui:define name="pageNum">2</ui:define>
</ui:composition>
</h:body>
</html>
</jsp:root>
Notice that there is no h:head
element in page2.xhtml
. This is because JSF, when it encounters a ui:composition
element, it ignores everything other than the content of h:body
. You got it right: JSF only looks at the lines I have highlighted in Listing 7-25.
But then, you might ask, why do we bother with all the stuff that precedes the h:body
tag? The reason is that the file must be a valid XML document. But it is true that we can simplify it. That’s why I dropped the h:head
element (which JSF ignores anyway), without which the code remains valid XML. With a page that doesn’t use JSP tags inside h:body
, you can also get rid of the JSP elements. This is what I did with page3.xhtml, which you can see in Listing 7-26.
<?xml version="1.0" encoding="UTF-8"?>
<!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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:body>
<ui:composition template="/templates/layout.xhtml">
<ui:define name="title">Third page</ui:define>
<ui:define name="pageNum">3</ui:define>
</ui:composition>
</h:body>
</html>
Obviously, you cannot remove the JSP header elements and jsp:root
when you use JSP code inside h:body
. But you can use JSTL and your own custom-tag libraries without declaring the jsp
namespace, as long as you declare the appropriate namespaces in the html
tag. What you certainly cannot use in any case, with or without JSP declaration, are JSP scripting and directive elements, because anything enclosed between <%
and %>
is not valid XML.
Let’s go back to describing how JSF handles the pages that make use of templates.
The presence of the ui:composition
element with a defined template
attribute means that it is the template document that generates the page to be sent back to the user as a response, not the page that contains the ui:composition
element.
Listing 7-27 shows the template for page*.xhtml
.
<?xml version="1.0" encoding="UTF-8"?>
<!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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:head>
<title>
<ui:insert name="title">Default Title</ui:insert>
</title>
<h:outputStylesheet name="styles.css" library="css"/>
</h:head>
<h:body>
<f:view>
<ui:insert name="header">
<ui:include src="/templates/defaults/header.xhtml"/>
</ui:insert>
<h:form>
<h:outputText value="Page "/>
<ui:insert name="pageNum"/>
<h:outputText value=" has received "#{aStringBean.str}" "/>
<h:commandButton action="goBack" value="Back to first page"/>
</h:form>
</f:view>
</h:body>
</html>
The two highlighted lines identify two places where the template expects the “client” pages to insert content. If you go back to page2.xhtml
and page3.xhtml
(Listings 7-25 and 7-26), you will see that the two ui:define
s inside ui:composition
have the same name
attributes as the two ui:insert
s of the template.
When layout.xhtml
is used to generate the response to a request sent to page2.xhtml
, the element <ui:insert name="title">Default Title</ui:insert>
is replaced with the string “Second page” and the element <ui:insert name="pageNum"/>
is replaced with “2”. For page3.xhtml
, the string is “Third page” and the page number is “3”. Notice that the body of ui:insert
is the default value for that insert, to be used when the “client” page doesn’t define any value.
Notice that both layout.xhtml
and first.xhtml
include a default header (shown in Listing 7-28).
<?xml version="1.0" encoding="UTF-8"?>
<!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:body>
<ui:composition>
<h1>Example of Templating</h1>
</ui:composition>
</h:body>
</html>
In header.xhtml
, the element ui:composition
doesn’t define a template
attribute. Its presence ensures that the rest of the page is ignored when header.xhtml
is included with ui:include
. Actually, the only line needed in header.xhtml
is the one I have highlighted. But the advantage of having a well-formed XHTML page is that you can view it in a browser. With more complex pages, it is sometimes useful to be able to do so.
There is still something I need to clarify. Have you noticed that the header shown in the first page (see Figure 7-9) is black, while the header of the second page (see Figure 7-10) is gray?
This is because the template, with the element
<h:outputStylesheet name="styles.css" library="css"/>
loads a style sheet that defines the color of headers to be gray.
As first.xhtml
doesn’t use the template, the color of the headers remains the default black. Obviously, nothing prevents you from using the style sheet in first.xhtml
by placing in its h:head
the same element used in the template. Alternatively, you can also use the HTML element
<link rel="stylesheet" type="text/css" href="/templ/resources/css/styles.css"/>
Still on the subject of linking to the style sheet with h:outputStylesheet
: notice that the name of the resources
folder doesn’t appear anywhere. This means that it is hardcoded within the component and that you are stuck with it. But the folder names templates
and defaults
are entirely my choice. Therefore, you can choose the names you like.
To complete the description of the templ
application, I still need to show you web.xml (Listing 7-29), which is pretty obvious, and faces-config.xml
(Listing 7-30), which is also self-explanatory.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-
app_2_5.xsd">
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
</web-app>
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0"
>
<navigation-rule>
<from-view-id>/first.xhtml</from-view-id>
<navigation-case>
<from-outcome>go2</from-outcome>
<to-view-id>/page2.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>go3</from-outcome>
<to-view-id>/page3.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/page2.xhtml</from-view-id>
<navigation-case>
<from-outcome>goBack</from-outcome>
<to-view-id>/first.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/page3.xhtml</from-view-id>
<navigation-case>
<from-outcome>goBack</from-outcome>
<to-view-id>/first.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
So far, you have only seen examples in which the action
attribute of h:commandButton
is set to a fixed string. But you can also set it to the method of a bean. If you do so, when JSF reaches the Invoke Application phase while processing the request on the server, it executes that method and uses the value returned by that method to decide what page comes next. In this way, the destination page of an action is defined at execution time.
If this sounds too complicated, let’s see whether an example clarifies the matter. We start by making a copy of the templ
application and renaming it templa
. I am talking about action controllers and listeners now because I have already shown to you the templ
application we can work with.
I want to replace the two buttons Page 2
and Page 3
shown in Figure 7-9 with a single button that alternates between the two pages. To do this, I need to add the Java class shown in Listing 7-31.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="actionBean")
@SessionScoped
public class Action {
int n = 3;
public int getN() { return 5 - n; }
public String goThere() {
n = 5 - n;
return "go" + n;
}
}
Notice that every time goThere
is executed, n
changes between the two values 2 and 3, so that the method returns alternatively “go2” and “go3”. Also notice that getN
returns 2 when n
is 3 and 3 when n
is 2.
The only other update I made to templ
to change it into templa
was to replace the following two lines of first.xhtml
(Listing 7-24)
<h:commandButton action="go2" value="Page 2"/>
<h:commandButton action="go3" value="Page 3"/>
with
<h:commandButton action="#{actionBean.goThere}" value="Page #{actionBean.n}"/>
If you are thinking that this is a silly application, I fully agree with you. But the last thing I want is to give you examples in which the mechanism you should learn is buried in realistic but unnecessary complexities. Note that by moving the decision of what page comes next to the action-controller bean, you are effectively moving the business logic out of the View, thereby gaining in flexibility and maintainability.
That said, I am not yet happy about how this goThere
method works. The problem I have is that the method does more than simply select the next page. It also has the side effect of modifying n
. Side effects are dreaded by experienced programmers, because in a complex application they can cause bugs that are very difficult to trace. You want to write transparent programs in which nothing happens “behind your back.”
The right way to do it is to move what is now a side effect to its own method. Check out Listing 7-32 for an improved version of Action.java
.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.event.ActionEvent;
@ManagedBean(name="actionBean")
@SessionScoped
public class Action {
int n = 3;
public int getN() { return 5 - n; }
public String goThere() { return "go" + n; }
public void swapPages(ActionEvent event) { n = 5 - n; }
}
Obviously, you also have to update first.xhtml
. All you need to do is update the h:commandButton
element as follows:
<h:commandButton action="#{actionBean.goThere}" value="Page #{actionBean.n}"
actionListener="#{actionBean.swapPages}"
/>
During the Invoke Application phase, JSF executes first the action listener and then the action controller. The value of n
is obtained from the bean during the Render Response phase. This works. Sometimes, though, you might like JSF to execute the action listener as soon as possible after receiving the request, before other things happen. In that case, you can add to the component with actionListener
the attribute immediate="true"
, which forces the execution of the action listener already in the Apply Request Values phase.
In the next chapter, you will see how action control works in the JSF version of eshop
, which is a more complex application.
composite
LibraryJSF is based on user-interface components, but for a long time, it was difficult to create new components or combine existing components into a new one. JSF introduced the composite
library with release 2.0 to make those tasks easier.
Table 7-5 lists the all the tags of the composite
library. The two tags interface
and implementation
are special, in that they are containers for other tags.
Conceptually, to define a new component, you need to go through the following steps:
- Define its namespace (i.e., where it is).
- Specify its functionality (i.e., what it does).
- Define how you use it (i.e., its interface).
- Design how you code it (i.e., its implementation).
To write the first example, let’s go through the four points I listed at the end of the previous section.
The code for the new component is shown in Listing 7-33. To test it, copy the folder composite
from the software package for this chapter to Tomcat’s webapps
folder, and then type in the browser http://localhost:8080/composite
.
<?xml version="1.0" encoding="UTF-8"?>
<!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:composite="http://java.sun.com/jsf/composite"
>
<h:head><title>Example of a composite component</title></h:head>
<h:body>
<composite:interface>
<composite:attribute name="x"/>
</composite:interface>
<composite:implementation>
<h:outputText value="Hello, #{cc.attrs.x}!"/>
</composite:implementation>
</h:body>
</html>
Not surprisingly, for such a trivial component, the code is also trivial. But it tells you a lot about developing components with the composite
library.
First of all, inside h:body
, you find two elements, a composite:interface
and a composite:implementation
. Inside the former, you define the attribute named x
, and inside the latter, you define the logic of the component.
To access the attribute from within the implementation, you use the expression #{cc.attrs.x)
.
Listing 7-34 shows you how to use the new component, and Figure 7-11 is how the page appears in a browser.
<?xml version="1.0" encoding="UTF-8"?>
<!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:gz="http://java.sun.com/jsf/composite/gz"
>
<h:head><title>Example of a composite component</title></h:head>
<h:body>
<gz:hello x="wherever you are"/>
</h:body>
</html>
Have you noticed anything unusual in comp.xhtml
? Instead of separately declaring the namespaces of the JSF composite library and of your custom components, you declare a single namespace composite/gz
. For this to work, you need to create in the root of your application a folder named resources
; create a folder (in the example, named gz
) inside resources
; and place your custom components there. The name of the component (e.g., hello
) is obtained from the name of the component file (e.g., hello.xhtml
) by removing its extension.
It is an established practice to use the same string for the prefix and for naming the folder inside resources
, and I recommend that you follow it, but the two strings can be different.
Note that if you place elements in an interface
body, you need to define a corresponding implementation
. But you can have code in implementation
with an empty interface
, like in:
<composite:interface/>
<composite:implementation>
<h:outputText value="Hello, World!"/>
</composite:implementation>
It simply means that your new component will not have any attribute to set.
To include in a composite component an input component, do exactly what you did for an output component in hello.xhtml
. In fact, if you replace in hello.xhtml the line
<h:outputText value="Hello, #{cc.attrs.x}!"/>
with
<h:inputText value="Hello, #{cc.attrs.x}!"/>
you will see the page shown in Figure 7-12, but be aware that this is not a working page. It’s just to show you how to use composite:attribute
.
You can also use composite:attribute
to set the action attribute of h:commandButton
and h:commandLink
. For example, if you want to build a composite component called, say, flip
around the h:commandButton
you used in templa
a couple of pages back, the body of flip.xhtml
would look something like this:
<composite:interface>
<composite:attribute name="act" targets="myB" method-signature="java.lang.String action()"/>
</composite:interface>
<composite:implementation>
<h:commandButton id="myB" action="#{cc.attrs.act}" value="Page #{actionBean.n}"
actionListener="#{actionBean.swapPages}"
/>
</composite:implementation>
Then, you would use the new composite component like this:
<gz:flip act="#{actionBean.goThere}"/>
As it was in the previous examples, you use the expression #{cc.attrs.act}
to access from the implementation the value of the act
attribute declared in interface
. In addition, unlike what happened in the previous examples, you also need a reference in the opposite direction, from interface
to implementation
. This is because JSF must be able to wire the method set in gz:flip
to the h:commandButton
component for which the method is meant. In fact, if there were more components in implementation
, you could wire the same method to several of them by writing their identifiers in the targets
attribute separated by spaces (this is why the name of the attribute is targets
, plural, instead of target).
The value of method-signature
specifies that the value of act
must evaluate to a method, and defines its signature. This means that <gz:flip act="go2"/>
wouldn’t work. You would have to replace:
method-signature="java.lang.String action()"
with
type="java.lang.String"
The two attributes are mutually exclusive, and if you leave out both of them, JSF assumes
type="java.lang.Object"
Now that you know how to make visible the action
attribute of h:commandButton
, you will perhaps be asking yourself how you expose its actionListener
attribute as well. Here it is:
<composite:interface>
<composite:attribute name="act" targets="myB" method-signature="java.lang.String action()"/>
<composite:actionSource name="myB"/>
</composite:interface>
<composite:implementation>
<h:commandButton id="myB" action="#{cc.attrs.act}" value="Page #{actionBean.n}"/>
</composite:implementation>
Then, you would use the new composite component like this:
<gz:flip act="#{actionBean.goThere}">
<f:actionListener for="myB" binding="#{actionBean.swapPages}"/>
</gz:flip>
The element composite:actionSource
exposes the h:commandButton
component, and f:actionListener
wires to it the appropriate action listener. Notice that the attribute actionListener
has disappeared from h:commandButton
.
A few words about composite:facet
and composite:renderFacet
. Close to the beginning of the section about the core
library, I mentioned that facets are a means to let components do something special with a block of code. Now, suppose that you want to include a special word in several places within the composite component you are developing and that the page that uses the component should be able to define that word. You could do it like this:
<composite:interface>
<composite:facet name="aWord"/>
</composite:interface>
<composite:implementation>
<!-- ...some code... -->
<composite:renderFacet name="aWord"/> <!-- say it here -->
<!-- ...some code... -->
<composite:renderFacet name="aWord"/> <!-- and here -->
<!-- ...some code... -->
<composite:renderFacet name="aWord"/> <!-- and again here -->
</composite:implementation>
And this is how you would use the component:
<gz:myFacetedComponent>
<f:facet name="aWord"><h:outputText value="#@%!"/></f:facet>
</gz:myFacetedComponent>
JSF will take the body of the facet
element defined in the using page and insert it where you invoke composite:renderFacet
. If you like to insert those components as a facet, you need to use composite:insertFacet
instead.
Normally, JSF ignores what is inside the body of your custom component, like in
<gz:myComponent>
<h:outputText value="#@%! "/>
<h:inputText value="#{aBean.whatever}"/>
</gz:myComponent>
If you want to include it in your composite component, you can do it with
<composite:insertChildren/>
In this chapter, we have covered a lot of ground. I gave you a first taste of JSF with the simplef
, simplefx
, and simpleh
applications. Then, after describing the JSF life cycle, I went on to talk about all four JSF tag libraries html
, core
, facelet
, and composite
.
For each library, I listed their tags and showed you with simple examples how to use the most common or significant tags.
In the next chapter, we’ll go back to eshop
to see how we can convert it to a JSF application.