Ajax JSF
Ajax JSF
Ajax JSF
Solution
Developers who want to include AJAX support in JavaServer Faces applications have more than one strategy to choose from. Which strategy they choose
depends on the needs of their situation. Developers might ask themselves the following questions to help them decide which strategy to select:
Is this a new application or is the development team adding AJAX support to an existing JavaServer Faces application?
Is the page author capable of adding the JavaScript and AJAX code to the page, or should it be handled by a server-side component so that the page
author can simply add the component tag to the page?
Must the AJAX code be reusable?
Must the AJAX code be customizable?
Must the AJAX code be usable outside of the JavaServer Faces technology runtime?
Is the application developer capable of doing the extra programming required to synchronize data with the JavaServer Faces objects if the development
team decides to de-couple the AJAX code from the JavaServer Faces runtime?
This entry discusses three strategies for incorporating AJAX support into a JavaServer Faces application. The first two strategies involve creating a custom
component to generate the necessary JavaScript and to make AJAX interactions with another server-side component. In Strategy 1, the JavaServer Faces
technology life cycle and the custom component handle the AJAX requests. In Strategy 2, the custom component communicates with a special servlet, which
handles all the AJAX requests. Strategy 3 does not require any custom components; all the additional AJAX support is performed by a servlet provided by the
developer.
Strategy 1 and Strategy 2 require knowledge of the JavaServer Faces technolgy life cycle to implement them. Strategy 3 requires knowledge of the Java servlet
API.
The following sections explain the three strategies and provide more detail on their advantages and disadvantages. After reading about these strategies and
answering the list of questions above, developers should be able to select the strategy that is appropriate for their particular situation. The Comparison of
Strategies section includes a chart that summarizes the characteristics of each strategy, which makes it even easier to make the decision.
Strategy 1: A Custom JavaServer Faces Component Renders Client-side AJAX JavaScript and Processes AJAX Requests
Figure 1 illustrates how this strategy works. The numbered steps following the figure explain what is happening in the figure.
https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008
bpcatalog: bpcatalog: Using JSF with AJAX Page 2 of 7
Figure 1: Architecture of a JavaServer Faces Component that Renders Client-Side AJAX JavaScript and Processes AJAX Requests
The following steps explain the architecture illustrated in Figure 1:
1. The page called Enter Address Page contains an HTML script element rendered by the renderer, AutoCompleteTextRenderer.
2. A call is made to the URL, faces/autocomplete-script, which is mapped to a FacesServlet instance. This instance processes the
RenderPhaseListener instance, which recognizes the URI and returns the component.js page containing the client-side JavaScript code
necessary for the AJAX interactions. After the component.js page is returned, the RenderPhaseListener instance stops taking part in the
JavaServer Faces technology life cycle processing for now.
3. When the user starts typing in the City text field, an onkeypress event occurs. The JavaScript function mapped to this event creates an
XMLHttpRequest object and configures it with the URL to the FacesServlet instance. This URL is faces/autocomplete&id=San. The
id=San part of the URL is a URL parameter in which San is the user input that is matched against the list of cities. The XMLHttpRequest object
makes a call to the FacesServlet instance. HTML page events continue to be processed by the JSP page.
4. The FacesServlet instance processes the RenderPhaseListener instance that recognizes the URL faces/autocomplete and looks up
the AutoCompleteTextField component, which provides the completion logic.
5. The RenderPhaseListener instance generates an XML document containing the potential completion items and returns it to the
XMLHttpRequest object, which then calls the XMLHttpRequest callback function.
6. The XMLHttpRequest callback function updates the HTML DOM based on the contents of the XML document that was returned.
7. After entering the form data, the user clicks the Update button and the form is posted using an HTTP POST to the FacesServlet instance,
which updates SessionBean with the address information entered by the user.
The remainder of this section provides further details on how this strategy works.
In Figure 1, the page called Enter Address Page is a JavaServer Faces page. This page contains a tag that represents the AutocompleteTextField
component, which is a JavaServer Faces component. This component renders two things: an HTML text field, into which the user enters the name of a
city, and the necessary client-side JavaScript AJAX code that fetches possible city names from a server-side managed bean. This managed bean
contains a method that implements the algorithm for completing city names.
To add the AJAX-enabled component to the application, the page author need only include the following tag in the page:
Code Example 1: Declaring an AJAX-enabled JavaServer Faces Component in a JavaServer Faces page
The AutoCompleteTextFieldTag tag handler implements the ajaxTags:completionField tag, which is rendered to HTML by the
renderer, AutoCompleteTextFieldRenderer. The first time the component is encountered in the page,
AutoCompleteTextFieldRenderer renders a reference to external JavaScript code, as shown in this HTML fragment:
https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008
bpcatalog: bpcatalog: Using JSF with AJAX Page 3 of 7
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
The call to event.getFacesContext().responseComplete() following the creation of the XML response causes the rest of the JavaServer
Faces life cycle to be skipped.
The response is returned to the XMLHttpRequest callback method, which updates the HTML DOM with the list of potential city names.
The end user might then select a relevant city name from the list returned from the AutoCompleteTextField component and click on the Update
button, which causes the form to be submitted to the FacesServlet instance, after which the SessionBean object is updated.
This strategy makes it easy for page authors to add AJAX-enabled components to a JavaServer Faces page. As long as the component is added to the
application, all they need to do is include the corresponding component tag in the page.
The component developer can make the component more customizable by allowing external JavaScript files to override the embedded file as well as
allowing the use of external style sheets. One way to do this is to include JavaScript and CSS properties on the component that the user can override. For
example, the AutocompletionTextField component can have an ondisplay property that lets users of the component specify JavaScript code
that is executed when an item is selected from the popup. Similarly, a selectedItemStyle property could let the user specify a CSS or a CSS style
class to be applied to selected items in the popup.
This approach is used by the AJAX Progress Bar for JavaServer Faces Technology. As with Strategy 1, FacesServlet is used to orchestrate all
the processing of AJAX requests and all the serving of script files. The main difference between Strategy 1 and Strategy 1A is the use of POST to
submit the actual view state back to the server. Doing this requires the AJAX-enabled components to abort normal page processing to prevent
rendering of the entire JSP page for AJAX requests. This is done the same way as in Strategy 1, using the responseComplete method on the
FacesContext instance. Another difference in the architecture of the progress bar example is that the PhaseListener instance is responsible
only for rendering the script, whereas ProgressBarRenderer writes out the response XML that is handled by the AJAX JavaScript code.
Another complexity resulting from the polling nature of the progress bar is the need for a closure to the function passed to the setTimeout
https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008
bpcatalog: bpcatalog: Using JSF with AJAX Page 4 of 7
JavaScript method. The progress bar uses the technique described by Richard Cornford at http://jibbering.com/faq/faq_notes/closures.html. This is
a very handy technique when coding AJAX-enabled components.
Performance should be considered when determining how much view state is associated with each request relative to the volume of AJAX requests being
processed when using this approach. While this approach is more tightly coupled with the JavaServer Faces life cycle and therefore provides ready
access to Faces objects, this tight coupling could result in a performance degradation compared to the strategy of using a separate AJAX controller, which
would not have a tight coupling to the view state.
In this strategy the JavaScript rendered by the JavaServer Faces component communicates with a separate servlet. All asynchronous requests will
therefore be handled outside of the JavaServer Faces technology life cycle processing. However, the separate servlet can look up the FacesContext
instance and evaluate value binding and method binding expressions so that it can do such things as find managed beans and make calls to them.
Figure 2 illustrates this strategy. The numbered steps following the figure explain what is happening in the figure.
In this strategy, no custom JavaServer Faces components are used. As in Strategy 2, a separate dedicated AJAX servlet is used, and custom JavaScript
https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008
bpcatalog: bpcatalog: Using JSF with AJAX Page 5 of 7
code is added to the JSP page for the purpose of communicating with the servlet. Developers are responsible for all the "plumbing". This means that they
must provide the code that handles JavaScript events associated with the JavaServer Faces components, makes asynchronous calls, and updates the
HTML document when responses arrive.
Figure 3 illustrates this strategy. The numbered steps following the figure explain what is happening in the figure.
Comparison of Strategies
https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008
bpcatalog: bpcatalog: Using JSF with AJAX Page 6 of 7
Controller
Where do I put the In a PhaseListener instance. In a servlet or servlet In a servlet or servlet filter.
control logic? filter.
Does the page developer No. The JavaServer Faces component renderer will render the Yes. Additionally, care must be taken to ensure
need to provide client- necessary JavaScript. the form elements mapped to by the script match
side AJAX JavaScript those rendered by the target JavaServer Faces
and map to form component.
elements?
Is the solution re- Yes. However, the JavaScript included with the JavaServer Faces No. Each JavaServer Faces page would require its
usable? component must be written such that it can process requests own JavaScript. The JavaScript can be shared in a
from multiple components. There is a limited number of separate file, but portions such as the
XMLHttpRequest objects that can be used in a page, so care XMLHttpRequest callback function are generally
should be taken with the JavaScript in this case also. bound to a specific use case.
Is the solution Yes, provided the component provides customization hooks Yes, but that is the problem. Each JavaServer
customizable? Faces page contains a customized solution.
Does the component Yes, but there are subtle differences in No No
have access to the view how the view state can be made
state of a JavaServer accessible depending on the version of
Faces page? the JavaServer Faces technology
runtime you are using.
Can the AJAX control Yes. The control logic is in a Yes. The controller is a servlet that can be modified or replaced.
logic for a JavaServer PhaseListener instance, which would
Faces component be need to be replaced. This would require
overridden? repacking the component.
Can the AJAX control Yes. Each request is a JavaServer Faces Yes. The AJAX control logic code can access managed beans and evaluate
logic access managed request that has ready access to expressions by looking up the FacesContext instance. This requires a few
beans and evaluate managed beans and expressions. lines of code.
expressions?
Can I leverage existing Yes. Either the JavaScript must be embedded with the Yes.
JavaScript libraries? JavaServer Faces component or the component must be capable
of using external JavaScript.
Can I leverage the AJAX No. No. Yes. Servlets and servlet filters do not require a
control logic outside a JavaServer Faces technology runtime; although, if
JavaServer Faces portions of the AJAX control logic are bound to
technology runtime? managed beans or are evaluating expressions in
the JavaServer Faces technology runtime, this
would not be possible.
The JavaScript should be placed in a separate file as mentioned above, to ensure that the JavaScript contents can be cached by the browser.
While the JavaServer Faces component can be used multiple times in a page, the JavaScript inclusion reference should be emitted exactly once -- before the first
usage. A good way to do this is to modify the renderer that emits the script tag so that it stores a flag for itself in the request map. This flag records whether
the renderer has written the script out for the current page yet. The following code snippet demonstrates how to add code to the renderer that will store the flag
and check its value to determine if the script tag has been rendered:
...
private void renderScriptOnce(ResponseWriter writer, UIComponent component, FacesContext context)
throws IOException {
// Store attribute in request map when we've rendered the script such
// that we only do this once per page
Map requestMap = context.getExternalContext().getRequestMap();
Boolean scriptRendered = (Boolean)requestMap.get(RENDERED_SCRIPT_KEY);
if (scriptRendered == Boolean.TRUE) {
return;
}
// Render script and CSS here
...
}
private static final String RENDERED_SCRIPT_KEY = "bpcatalog-ajax-script-rendered";
One issue that developers must deal with is how to organize their workspace. What should the project conventions be? Generally, this is covered by existing
project conventions for JavaServer Faces technology modules and applications. For example, the faces-config.xml file and the TLD files for JavaServer
Faces technology are usually kept in the src/conf directory.
But where should you keep the JavaScript files? Should they be kept with the source code files? In most cases, we recommend that the JavaScript files be kept
in the src/resources directory. In some cases, you might be using a pre-existing library of JavaScript files, which might be reusable even without the
JavaServer Faces components, such as in the case of making a JavaServer Faces component that uses some of those existing JavaScript files. In this instance,
the JavaScript library should be viewed as a separate project and should be used only by the JavaServer Faces application.
https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008
bpcatalog: bpcatalog: Using JSF with AJAX Page 7 of 7
Another issue to consider is how to package these JavaServer Faces components and JavaScript artifacts into a WAR file or EAR file. The packaging is mostly
the same as for other JavaServer Faces modules and applications, but you need to consider where to put the AJAX artifacts, which include the javascript files.
Generally, it is recommended that you place the AJAX artifacts with the compiled classes so that the JavaServer Faces components can load them by calling
getClass().getResourceAsStream().
In order to use the components within an IDE, there are additional packaging considerations, such as how to make properties visible in IDE property sheets.
These considerations differ from IDE to IDE (until this hopefully gets standardized with JSR 273). For a description of how to package your JavaServer Faces
component for Sun Java Studio Creator, read http://developers.sun.com/prodtech/javatools/jscreator/reference/techart/jsfcomplibrary.html .
Helpful Hints for Developing AJAX components with JavaServer Faces Technology
Understand the JavaServer Faces component model. The J2EE 1.4 Tutorial on Creating JavaServer Faces Components describes the necessary artifacts
needed to create custom JavaServer Faces components.
Get a good JavaScript book. JavaScript: The Definitive Guide, 4th Edition By David Flanagan is quite adequate.
Get familiar with Venkman, the JavaScript debugger in the Mozilla suite.
Get familiar with the Internet Explorer Script Debugger.
Visit QuirksMode.org, a great JavaScript/CSS reference site.
It's generally a good idea to put all your JavaScript code into one file that is referred to using <script> tags. During iterative development, it's a good idea
to place this file directly in your server root so you can edit it in place. Then modify your code to refer to it at this location, just during development. When
you get everything working, you can switch to using the FacesServlet and PhaseListener style to keep things self contained.
References
© Sun Microsystems 2005. All of the material in The Java BluePrints Solutions Catalog is copyright-protected and may not be published in other works without express written
permission from Sun Microsystems.
https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008