Taking Notes from Core JavaServer Faces
Why JavaServer Faces?
If you are familiar with client-side Java development, you can think of JSF as “Swing for server-side applications.”
JSF has these parts:
• A set of prefabricated UI (user interface) components
• An event-driven programming model
• A component model that enables third-party developers to supply additional components
JSF is part of the Java EE standard. JSF is included in every Java EE application server, and also it can be easily added to a standalone web container such as Tomcat.
The original version, JSF 1.0, was released in 2004, and a bug-fix release, named JSF 1.1, was issued shortly thereafter. JSF 1.2, was released as part of Java EE 5 in 2006.
A configuration file for the application lists bean resources and navigation rules. By default, this file is called faces-config.xml.
Java Blueprints conventions http://java.sun.com/blueprints/code/projectconventions.html
Web applications have two parts: the presentation layer and the business logic.The presentation layer is concerned with the look of the application. The extension of the page files is .jsp or .jsf, whereas in the preferred configuration, the extension of the page URLs is .faces.
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %><%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
The JSF implementation defines two sets of tags. The HTML tags generate HTML-specific markup. If you want your web application to render pages for an alternative client technology, you must use a different tag library. The core
tags are independent of the rendering technology.All JSF tags are contained in an f:view tag.
Navigation
A navigation rule tells the JSF implementation which page to send back to the browser after a form has been submitted.
Servlet Configuration
<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>*.faces</url-pattern></servlet-mapping>
JSF Framework Services
Here are the most important services that the JSF framework provides:
Model-view-controller architecture: JSF connects the view and the model. JSF operates as the controller that reacts to the user by processing action and value change events, routing them to code that updates the model or the view.
Data conversion, Validation and error handling, Internationalization, Custom components.
Alternative renderers—By default, JSF generates markup for HTML pages. But it is easy to extend the JSF framework to produce markup for another page description language such as WML or XUL.
Tool support
Behind the Scenes
Each tag has an associated tag handler class. When the page is read, the tag handlers are executed. The JSF tag
handlers collaborate with each other to build a component tree. The component tree is a data structure that contains Java objects for all user interface elements on the JSF page.
Rendering Pages
Next, the HTML page is rendered. All text that is not a JSF tag is passed through. The JSF tags are converted to HTML, each of these tags gives rise to an associated component. This process is called encoding. The encoded page is sent to the browser, and the browser displays it in the usual way.
Decoding Requests
When a form is submitted, the form data is placed in a hash table that all components can access.
Next, the JSF framework gives each component a chance to inspect that hash table, a process called decoding. Each component decides on its own how to interpret the form data.
The Life Cycle
The JSF specification defines six distinct phases:
Restore View phase, Apply Request Values phase, Process Validations phase, Process Validations phase , Render Response phase.
The Restore View phase retrieves the component tree for the requested page if it was displayed previously or constructs a new component tree if it is displayed for the first time. If the page was displayed previously, all components are set to their prior state. This means that JSF automatically retains form information.
If the request has no query data, the JSF implementation skips ahead to the Render Response phase. This happens when a page is displayed for the first time.Otherwise, the next phase is the Apply Request Values phase. In this phase, the JSF implementation iterates over the component objects in the component tree. Each component object checks which request values belong to it and stores them.
In addition to extracting request information, the Apply Request Values phase adds events to an event queue when a command button or link has been clicked. events can be executed after each phase. In specialized situations, an event handler can “bail out” and skip to the Render Response phase or even terminate request processing altogether.
In the Process Validations phase, the submitted string values are first converted to “local values,” which can be objects of any type. When you design a JSF page, you can attach validators that perform correctness checks on the local
values. If validation passes, the JSF life cycle proceeds normally. However, when conversion or validation errors occur, the JSF implementation invokes the Render Response phase directly, redisplaying the current page so that the
user has another chance to provide correct inputs.
After the converters and validators have done their work, it is assumed that it is safe to update the model data. During the Update Model Values phase, the local values are used to update the beans that are wired to the components.
In the Invoke Application phase, the action method of the button or link component that caused the form submission is executed. That method can carry out arbitrary application processing. It returns an outcome string that is passed to
the navigation handler. The navigation handler looks up the next page.
Finally, the Render Response phase encodes the response and sends it to the browser. When a user submits a form, clicks a link, or otherwise generates a new request, the cycle starts anew.
MANAGED BEANS
In a JSF application, beans are commonly used for the following purposes:
• User interface components (traditional user interface beans)
• Tying together the behavior of a web form (called “backing beans”)
• Business objects whose properties are displayed on web pages
• Services such as external data sources that need to be configured when an application is assembled
Value Expressions
Many JSF user interface components have an attribute value that lets you specify either a value or a binding to a value that is obtained from a bean property.
The expression can be used both for reading and writing when it is used in an input component: <h:inputText value="#{user.name}"/>
The property getter is invoked when the component is rendered. The property setter is invoked when the user response is processed.
Message Bundles
You can declare the message bundle in two ways. The simplest way is to include the following elements in your faces-config.xml file:
<application><resource-bundle><base-name>com.corejsf.messages</base-name><var>msgs</var></resource-bundle></application>
Alternatively, you can add the f:loadBundle element to each JSF page that needs access to the bundle, like this:
<f:loadBundle basename="com.corejsf.messages" var="msgs"/>
You can now use value expressions to access the message strings: <h:outputText value="#{msgs.guessNext}"/>
Messages with Variable Parts
Placeholders are numbered {0}, {1}, {2}, and so on. In your JSF page, use the h:outputFormat tag and supply the values for the placeholders as f:param child elements.
<h:outputFormat value="#{msgs.currentScore}"><f:param value="#{quiz.score}"/></h:outputFormat>
You can format numbers as currency amounts by adding a suffix number,currency to the placeholder: currentTotal=Your current total is {0,number,currency}.
The choice format lets you format a number in different ways, such as “zero points”, “one point”, “2 points”, “3 points”, and so on.
currentScore=Your current score is {0,choice,0#zero points|1#one point|2#{0} points}.
There are three cases: 0, 1, and >=2. Each case defines a separate message string.
Setting the Application Locale
1. You can let the browser choose the locale. Set the default and supported locales in WEB-INF/faces-config.xml.
<application><locale-config><default-locale>en</default-locale><supported-locale>de</supported-locale></locale-config></application>
When a browser connects to your application, it usually includes an Accept-Language value in the HTTP header, The JSF implementation reads the header and finds the best match among the supported locales.
2.You can add a locale attribute to the f:view element: <f:view locale="de">The locale can be dynamically set: <f:view locale="#{user.locale}"/>>
3. You can set the locale programatically. Call the setLocale method of the UIViewRoot object:
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot(); viewRoot.setLocale(new Locale("de"));
Backing Beans
Sometimes it is convenient to design a bean that contains some or all component objects of a web form. Such a bean is called a backing bean for the web form. Output components belong to the UIOutput class and input components belong to the UIInput class.
Visual JSF development environments generally use backing beans. These environments automatically generate the property getters and setters for all components that are dragged onto a form.
When you use a backing bean, you need to wire up the components on the form to those on the bean. You use the binding attribute for this purpose:
<h:outputText binding="#{quizForm.scoreComponent}"/>
When the component tree for the form is built, the getScoreComponent method of the backing bean is called, but it returns null. As a result, an output component is constructed and installed into the backing bean with a call to setScoreComponent.
You should not mix form components and business data in the same bean. If you use backing beans for your presentation data, use a different set of beans for business objects.
Bean Scopes
For the convenience of the web application programmer, a servlet container provides separate scopes, each of which manages a table of name/value bindings.
Session Scope
the HTTP protocol is stateless. The browser sends a request to the server, the server returns a response, and then neither the browser nor the server has any obligation to keep any memory of the transaction.
For that reason, servlet containers augment the HTTP protocol to keep track of a session—that is, repeated connections by the same client. There are various methods for session tracking. The simplest method uses cookies: name/value
pairs that a server sends to a client, hoping to have them returned in subsequent requests.
As long as the client does not deactivate cookies, the server receives a session identifier with each subsequent request.
Application servers use fallback strategies, such as URL rewriting, for dealing with those clients that do not return cookies. URL rewriting adds a session identifier to a URL: http://corejsf.com/login/index.jsp;jsessionid=b55cd6...d8e
A session terminates if the web application invokes the invalidate method on the HttpSession object, or if it times out.
Application Scope
Request Scope
The request scope is short-lived. It starts when an HTTP request is submitted and ends when the response is sent back to the client.
Life Cycle Annotations
You can use with @PostConstruct or @PreDestroy to specify managed bean methods that are automatically called just after the bean has been constructed and just before the bean goes out of scope.
Configuring Beans
The most commonly used configuration file is WEB-INF/faces-config.xml. However, you can also place configuration information inside the following locations:
• Files named META-INF/faces-config.xml inside any JAR files loaded by the external context’s class loader.
• Files listed in the javax.faces.CONFIG_FILES initialization parameter inside WEB-INF/web.xml.
<context-param><param-name>javax.faces.CONFIG_FILES</param-name><param-value>WEB-INF/navigation.xml,WEB-INF/beans.xml</param-value></context-param>
<managed-bean><managed-bean-name>user</managed-bean-name><managed-bean-class>com.corejsf.UserBean</managed-bean-class><managed-bean-scope>session</managed-bean-scope></managed-bean>
Setting Property Values <managed-property>
To initialize a property with null, use a null-value element. <null-value/>
Initializing Lists and Maps
<list-entries><value-class>java.lang.Integer</value.class><value>3</value></list-entries>
<map-entries><key-class>java.lang.Integer</key-class><map-entry><key>1</key><value>George Washington</value></map-entry>
Chaining Bean Definitions
<list-entries><value-class>com.corejsf.ProblemBean</value-class><value>#{problem1}</value>
<managed-bean-name>problem1</managed-bean-name><managed-bean-scope>none</managed-bean-scope>
The problem beans have scope none since they are never requested from a JSF page but are instantiated when the quiz bean is requested.
Compatible Bean Scopes
When defining a bean of this scope . . . . . . you can use beans of these scopes
none none
application none, application
session none, application, session
request none, application, session, request
String Conversions
For primitive types, this conversion is straightforward. For other property types, the JSF implementation attempts to locate a matching PropertyEditor. If a property editor exists, its setAsText method is invoked to convert strings to property values.
The Syntax of Value Expressions
Using Brackets
Just as in JavaScript, you can use brackets instead of the dot notation. the following three expressions all have the same meaning: a.b, a["b"], a['b']
• When you access an array or map, the [] notation is more intuitive.
• You can use the [] notation with strings that contain periods or dashes: for example, msgs["error.password"].
•The [] notation allows you to dynamically compute a property: a[b.propname].
Resolving the Initial Term
The initial term referred to a bean that was configured in the faces-config.xml file or to a message bundle map.
There are a number of predefined objects: header, param,cookie, initParam, requestScope, sessionScope, applicationScope, facesContext, view.
If the initial term is not one of the predefined objects, the JSF implementation looks for it in the request, session, and application scopes, in that order. Those scopes are map objects that are managed by the servlet container.
Finally, if the name is still not found, it is passed to the VariableResolver of the JSF application. The default variable resolver looks up managed-bean elements in a configuration resource, typically the faces-config.xml file.
Method Expressions
A method expression denotes an object, together with a method that can be applied to it.
<h:commandButton action="#{user.checkPassword}"/>
Four component attributes can take a method expression:action, validator, valueChangeListener, actionListener.
NAVIGATION
Static Navigation
In a simple web application, page navigation is static. That is, clicking a particular button always selects a fixed JSF page for rendering the response.
<h:commandButton label="Login" action="login"/>
<navigation-rule><from-view-id>/index.jsp</from-view-id><navigation-case><from-outcome>login</from-outcome><to-view-id>/welcome.jsp</to-view-id></navigation-case></>
<navigation-case><from-outcome>logout</from-outcome><to-view-id>/logout.jsp</to-view-id></navigation-case>
This rule applies to all pages because no from-view-id element was specified.
Dynamic Navigation
To implement dynamic navigation, the submit button must have a method expression.
<h:commandButton label="Login" action="#{loginController.verifyUser}"/>
String verifyUser() {if (...) return "success";else return "failure";}
The navigation handler uses the returned string to look up a matching navigation rule.
Advanced Navigation Issues
Redirection
If you add a redirect element after to-view-id, then the JSP container terminates the current request and sends an HTTP redirect to the client. The redirect response tells the client which URL to use for the next page. Redirecting the page is slower than forwarding because another round trip to the browser is involved. However, the redirection gives the browser a chance to update its address field: <navigation-case>...<redirect/></navigation-case>
Use the redirect element for pages that the user might want to bookmark.
Without the redirect element, the navigation handler forwards the current request to the next page, and all name/value pairs stored in the request scope are carried over to the new page. However, with the redirect element, the request scope data is lost.
Wildcards
You can use wildcards in the from-view-id element of a navigation rule. <from-view-id>/secure/*</from-view-id>
Only a single * is allowed, and it must be at the end of the ID string. If there are multiple matching wildcard rules, the longest match is taken.
Using from-action
if you have two separate actions with the same action string or two action method expressions that return the same action string, To differentiate between the two navigation cases, you can use a from-action element. The contents of the element must be identical to the method expression string of the action attribute.
<navigation-case><from-action>#{quiz.answerAction}</from-action><from-outcome>again</from-outcome><to-view-id>/again.jsp</to-view-id></navigation-case>
The Navigation Algorithm
The first of two phases is to find the matching navigation-rule, following these steps:
1. If the outcome is null, return immediately and redisplay the current page.
2. Merge all navigation rules with the same from-view-id value.
3. Try to find a navigation rule whose from-view-id value matches the view ID exactly. If such a rule exists, take it.
4. Consider all navigation rules whose from-view-id values end with a wildcard suffix, such as secure. For each such rule, check whether the prefix (after removing the *) is identical to the corresponding prefix of the view ID. If there are matching rules, take the one with the longest matching prefix.
5. If there is a rule without a from-view-id, take it.
6. If there is no match at all, redisplay the current page.
The second of two phases is to consider all navigation-case elements in the matching navigation rule (which may consist of several merged navigation-rule elements with matching from-view-id.values).
Follow these steps to find the matching case:
1. If a case has both matching from-outcome and from-action, take it.
2. Otherwise, if a case has matching from-outcome and no from-action, take it.
3. Otherwise, if a case has matching from-action and no from-outcome, take it.
4. Otherwise, if there is a case with neither from-outcome nor from-action, take it.
5. If there is no match at all, redisplay the current page.
STANDARD JSF TAGS: <%@ taglib uri="http://java.sun.com/jsf/core(html)" prefix="f(h)" %>
An Overview of the JSF Core Tags
view, subview, attribute, param, facet, actionListener, setPropertyActionListener, valueChangeListener, phaseListener, converter, convertDateTime, convertNumber, validator, validateDoubleRange, validateLength, validateLongRange, loadBundle, selectitems, selectitem, verbatim.
Any component
can store artibrary name/value pairs in its attribute map. You can set an attribute in a page and later retrieve it programatically.
The f:param tag also lets you define a name/value pair, but the value is placed in a separate child component, a much bulkier storage mechanism. However, the child components form a list, not a map. You use f:param if you need to supply a number of values with the same name .
f:facet adds a named component to a component’s facet map. A facet is not a child component; each component has both a list of child components and a map of named facet components. The facet components are usually rendered
in a special place.
An Overview of the JSF HTML Tags
JSF HTML tags represent the following kinds of components: Inputs, Outputs, Commands, Selection, Others. panelGrid: HTML table panelGroup: Two or more components that are laid out as one
IDs and Bindings
The versatile id attribute lets you do the following:
• Access JSF components from other JSF tags
• Obtain component references in Java code
• Access HTML elements with scripts
<h:inputText id="name" .../> <h:message for="name"/>
UIComponent component = event.getComponent().findComponent("name");
<h:outputText binding="#{form.statePrompt}" .../>
Conditional Rendering
You use the rendered attribute to include or exclude a component, depending on a condition: <h:commandButton ... rendered = "#{user.loggedIn}"/>
HTML 4.0 Attributes, DHTML Events,
Forms
prependId: true (default) if the ID of this form is prepended to the IDs of its components; false to suppress prepending the form ID (useful if the ID is used in JavaScript code)
All JSF form submissions are implemented with the POST method.
Form Elements and JavaScript
<h:form id="registerForm"><h:inputText id="password" .../>
var password = form["registerForm:password"].value;
All form controls generated by JSF have names that conform to: formName:componentName to access the password field, you must do this instead: documents.forms.registerForm["registerForm:password"].value
Text Fields and Text Areas: h:inputText, h:inputSecret, h:inputTextarea
Hidden Fields h:inputHidden
Hidden fields are often used with JavaScript actions to send data back to the server.
Displaying Text and Images: h:outputText, h:outputFormat, h:graphicImage
<h:outputFormat value="{0} is {1} years old"><f:param value="Bill"/><f:param value="38"/></h:outputFormat>
Buttons and Links: h:commandButton, h:commandLink, h:outputLink
The h:commandButton and h:commandLink actions both represent JSF command components—the JSF framework fires action events and invokes actions when a button or link is activated.
action: If specified as a string: Directly specifies an outcome used by the navigation handler to determine the JSF page to load next as a result of activating the button or link.If specified as a method expression: The method has this signature: String methodName(); the string represents the outcome.
immediate: A Boolean. If false (the default), actions and action listeners are invoked at the end of the
request life cycle; if true, actions and action listeners are invoked at the beginning of the life cycle.
Selection Tags
h:selectBooleanCheckbox, h:selectManyCheckbox, h:selectOneRadio, h:selectOneListbox, h:selectManyListbox, h:selectOneMenu, h:selectManyMenu
The f:selectItems Tag
<h:selectOneRadio value="#{form.condiments}><f:selectItems value="#{form.condimentItems}"/></h:selectOneRadio>
If you specify a map, the JSF implementation creates a SelectItem instance for every entry in the map. The entry’s key is used as the item’s label, and the entry’s value is used as the item’s value.
Item Groups
Binding the value Attribute
In all likelihood, whether you are using a set of checkboxes, a menu, or a listbox, you will want to keep track of selected items. For that purpose, you can exploit selectOne and selectMany tags, which have value attributes that represent
selected items.
<h:selectOneRadio value="#{form.beverage}"><f:selectItems value="#{form.beverageItems}"/></h:selectOneRadio>
You can keep track of multiple selections with a selectMany tag. These tags also have a value attribute that lets you specify one or more selected items. That attribute’s value must be an array or list of convertible types.
Messages
During the JSF life cycle, any object can create a message and add it to a queue of messages maintained by the faces context. At the end of the life cycle—in the Render Response phase—you can display those messages in a view.
JSF applications use two tags to display messages in JSF pages: h:messages and h:message.
The h:messages tag displays all messages that were stored in the faces context during the course of the JSF life cycle.
The h:message tag displays a single message for a particular component. That component is designated with h:message’s mandatory for attribute. If more than one message has been generated for a component, h:message shows only the last one: <h:messages layout="table" errorClass="errors"/> <h:message for="name" errorClass="errors"/>
Panels
h:panelGrid generates an HTML table element. You can specify the number of columns in the table with the columns attribute: <h:panelGrid columns="3">
DATA TABLES
The Data Table Tag—h:dataTable
The h:dataTable tag iterates over data to create an HTML table.
<h:dataTable value='#{items}' var='item'><h:column>... </h:column>...</h:dataTable>
Headers, Footers, and Captions
JSF 1.2 adds table captions to h:dataTable. You add a caption facet to your h:dataTable tag.
<h:dataTable ...><f:facet name="caption">An array of names:</f:facet>
<h:column headerClass="columnHeader" footerClass="columnFooter"><f:facet name="header">...<f:facet name="footer"></f:facet></f:facet></h:dataTable>
Editing Table Cells
To edit table cells, you provide an input component for the cell you want to edit.
<h:column><h:inputText value='#{name.last}' rendered='#{name.editable}'/><h:outputText value='#{name.last}' rendered='#{not name.editable}'/></h:column>
Styles
h:dataTable has attributes that specify CSS classes for the following:
• The table as a whole (styleClass)
• Column headers and footers (headerClass and footerClass)
• Individual columns (columnClasses)
• Individual rows (rowClasses)
Styles by Column: columnClasses="oddColumn,evenColumn"
h:dataTable reuses the column classes, starting with the first. By specifying only the first two column classes, we can set the CSS classes for even and odd columns.
Database Tables
<h:dataTable value="#{customer.all}" var="currentCustomer" ><h:column> <h:outputText value="#{currentCustomer.Cust_ID}"/> </h:column>
JSF page accesses column data by referencing column names.
public Result getAll(){ResultSet result = stmt.executeQuery("SELECT * FROM Customers"); return ResultSupport.toResult(result);}
JSTL Result Versus Result Sets
The value you specify for h:dataTable can be, an instance of javax.servlet.jsp.jstl.Result or an instance of java.sql.ResultSet. h:dataTable wraps instances of those objects in instances of ResultDataModel and ResultSetDataModel, respectively.
If you have worked with result sets, you know they are fragile objects that require a good deal of programmatic control. The JSTL Result class is a bean that wraps a result set and implements that programmatic control for you; results
are thus easier to deal with than are result sets.
Table Models
When you use a Java object, array, list, result set, or JSTL result object to represent table data, h:dataTable wraps those objects in a model that extends the javax.faces.model.DataModel class. All of those model classes, listed below, reside in the javax.faces.model package: ArrayDataModel, ListDataModel, ResultDataModel, ResultSetDataModel, ScalarDataModel.
h:dataTable deals with the models listed above; it never directly accesses the object—array, list, etc. You can access those objects yourself with the DataModel.getWrappedData method. That method comes in handy for adding and removing table rows.
Editing Table Models
It is easy to add and delete table rows with two methods provided by all data models: getWrappedData() and setWrappedData().
Name[] currentNames = (Name[]) model.getWrappedData(); ... model.setWrappedData(newNames);
Get the current object wrapped by the model with getWrappedData(), modify it (by adding or deleting rows), and then reset the wrapped object with setWrappedData().
Sorting and Filtering
To sort or filter tables with h:dataTable, you need to implement a table model that decorates one of the table models.
Scrolling Techniques
There are two ways to scroll through tables with lots of rows: with a scrollbar or with some other type of control that moves through the rows.
Scrolling with a Scrollbar
Scrolling with a scrollbar is the simplest solution. Wrap your h:dataTable in an HTML div.
<div style="overflow:auto; width:100%; height:200px;"><h:dataTable...></h:dataTable></div>
Scrolling with Pager Widgets
CONVERSION AND VALIDATION
In the Apply Request Values phase, the request values are stored in component objects. The value stored in the component object is called the submitted value. A conversion process transforms the incoming strings to various java types.
The converted values are not immediately transmitted to the beans that make up the business logic. Instead, they are first stored inside the component objects as local values. After conversion, the local values are validated.
After all local values have been validated, the Update Model Values phase starts, and the local values are stored in beans, as specified by their value references.
JSF first converts and validates all user input. If errors are found, the page is redisplayed with the values that the user entered so that the user can try again. The Update Model Values phase starts only if all validations are successful.
Using Standard Converters
<h:inputText value="#{payment.amount}"><f:convertNumber minFractionDigits="2"/></h:inputText>
<h:inputText value="#{payment.date}"><f:convertDateTime pattern="MM/yyyy"/></h:inputText>
The converter Attribute
An alternate syntax for attaching a converter to a component is to add the converter attribute to the component tag. You specify the ID of the converter like this: <h:outputText value="#{payment.date}" converter="javax.faces.DateTime"/>
A third way of specifying the converter would be as follows:
<h:outputText value="#{payment.date}"><f:converter converterId="javax.faces.DateTime"/></h:outputText>
Displaying Error Messages <h:message for="amount"/>
Displaying All Error Messages <h:messages layout="table"/>
Using a Custom Error Message <h:inputText ... converterMessage="Not a valid number."/>
Changing the Text of Standard Error Messages
Using Standard Validators
A key role of validation is to protect the model. Because JSF uses separate phases for processing validations and updating model values, you can be assured that the model is not put into an inconsistent state if some of the inputs
cannot be validated: <f:validateLength minimum="13"/>
Standard Validators: f:validateDoubleRange, f:validateLongRange, f:validateLength
Checking for Required Values
<h:inputText id="date" value="#{payment.date}" required="true"/>
An alternate syntax for attaching a validator to a component is to use the f:validator tag. You specify the ID of the validator and the validator parameters: <f:validator validatorId="javax.faces.validator.LengthValidator"><f:attribute name="minimum" value="13"/></f:validator>
Yet another way of specifying the validator is with a validator attribute to the component tag.
Displaying Validation Errors
You can supply a custom message for a component by setting the requiredMessage or validatorMessage attribute:
<h:inputText id="card" value="#{payment.card}" required="true" requiredMessage="#{msgs.cardRequired}" validatorMessage="#{msgs.cardInvalid}"><f:validateLength minimum="13"/></h:inputText>requiredMessage or validatorMessage attribute.
Bypassing Validation
validation errors (as well as conversion errors) force a redisplay of the current page. This behavior can be problematic
with certain navigation actions.If a command has the immediate attribute set, then the command is executed during the Apply Request Values phase: <h:commandButton value="Cancel" action="cancel" immediate="true"/>
Programming with Custom Converters and Validators
Implementing Custom Converter Classes
A converter is a class that converts between strings and objects. A converter must implement the Converter interface, which has the following two methods:
Object getAsObject(FacesContext context, UIComponent component, String newValue)
String getAsString(FacesContext context, UIComponent component, Object value)
The first method converts a string into an object of the desired type, throwing a ConverterException if the conversion cannot be carried out. This method is called when a string is submitted from the client, typically in a text field. The second method converts an object into a string representation to be displayed in the client interface.
Specifying Converters
One mechanism for specifying converters involves a symbolic ID that you register with the JSF application.
<converter><converter-id>com.corejsf.CreditCard</converter-id><converter-class>...</converter-class></converter>
<f:converter converterId="com.corejsf.CreditCard"/>
<h:inputText value="#{payment.card}" converter="com.corejsf.CreditCard"/>
You can also access a converter without defining it in a configuration file. Use the converter attribute with a value expression that yields the converter object: <h:outputText value="#{payment.card}" converter="#{bb.convert}"/>
Here, the bb bean must have a convert property of type Converter.
Alternatively, if you are confident that your converter is appropriate for all conversions between String and CreditCard objects, then you can register it as the default converter for the CreditCard class:
<converter><converter-for-class>com.corejsf.CreditCard</converter-for-class><converter-class>com.corejsf.CreditCardConverter</converter-class></converter>
Now you do not have to mention the converter any longer. It is automatically used whenever a value reference has the type CreditCard.
Implementing Custom Validator Classes
1. Implement a validator by implementing the javax.faces.validator.Validator interface.
2. Register your validator in a configuration file (such as faces-config.xml).
The Validator interface defines only one method:
void validate(FacesContext context, UIComponent component, Object value)
If validation fails, generate a FacesMessage that describes the error, construct a ValidatorException from the message, and throw it.
Registering Custom Validators
<validator><validator-id>com.corejsf.CreditCard</validator-id><validator-class>com.corejsf.CreditCardValidator</validator-class></validator>
<f:validator validatorId="com.corejsf.CreditCard"/>
Validating with Bean Methods
You can also add the validation method to an existing class and invoke it through a method expression.
<h:inputText id="card" value="#{payment.card}" required="true" validator="#{payment.luhnCheck}"/>
Supplying Attributes to Converters
Every JSF component can store arbitrary attributes. You can set an attribute of the component to which you attach a converter; use the f:attribute tag. Your converter can then retrieve the attribute from its component.
<h:outputText value="#{payment.card}"><f:converter converterId="CreditCard"/><f:attribute name="separator" value="-"/></h:outputText>
In the converter, retrieve the attribute as follows: separator = (String) component.getAttributes().get("separator");
Validating Relationships Between Multiple Components
The trick is to attach the validator to the last of the components. Of course, you need to have access to the other components. You can easily achieve that access by using a backing bean that contains all components of the current form , and attach the validation method to the backing bean.
EVENT HANDLING
JSF supports three kinds of events: Value change events, Action events, Phase events.
Value change events are fired by input components when the component’s value changes.
Action events are fired by command components, when the button or link is activated. Phase events are routinely fired by the JSF life cycle.
Life Cycle Events
Requests in JSF applications are processed by the JSF implementation with a controller servlet, which in turn executes the JSF life cycle.
The JSF life cycle consists of the following phases:
Restore View, Apply Request Values, Process Validations, Update Model Values, Invoke Application, Render Response.
Starting with the Apply Request Values phase, the JSF implementation may create events and add them to an event queue during each life cycle phase. After those phases, the JSF implementation broadcasts queued events to registered listeners.
Value Change Events
<h:selectOneMenu value="#{form.country}" onchange="submit()" valueChangeListener="#{form.countryChanged}"><f:selectItems value="#{form.countryNames}"/></h:selectOneMenu>
javax.faces.event.ValueChangeEvent: Object getNewValue(), Object getOldValue()
Action Events
<h:commandLink actionListener="#{bean.linkActivated}"></h:commandLink>
It is important to distinguish between action listeners and actions. In a nutshell, actions are designed for business logic and participate in navigation handling, whereas action listeners typically perform user interface logic and do not par-
ticipate in navigation handling.
Event Listener Tags
You can also add action and value change listeners to a component with the following tags: f:actionListener, f:valueChangeListener
The tags have one advantage over the attributes: Tags let you attach multiple listeners to a single component.
The Event Listener Tags specifies a Java class.
Immediate Components
Value change events are normally fired after the Process Validations phase, and action events are normally
fired after the Invoke Application phase.
But sometimes you want value change events or action events to fire at the beginning of the life cycle to bypass validation for one or more components.
Immediate events are fired after the Apply Request Values phase.
Using Immediate Input Components
Immediate input components perform conversion and validation, and subsequently deliver value change events at the beginning of the JSF life cycle—after the Apply Request Values—instead of after Process Validations.
<h:selectOneMenu value="#{form.country}" onchange="submit()"immediate="true" valueChangeListener="#{form.countryChanged}"><f:selectItems value="#{form.countryNames}"/></h:selectOneMenu>
To summarize, you can skip validation when a value change event fires by doing the following:
1. Adding an immediate attribute to your input tag
2. Calling FacesContext.renderResponse() at the end of your listener
The call to renderResponse() skips the rest of the life cycle up to Render Response. Thus, the other validations are skipped and the response is rendered normally
Notice that we add an onchange attribute whose value is submit() to our h:selectOneMenu tag. Setting that attribute means that the JavaScript submit function will be invoked whenever someone changes the selected value of the menu, which causes the surrounding form to be submitted.
That form submit is crucial because the JSF implementation handles all events on the server. If you take out the onchange attribute, the form will not be submitted when the selected menu item is changed, meaning that the JSF life cycle will never be invoked, our value change listener will never be called.
Using Immediate Command Components
<h:commandLink action="#{localeChanger.germanAction}" immediate="true"><h:graphicImage value="/german_flag.gif" style="border: 0px"/></h:commandLink>
Unlike value change events, we do not need to modify our listener to invoke FacesContext.renderResponse() because all actions, immediate or not, proceed directly to the Render Response phase, regardless of when they are fired.
Passing Data from the UI to the Server
JSF gives us three convenient mechanisms to pass information from the UI to the server, in the form
of JSP tags: f:param, f:setPropertyActionListener, f:attribute
The f:param Tag
If you attach an f:param tag to a command component, such as a button or a link, the JSF implementation passes the parameter’s value to the server as a request parameter.
<h:commandLink immediate="true" action="#{localeChanger.changeLocale}"><f:param name="languageCode" value="de"/></h:commandLink>
Map<String, String> params = context.getExternalContext().getRequestParameterMap(); params.get("languageCode");
The f:attribute Tag
Another way to pass information from the UI to the server is to set a component’s attribute with the f:attribute tag.
<h:commandLink immediate="true" actionListener="#{localeChanger.changeLocale}"><f:attribute name="languageCode" value="de"/></h:commandLink>
Map<String, Object> attrs = component.getAttributes(); (String) attrs.get("languageCode");
The f:setPropertyActionListener Tag
f:param and f:attribute are handy for passing information from the UI to the server, but those tags require us to manually dig the information out from a request parameter or component attribute, respectively.
With f:setPropertyActionListener, the JSF implementation sets a property in your backing bean for you.
<h:commandLink immediate="true" action="#{localeChanger.changeLocale}"><f:setPropertyActionListener target="#{localeChanger.languageCode}" value="de"/></h:commandLink>
Phase Events
The JSF implementation fires events, called phase events, before and after each life cycle phase. Those events are handled by phase listeners. You specify phase listeners in a faces configuration file
<lifecycle><phase-listener>com.corejsf.PhaseTracker</phase-listener></lifecycle>
You implement phase listeners by means of the PhaseListener interface from the javax.faces.event package. That interface defines three methods:
• PhaseId getPhaseId()
• void afterPhase(PhaseEvent)
• void beforePhase(PhaseEvent)
The getPhaseId method tells the JSF implementation when to deliver phase events to the listener.You could also
specify PhaseId.ANY_PHASE, which really means all phases. Your phase listener’s beforePhase and afterPhase methods will be called six times per life cycle: once each for each life cycle phase.
SUBVIEWS AND TILES
Common Layouts
Separate Layout from Content
Content Inclusion in JSP-Based Applications
• <%@ include file="header.jsp"% >
• <jsp:include page="header.jsp"/>
• <c:import url="header.jsp"/>
The first choice listed above—the JSP include directive—includes the specified file before the enclosing JSF page is compiled to a servlet. However, the include directive suffers from an important limitation: If the included file’s content
changes after the enclosing page was first processed, those changes are not reflected in the enclosing page. That means you must manually update the enclosing pages—whether the including pages changed or not—whenever included content changes.
The last two choices listed above include the content of a page at runtime and merge the included content with the including JSF page. Because the inclusion happens at runtime, changes to included pages are always reflected when the
enclosing page is redisplayed. For that reason, jsp:include and c:import are usually preferred to the include directive.
The c:import tag works just like jsp:include, but it has more features—for example, c:import can import resources from another web application, whereas jsp:include cannot.
JSF-Specific Considerations
You must take into account two special considerations when you include content in a JavaServer Faces application:
1. You must wrap included JSF tags in an f:subview tag.
2. Included JSF tags cannot contain f:view tags.
<f:view><f:subview id="header"><c:import url="header.jsp"/></f:subview></f:view>
Looking at Tiles
With Tiles, you define a single layout that can be reused by multiple tiles, which are nothing more mysterious than imported JSP pages. Tiles lets you implement layout code once and reuse it among many pages.
Installing Tiles
<servlet><servlet-name>Tiles Servlet</servlet-name><servlet-class>org.apache.tiles.servlets.TilesServlet</servlet-class><load-on-startup>2</load-on-startup></servlet>
Using Tiles with JSF is a three-step process:
1. Use tiles:insert to insert a tile definition in a JSF page.
2. Define the tile in your Tiles configuration file.
3. Implement the tile’s layout.
<h:form><tiles:insert definition="book" flush="false"/></h:form>
Tiles are defined in /WEB-INF/tiles.xml
<definition name="book" path="/headerMenuContentLayout.jsp"><put name="header" value="/bookHeader.jsp"/><put name="menu" value="/bookMenu.jsp"/><put name="content" value="/bookContent.jsp"/></definition>
The tile’s layout is specified with the definition element’s path attribute. The tile attributes, specified with put ele-
ments, are used by the layout.
We have encapsulated layout so that we can reuse it in other tiles, instead of replicating that layout code from one
JSF page to another.
Parameterizing Tiles
Extending Tiles
<definition name="header-menu-content" path="/headerMenuContentLayout.jsp"></>
<definition name="book" extends="header-menu-content"></>
When you extend a tile, you inherit its layout and attributes.
Nested Tiles Using a tile name instead of a JSP page lets you nest tiles.
Tile Controllers
Tiles lets you attach a Java object, called a tile controller, to a tile. That object’s class must implement the org.apache.struts.tiles.Controller interface, which defines a single perform method. Tiles invokes that method just before it loads the controller’s associated tile. Tile controllers have access to their tile’s context, which lets the controller access the tile’s attributes or create new attributes.
EXTERNAL SERVICES
Connection Management
First, opening a connection to a database can be time consuming. Several seconds may elapse for the processes of connecting, authenticating, and acquiring resources to be completed. Thus, you cannot simply open a new connection for every page request.
On the flip side, you cannot keep open a huge number of connections to the database. Connections consume resources, both in the client program and in the database server. Commonly, a database puts a limit on the maximum num-
ber of concurrent connections that it allows. Thus, your application cannot simply open a connection whenever a user logs on and leave it open until the user logs off. After all, your user might walk away and never log off.
One common mechanism for solving these concerns is to pool the database connections. A connection pool holds database connections that are already opened.
Application programs obtain connections from the pool. When the connections are no longer needed, they are returned to the pool, but they are not closed. Thus, the pool minimizes the time lag of establishing database connections.
Using Prepared Statements A common optimization technique for JDBC programs is the use of the PreparedStatement class. You use a prepared statement to speed up database operations if your code issues the same type of query multiple times.
A prepared statement asks the database to precompile a query—that is, parse the SQL statement and compute a query strategy. That information is kept with the prepared statement and reused whenever the query is reissued.
Many connection pool implementations will cache prepared statements.
Accessing a Container-Managed Resource
The Java EE specification requires that resources are declared in the web.xml file of your web application.
<resource-ref><res-ref-name>jdbc/mydb</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref>
There are two ways for doing the lookup. The most elegant one is resource injection.
@Resource(name="jdbc/mydb") private DataSource source;
InitialContext ctx = new InitialContext();
source = (DataSource) ctx.lookup("java:comp/env/jdbc/mydb");
An Introduction to LDAP
LDAP Directories
LDAP uses a hierarchical database. It keeps all data in a tree structure, not in a set of tables as a relational database would.
Managing Configuration Information
Placing configuration information into server.xml is appropriate for a global resource such as a database. This resource be used by all web applications inside the container. On the other hand, application-specific configuration
information should be placed inside web.xml or faces-config.xml.
Container-Managed Authentication and Authorization
To protect a set of pages, you specify access control information in the web.xml file.
A realm is any mechanism for looking up usernames, passwords, and roles. Application servers commonly supports several standard realms that access user information from one of the following sources: An LDAP directory, A relational database, A file (such as Tomcat’s conf/tomcat-users.xml)
<security-constraint><web-resource-collection><web-resource-name>Protected Pages</web-resource-name><url-pattern>/protected/*</url-pattern></web-resource-collection> </security-constraint>
<login-config><auth-method>FORM</auth-method><realm-name>openldap</realm-name><form-login-config><form-login-page>/login.html</form-login-page><form-error-page>/noauth.html</form-error-page></form-login-config></login-config>
<security-role><role-name>registereduser</role-name></security-role>
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
Object requestObject = context.getRequest();
HttpServletRequest request = (HttpServletRequest) requestObject; request.isUserInRole(role);
request.getRemoteUser();
AJAX
Ajax Fundamentals
In an Ajax request, we don’t refresh the entire page; instead, we update only part of the page.
Reason to use JavaScript Libraries:
To reduce the amount of JavaScript code you need to write for Ajax requests, and to make sure that those requests succeed across multiple browsers.
The Prototype Library
new Ajax.Updater("dateDIV", "dateAndTime.ajax", { method: "get" }); }
new Ajax.Request(window.document.forms[0].action,{method: "post",parameters: "ajax=true&zip=" + zip,onComplete: processRealtimeValidation});
Direct Web Remoting
Ajax Components
The Rico Accordion
Rico is a one of a number of frameworks based on Prototype.
Ajax4jsf(Replaced by RichFaces )
a4j:support lets you attach Ajax functionality to a component, typically an input component; and a4j:status renders JSF components at the start and end of each Ajax4jsf Ajax call.
OPEN SOURCE
Alternate View Technologies—Facelets
XHTML Views
Facelets is an open source display technology for JSF, to implement our views in XHTML (Extensible HTML)
instead of JSP. In our XHTML files, we will have mock-up HTML that is edited by a graphic designer, but at runtime, Facelets will swap out that mock-up HTML with JSF components. This will allow graphic designers to create a look and feel with mock-up markup that developers can replace with JSF components at runtime.
Replacing Markup with JSF Components: The jsfc Attribute
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core">
<f:loadBundle basename="com.corejsf.messages" var="msgs"/>
<form jsfc="h:form" id="login"> <input type="text" id="name" value="#{user.name}" style="background: #ffa;" jsfc="h:inputText"/>
<label for="name" class="label" jsfc="h:outputLabel"> #{msgs.namePrompt}</label>
We use an XML namespace to enable Facelet tags that mimic the JSF core tag library. We have added jsfc attributes to our form, labels, text fields, and button. When you run this souped-up XHTML page through Facelets, it swaps
the markup for components of the specified type.
Using JSF Tags
As Facelets parses the XHTML, it creates the resulting component tree.
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html">
Page Composition with Templates
Facelets lets you compose web pages from individual XHTML fragments, similar to the popular Tiles framework.
<ui:composition template="/layout.xhtml"><ui:define name="header"><img src="images/facelets.jpg"/></ui:define>...<ui:define name="content"><ui:include src="login-composition.xhtml"/></ui:define></ui:composition>
the template:
...<div class="header"><ui:insert name="header"/></div><div class="menu"><ui:insert name="menu"/></div>...
Facelets Custom Tags
You can easily create your own XHTML tags and use them in your Facelets views.
<html ...xmlns:debug="http://corejsf/facelets/debug">...<debug:headers/>...</html>
We must include our namespace declaration and then we are free to use the tag.
<facelet-taglib><namespace>http://corejsf/facelets/debug</namespace><tag><tag-name>headers</tag-name><source>tags/corejsf/debug/headers.xhtml</source></tag></facelet-taglib>
0 comments:
Post a Comment