JSF 2.0 for the Cloud, Part Two

By Deepak Vohra

Published May 2012

Downloads:
DownloadOracle JDeveloper 11.1.2
DownloadOracle Database 11g Express Edition
DownloadSample Application

Introduction

JavaServer Faces 2.0 provides features ideally suited for the virtualized computing resources of the cloud. Here, in Part Two of a two-part article, we look at Ajax support, view parameters, preemptive navigation, event handling, and bookmarkable URLs.

In Part One of this article, I demonstrated some new features in JavaServer Faces 2.0 (JSF 2.0) that make it cloud-ready:

  • Resource handling
  • @ManagedBean annotation
  • Implicit navigation

In Part Two, we take a look at following features:

  • Ajax support
  • View parameters
  • Preemptive navigation
  • Event handling
  • Bookmarkable URLs

Note: You can download the source code for the sample application started in Part One here. Some sections of the sample code have been commented out and can be uncommented for relevant sections of this article.

Adding Ajax to the Mix

JSF 2.0 introduced a provision for adding Ajax functionality to any JSF component. Ajax provides asynchronous transfer of data between a client and a server. Ajax features in JSF 2.0 include support for partial page rendering, partial page processing, and grouping of components.

Ajax support in JSF 2.0 can be added by using either of the following methods.

  • f:ajax tag
  • JSF Ajax library (jsf.js)

The f:ajax behavior tag is the preferred method. It simplifies JSF development in that it shields you from having to program JavaScript into the component tags. However, an understanding of AjaxBehaviorEvent, which represents component behavior specific to Ajax, is required.

We will discuss both approaches, but we will use the jsf.js Ajax JavaScript library to demonstrate adding a JavaScript resource using the h:outputScript tag.

Using the JSF Ajax JavaScript Library

In the Ajax version of our application, we will submit the SQL query to create a data table using Ajax. The Ajax version of the input.xhtml Facelets page consists of an h:dataTable element with value binding to the managed bean property resultSet, which consists of the JDBC ResultSet for a SQL query specified in the input field.

The JSF Ajax library can be used by performing the following procedure.

Add an h:outputScript tag, including the library name and the script name (jsf.js), and specify the target attribute as head.

The target attribute specifies the element in which the JavaScript is to be rendered. Because jsf.js is packaged in the jsf-impl.jar file in the META-INF\resources\javax.faces folder, the script can be added as a JAR-packaged resource.

 <h:outputScript library="javax.faces" name="jsf.js" target="head"/>  

If a JavaScript script is available outside a JAR file, it can be added by creating a library for it in the resources folder. For example, if the jsf.js script is available separately, it can be added by creating a js folder in the resources folder, copying the script to the folder, and including the script with the following h:outputScript tag.

 <h:outputScript library="js" name="jsf.js" target="head"/>  

The h:outputScript tag attributes can be added in the Facelets page using code assist. The h:graphicImage tag can be added with the resource specified using the EL expression #{resource['images:logo.jpg']}, for example:

 <h:graphicImage value="#{resource['images:logo.jpg']}"/>  

If a resource is not found at the specified path, the error src="RES_NOT_FOUND" gets generated and the graphic image does not get displayed, which can be fixed by adding the resource to the specified path.

The jsf.js JavaScript is invoked in h:inputText to send an Ajax request. The valueChangeListener has a value binding to the commandButton_action method in the managed bean.

<h:inputText id="inputText1" onchange="jsf.ajax.request(this, event, {render: 'form1:dataTable1'}); return false;"  
      binding="#{catalog.inputText1}" valueChangeListener="#{catalog.commandButton_action}"
                             required="true"/>

With the jsf.js library, Ajax is added to the inputText component using the jsf.ajax.request function. Invoke the jsf.ajax.request() function in the onchange event handler. The function takes three arguments:

  • The first argument is the component invoking the function, which is this.

  • The second argument is the calling event, which is event.

  • The third argument is a JavaScript object with the properties execute and render, which take client IDs of components. Client IDs are component IDs prefixed with the IDs of all the preceding components in the naming container that contains the component. For example, we specified form1.dataTable1 as the client ID in the render property. The return false in the onchange event indicates that the form is not submitted. The valueChangeListener attribute specifies the managed bean method to invoke when the Ajax request is initiated.

Modify the commandButton_action method to return null instead of output, because with Ajax, we update the page that sent the request and we do not navigate to output.xhtml.

 return null; //return "output"; 

The f:ajax tag can be used instead of the jsf.js script. The f:ajax tag renders the dataTable1 data table and has binding to a listener commandButton_action (AjaxBehaviorEvent event), which is the same as the commandButton_action method for the jsf.js script version except for the AjaxBehaviorEvent parameter in the managed bean.

<h:inputText binding="#{catalog.inputText1}" required="true">
    <f:ajax execute="@form" event="valueChange" render="dataTable1"
            listener="#{catalog.commandButton_action}"/>
   </h:inputText>

The execute attribute specifies which components (space delimited, if multiple components are specified) of the JSF page participate in the execute portion of the request.

The event attribute specifies which Document Object Model (DOM) event initiates an Ajax request. The valueChange event is specified, which is also the default for JSF EditableValueHolder components, such as an input text component.

The render attribute specifies the components to be rendered in the Render Response phase of the request. Because the dataTable1 component is at the same hierarchical level as the inputText component, the "form1" is omitted and only dataTable1 is specified in the render attribute.

The listener attribute specifies the method to invoke when an AjaxBehaviorEvent is broadcast. In the following sub-section, the JSF Ajax JavaScript library is used for sending an Ajax request.

Right-click input.xhtml to run input.xhtml with the URL http://localhost:7101/JSF2-ViewController-context-root/faces/input.xhtml.

The image and style.css resources get rendered, as shown in Figure 1.


Figure 1. Rendered Image and style.css Resources

Specify a SQL query (SELECT * FROM OE.CATALOG) and click somewhere on the page outside the input text field to generate a valueChange event. A data table gets rendered (see Figure 2), which indicates that jsf.js got included in the page with a <script> tag.


Figure 2. Rendered Data Table

The EL expression for an image resource can also be used in other elements, such as the </a> element.

 <a href="#{resource['images:logo.jpg']}" >Logo</a>  

Rerun input.xhtml. The Logo link gets rendered, as shown in Figure 3.


Figure 3. Rendered Logo Link

Click the Logo link. The logo.jpg image gets rendered, as shown in Figure 4.


Figure 4. Rendered logo.jpg Image

We have used only the simplest form of convention for a resource in the resources folder, a library and the resource file, but the resource identifier can consist of other components. The complete format of the resource identifier can include a locale prefix, a library version, and the resource version, adding support for localization and versioning. The resourceName is the only required component of a resource identifier.

Resource Relocation Pitfall

Some resources, such as JavaScript scripts, can be rendered in a location other than the location of the resource tag. We used resource relocation when we specified the target attribute in the h:ouputScript tag to render the <script> element in the <head> element.

 <h:outputScript library="javax.faces" name="jsf.js" target="head"/>  

If we had omitted the target attribute, jsf.js would have been rendered inline. h:outputStylesheet renders only in the <head> element. The <h:head> tag is required in the Facelets page if a script is to be targeted to the <head> element or a style sheet is to be rendered.

As an example, remove the h:head tag by commenting it out.


Figure 5. Commenting out the h:head Tag

Redeploy the Facelets application and run the input.xhtml page. h:graphicImage gets rendered, but style.css and jsf.js do not get included, as noted by the absence of the styles and the Ajax feature in the rendered page, as shown in Figure 6.


Figure 6. Absence of Styles and Ajax Functionality

View Parameters

JSF 2.0 added support for view parameters, which add the provision to send request parameters in a GET request. A view parameter is a UI component represented with the UIViewParameter class. Just like other UI components, it is saved in the UI component tree for a Facelets page and can be associated with validators and converters. A view parameter is an EditableValueHolder because it implements the interface.

The mappings for view parameters to managed bean properties are specified in f:viewParam tags, which are specified within the f:metadata tag. The f:metadata tag is specified within the f:view tag. The f:view tag is optional with JSF 2.0 Facelets, and if it is included, it should be the outermost component tag.

For example, add the following f:viewParam tag to the f:metadata tag to specify the view parameter catalogId with value binding to managed bean property catalogId.

<f:view> 
<f:metadata> 
  <f:viewParam id="catalogId" name="catalogId" value="#{catalog.catalogId}"/> 
 </f:metadata>
...
</f:view>

The view parameters’ bindings are specified in the Facelets page metadata, and view parameters’ values are specified in the GET request URL. The GET request parameter values get set on the managed bean properties, as specified in the view parameters’ mappings, when the GET request is sent with a URI, for example:

 http://localhost:7101/context-root/faces/input.xhtml?catalogId=2.  

Preemptive Navigation

Preemptive navigation allows you to determine the resource file you navigate to and request parameters, if any, based on the navigation case and view parameters. This, then, allows you to create a URL for JSF resources you access from a GET request, so the URL displayed shows the resource and all request parameters. We will describe this using an example in the "REST-Style GET URLs and Bookmarkability" section.

Preemptive navigation is determining the destination URL for an h:link or h:button component prior to the h:link or h:button being activated or selected. An h:link component generates an <a/> tag and an h:button component generates an <input/> tag of type button.

The advantage of preemptive navigation is that the destination URL of the <a/> tag or <input/> tag is not hardcoded in the h:link or h:button. For example, you might want to include a variable request parameter in the destination URL. The destination URL for h:link and h:button components is predetermined during the Render Response phase and navigated to when a user activates the component by clicking the component.

The navigation case, including the target URL and target view ID, are evaluated and resolved during the Render Response phase before a user has activated the component, adding a provision for bookmarkable URLs that generate non-Faces requests when clicked.

Preemptive navigation might use either implicit navigation or declarative navigation to construct the target URL. The target URL is retrieved using a non-Faces request when a user activates a hyperlink or a button.

JSF 2.0 introduced the UIOutcomeTarget component, which has an outcome associated with it. The two subclasses of UIOutcomeTarget are HtmlOutcomeTargetButton and HtmlOutcomeTargetLink, and the corresponding UIComponent tags are h:button and h:link. In contrast, pre-JSF 2.0 UICommand components resolve and implement navigation at the same time after the Invoke Application phase.

PreRenderView Event Handling

JSF 2.0 provides a new system event, PreRenderViewEvent, which is dispatched after the view parameters have been processed, but before the view has been rendered. A listener for the event is registered using the f:event tag and its listener attribute. The following are some ways to apply a preRenderView event:

  • Load application data prior to rendering a view.
  • Set application context prior to rendering a view.
  • Navigate to a different view, not the view to be rendered, prior to which the event is dispatched.

For example, add an f:event tag within the f:metadata tag and specify its type to be preRenderView and the listener to be a createSQLQuery method in the managed bean:

<f:metadata> 
  <f:viewParam id="catalogId" name="catalogId" value="#{catalog.catalogId}"/>	
  </f:viewParam> 
<f:event type="preRenderView" listener="#{catalog.createSQLQuery}" />
 </f:metadata>
 

Redeploy and rerun input.xhtml and include a request parameter, catalogId, with a value of 2 in the request URL. The listener method createSQLQuery within the f:event tag invokes the createSQLQuery method prior to rendering the view to create and run a SQL query to generate a result set that is used to create a data table. The input.xhtml Facelets page gets rendered with a data table for catalogId 2, without having to specify a SQL query.


Figure 7. Generating a Data Table Using the PreRenderView Event

REST-Style GET URLs and Bookmarkability

In Representational State Transfer (REST), a URI represents a resource. For example, an employee can be represented with /employee/12345.

JSF 2.x provides support for REST-style GET URLs, which are generated by the h:link element, and bookmarkability. Using preemptive navigation, the outcome specified in the h:link component and the request parameters, which are processed by view parameters, are used to determine the destination URL by the JSF navigation handler during the Render Response phase. The resulting destination URLs are bookmarkable. The view parameters can be included in the resulting destination URLs using the includeViewParams attribute.

For example, add the following h:link element to input.xhtml to construct the destination URL from an outcome output2 and the view parameters, if there are any.

 <h:link outcome="/output2" includeViewParams="true" value="Create DataTable"/>  

Using the employee example, the h:link would be as follows:

 <h:link outcome="/employee/12345" includeViewParams="true" value="Employee 12345"/>  

Implicit navigation is used to map the outcome to a view ID (output2.xhtml or 12345.xhtml, in the preceding examples) and, subsequently, preemptive navigation is used to construct the destination URL during the Render Response phase of the GET request generated by the h:link element. The view parameters are added to the destination URL using the paramname=paramvalue format. includeViewParams can also be specified in the outcome itself.

 <h:link outcome="/output2? includeViewParams=true" value="Create DataTable"/>  

When the bookmarkable URL is selected (clicked), the JSF framework (the Faces servlet) is not invoked and a non-Faces request (similar to a redirect navigation) is generated.

Next, modify the f:metadata tag in input.xhtml to include only an f:viewParam tag, without the f:event tag for the preRenderView event.

   <f:metadata>
            <f:viewParam id="catalogId" name="catalogId" value="#{catalog.catalogId}"></f:viewParam>
       </f:metadata>

Create a new Facelets page, output2.xhtml, to create a JSF data table from view parameter catalogId. The f:metadata tag includes a f:event tag for the preRenderView event type and a listener, createSQLQuery.

<f:metadata>             <f:viewParam id="catalogId" name="catalogId" value="#{catalog.catalogId}"></f:viewParam>             <f:event type="preRenderView" listener="#{catalog.createSQLQuery}"/>         </f:metadata> 

Modify the createSQLQuery method in the managed bean to return the String literal "output" so that the navigation handler navigates to output.xhtml using implicit navigation.

 	// return null;     return "output";  

Re-deploy and run the Facelets page input.xhtml with URL http://localhost:7101/JSF2-ViewController-context-root/faces/input.xhtml?catalogId=2, which includes a request parameter. A bookmarkable hyperlink gets rendered (see Figure 8). The destination URL for the link gets constructed during the rendering phase.


Figure 8. Bookmarkable Link

To find the destination URL, select View>Source. The destination URL for the Create DataTable link includes the output2.xhtml Facelets page as the resource page and catalogId as a request parameter.

output2.xhtml is ascertained to be the destination resource using implicit navigation from the outcome value output2. The request parameter, catalogId, is added to the URL using view parameters.


Figure 9. Bookmarkable Link with Destination URL Constructed Using Preemptive Navigation

Click the Create DataTable hyperlink. The URL, http://localhost:7101/JSF2-ViewController-context-root/faces/output2.xhtml?catalogId=2, gets invoked in the browser.

The output2.xhtml Facelets page has a preRenderView event configured that navigates to the output.xhtml. We did not have to hardcode the destination URL in h:link. The destination URL is variable based on the request parameters» values. In the postback, the data table in output.xhtml gets rendered and displayed.


Figure 10. Rendered Data Table

Conclusion

In this article, we discussed JSF 2.0 features, such as Ajax support, view parameters, preemptive navigation, event handling, and bookmarkable URLs, all of which make JSF 2.0 well suited for the cloud environment. Looking ahead, it is planned that Java Platform, Enterprise Edition 7 (Java EE 7) will update the JSF specification for cloud-related practical considerations, such as multitenancy and elasticity, also known as horizontal scaling.

See Also

About the Author

Deepak Vohra is a NuBean consultant, Web developer, Sun Certified Java 1.4 Programmer, and Sun Certified Web Component Developer for Java EE and an Oracle Certified Associate, Oracle database 10g.