java left logo
java middle logo
java right logo
 

Home arrow Java EE Tips
 
 
Main Menu
Home
Java Tutorials
Book Reviews
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Java Network
Java Forums
Java Blog




Most Visited Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews
Top Rated Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews


Statistics
Registered Users: 3947
Java SE Tips: 614
Java ME Tips: 202
Java EE Tips: 183
Other API Tips: 779
Java Applications: 298
Java Libraries: 209
Java Games: 16
Book Reviews:
 
 
 
Using AJAX With Non-HTML Markup in JSF E-mail
User Rating: / 20
PoorBest 

This Tech Tip reprinted with permission by java.sun.com

JavaServer Faces (JSF) technology is a framework that simplifies building user interfaces for Java EE and J2EE applications. The March 24, 2004 Tech Tip, Introducing JavaServer Faces Technology gave a brief overview of the technology. It also showed how to create a JSF application that includes GUI components that are modeled by the JSF framework. A later tip showed how to create custom components with JavaServer Faces technology. Since the publishing of those tips, the technology has gone to the 1.2 level. One of the new features in JSF 1.2 is the ability to support multiple render kits in a single JSF application. In JSF, render kits are used to present the user interface in a markup such as HTML. JSF comes with an HTML render kit, but you could write a render kit to display user interface components in other markup languages such as Scalable Vector Graphics (SVG) or XML User Interface Language (XUL).

You might want to take advantage of the strengths that each markup language provides by combining them in a single JSF application. For example, you can use SVG to create sophisticated graphics and animations for an application. However SVG does not have a widget set which includes buttons or other components. You have to create these widgets using a markup. In contrast, XUL has a complete set of user interface controls that can easily be used, but it lacks the graphical capabilities that SVG provides. Common to both of these markups is the lack of a built-in form submission mechanism like the one available in HTML. However Asynchronous JavaScript and XML (AJAX) can be used with some JSF 1.2 features to effectively produce form submissions from non-HTML markup. In this tip you'll see a demonstration that uses AJAX and three render kits (HTML, SVG, and XUL) in a JSF application. (For more information about AJAX see the November 22, 2005 Tech Tip, Using AJAX with Java Technology.)

JSF Life Cycle Example

User interactions with a JSF application are processed in a series of steps known as the "JSF life cycle". Typically the life cycle is illustrated as a set of connected boxes, with each box identifying a phase in the process. Lines with arrows show the flow from one phase to the next. Accompanying this tip is an example JSF application that displays an animated version of the JSF life cycle. As mentioned earlier, the application uses the HTML, SVG and XUL render kits.

The following diagram shows the flow of the demo between the pages of different markup:

jsf-lifecycle

The application begins with the display of an HTML page that gives some background and design details pertinent to the demonstration.

Image

This page is produced with the standard HTML render kit. If you click the Next button at the bottom of the page it displays an SVG page that is rendered with an SVG render kit. The SVG page graphically illustrates the JSF life cycle.

Image

If you click on any box that represents a life cycle phase (such as Restore View Phase), it uses AJAX to generate a form submission. In response, you should see an XUL page that displays more detail about that JSF life cycle phase.

Image

Below the JSF life cycle illustration is a larger box that contains various buttons with labels such as Initial Request and Validation Error. If you click on these buttons you'll see an animated display of a specific process flow through the life cycle phases (for instance, the process flow for handling an initial request).

Image

Let's take a look at some of the code for the demonstration.

Posting From The Client

First, let's examine the SVG page. Here is a snippet of the SVG page written with JSF tags:

   <%@ page contentType="image/svg+xml"%>
   <%@ taglib uri="http://java.sun.com/jsf/svg" prefix="g" %>
   <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
   ...
      <f:view renderKitId="SVG" >
         <g:form id="form">
   ...
            <g:commandButton id="restore" width="120" 
                   height="50" x="100" y="100" type="submit"
                   action="xul-restore"
                   style="stroke:black; fill:#8470ff;" >
                 <g:outputText x="130" y="120"
                    textAnchor="middle" value="Restore" />
                 <g:outputText x="135" y="140"
                    textAnchor="middle" value="View" />
            </g:commandButton>
   ...
         </g:form>
      </f:view>

Notice the page directive that indicates the content type of the page:

   <%@ page contentType="image/svg+xml"%>

and the tag that indicates that SVG is the rendering technology for the page:

   <f:view renderKitId="SVG" >

You can learn more about the directives, tags, and attributes that need to appear on a page that uses a render kit such as SVG, in the article Creating and Using a Custom Render Kit.

In response to the information on the SVG page, the SVG render kit on the server produces the following SVG markup:

   <svg xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink">
   ...
     <script xlink:href="/jsf-renderkits/src/script/http-svg.es">
     </script>
     <script xlink:href="/jsf-renderkits/src/script/lifecycle.es">
     </script>
     <g id="form" method="post" 
         action="/jsf-renderkits/render/svg.jsp">
   ...
       <g id="form:restore" onclick="form_post(evt)">
         <rect width="120" height="50" x="100" y="100" 
            style="stroke:black; fill:#8470ff;"></rect>
         <text x="100" y="150" text-anchor="middle"></text>
         <text x="130" y="120">Restore</text>
         <text x="135" y="140">View</text>
       </g>
   ...
       <text name="javax.faces.ViewState" 
       id="javax.faces.ViewState" value="_id4:_id6" 
          visibility="hidden">_id4:_id6</text>
       <text name="javax.faces.RenderKitId" 
          id="javax.faces.RenderKitId" value="SVG" 
          visibility="hidden">SVG</text>
     </g>
   <script><![CDATA[
   function form_post(evt) {
     var control = evt.target;
     var form = getForm(control);
     var postData = getPostData(form, control);
     var url = "/jsf-renderkits/render/svg.jsp";
     sendRequest(url, postData);
   }
   //]]>
   </script>
   </svg>

This code is produced by various renderers in the SVG render kit. The encodeBegin() method of the FormRenderer produces the following ECMAScript file references:

   <script xlink:href="/jsf-renderkits/src/script/http-svg.es">
   </script>
   <script xlink:href="/jsf-renderkits/src/script/lifecycle.es">
   </script>

and also the starting "form" group:

  <g id="form" method="post" 
      action="/jsf-renderkits/render/svg.jsp">

The action attribute in the starting "form" group is used to identify this SVG element as a "form" element. The element is widely used in SVG.

The ButtonRenderer and TextRenderer encode methods produce the starting and ending group elements for the button control, and the associated dimensions and label for the button control:

   <g id="form:restore" onclick="form_post(evt)">
     <rect width="120" height="50" x="100" y="100" 
        style="stroke:black; fill:#8470ff;"></rect>
     <text x="100" y="150" text-anchor="middle"></text>
     <text x="130" y="120">Restore</text>
     <text x="135" y="140">View</text>
   </g>

Note that the onclick method name, form_post, is determined from the button control's parent form component:

   public void encodeBegin(FacesContext context, 
     UIComponent component)
          throws IOException {
   ...
       UIComponent root = context.getViewRoot();
       UIComponent myForm = component;
       while (!(myForm instanceof UIForm&& root != myForm) {
           myForm = myForm.getParent();
       }
       String formMethodName = myForm.getClientId(context
           "_post(evt)";
       writer.writeAttribute(
           "onclick", formMethodName, "onclick");   

The FormRenderer.encodeEnd() method writes out page state and the ending group element for the form control:

   <text name="javax.faces.ViewState" 
   id="javax.faces.ViewState" value="_id4:_id6" 
      visibility="hidden">_id4:_id6</text>
    <text name="javax.faces.RenderKitId" 
        id="javax.faces.RenderKitId" value="SVG" 
        visibility="hidden">SVG</text>
  </g>

It also produces the JavaScript function that will collect the post data and send the request:

   <script><![CDATA[
   function form_post(evt) {
     var control = evt.target;
     var form = getForm(control);
     var postData = getPostData(form, control);
     var url = "/jsf-renderkits/render/svg.jsp";
     sendRequest(url, postData);
   }
   //]]>
   </script>

he mapping is such that the request goes to the JSF controller.

The functions getForm, getPostData and sendRequest are all defined in the http-svg.es ECMAScript file. (You can find the http-svg.es file in the renderkits\src\script directory of the example JSF application.) For example, here's part of the definition of the getPostData function:

   function getPostData(form, control) {
       
       var formValues = new Array();
       formValues[0new Object();
       formValues[0].id = control.parentNode.id;
       formValues[0].value = control.parentNode.id;
       formValues[1new Object();
       formValues[1].id = form.id;
       formValues[1].value = form.id;
   
   ...
       
       var postData = "";
       for (var i=0; i<formValues.length; i++) {
           if (formValues[i].id == "javax.faces.ViewState") {
               var re = new RegExp("\\+""g");
               var val = formValues[i].value;
               formValues[i].value = val.replace(re, "\%2B");
           }
           postData += formValues[i].id + "=" 
               formValues[i].value;
           if (i != formValues.length-1) {
               postData += "&";
           }
       }
       return postData;
   }

Notice that getPostData sends the hidden field javax.faces.ViewState. This is how JSF determines that the request is a post back.

Processing the Request

When the request is sent to JSF, it goes through the normal JSF life cycle processing steps. However, there is a special JSF phase listener registered to execute after the invoke applications phase (that is, just before the render response phase). If the request is an AJAX request (denoted by the XML-HTTP string in the request header), this phase listener will get the view identifier of the view that will be rendered next. The phase listener then puts the view identifier in the response header.

   public class ResponsePhaseListener implements PhaseListener {

      private static final String XML_HTTP = "XML-HTTP";
       private static final String VIEW_URI = "VIEW-URI";
   ...
       public void afterPhase(PhaseEvent event) {
           // Disregard requests that are not XMLHttpRequest(s)
           Map<String, String> requestHeaderMap =
                 event.getFacesContext().getExternalContext().
                       getRequestHeaderMap();
           if (requestHeaderMap.get(XML_HTTP== null) {
               return;
           }
           // If we're dealing with an XMLHttpRequest...
           // Get the URI and stuff it in the response header.
           FacesContext context = event.getFacesContext();
           String viewId = context.getViewRoot().getViewId();
           String actionURL = 
               context.getApplication().getViewHandler()
                 .getActionURL(context, viewId);
           HttpServletResponse response = (HttpServletResponse
               context.getExternalContext().getResponse();
           response.setHeader("Cache-Control""no-cache");
           response.setHeader(VIEW_URI, actionURL);
       }
   ...
   }

The processResponse method gets the view identifier from the response header. The client then loads that location. The processResponse method is defined in the http-svg.es ECMAScript file.

   function processResponse() {
       var request = getXMLHttpRequest();
       if (request.readyState == 4) {
           if (request.status == 200) {
               var action = 
                   request.getResponseHeader("VIEW-URI");
               window.location.href = action;
               return;
           }
      }
   }

For more information using render kits in JSF, see the technical article Creating and Using a Custom Render Kit.

Running the Sample Code

A sample package accompanies this tip that demonstrates the techniques covered in the tip. You can deploy the sample package on any web container that supports the Servlet 2.5 API, JavaServer Pages (JSP) Technology 2.1, and JSF 1.2. You will also need to use JDK 5. For the client (browser) you need to use a Mozilla browser with built-in SVG support, such as Firefox 1.5.

To install and run the sample:

  1. If you haven't already done so, download GlassFish from the GlassFish Community Downloads page. GlassFish supports Servlet 2.5 and the JSP 2.1 "out of the box".
  2. Download the sample package for the tip and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/renderkits, where <sample_install_dir> is the directory in which you installed the sample package. For example, if you extracted the contents to C:\ on a Windows machine, then your newly created directory should be at C:\renderkits. The renderkits directory contains the web archive, renderkits.war, for the application, and the subdirectories src and web for viewing source.
  3. Start the GlassFish Application Server by entering the following command:
    
          <GF_install_dir>/bin/asadmin start-domain domain1
    
          where <GF_install_dir> is the directory in which you installed GlassFish.
    
  4. Deploy the sample by copying <sample_install_dir>/renderkits/jsf-renderkits.war to <GF_install_dir>/domains/domain1/autodeploy
  5. Open your browser to the URL: http://localhost:8080/jsf-renderkits/. As mentioned previously, you need to use a Mozilla browser, such as Firefox 1.5, with built-in SVG support.

About the Author

Roger Kitain is the JavaServer Faces co-specification lead. He has been extensively involved with server-side web technologies and products since 1997. Roger started working on JavaServer Faces technology in 2001, as a member of the reference implementation team. He has experience with Servlet and JSP technologies. Most recently, Roger has been involved with different rendering technologies for JSF.

Copyright (c) 2004-2005 Sun Microsystems, Inc.
All Rights Reserved.


 Related Tips

 
< Prev   Next >

Page 1 of 0 ( 0 comments )

You can share your information about this topic using the form below!

Please do not post your questions with this form! Thanks.


Name (required)


E-Mail (required)

Your email will not be displayed on the site - only to our administrator
Homepage(optional)



Comment Enable HTML code : Yes No



 
       
         
     
 
 
 
   
 
 
java bottom left
java bottom middle
java bottom right
RSS 0.91 FeedRSS 1.0 FeedRSS 2.0 FeedATOM FeedOPML Feed

Home - About Us - Privacy Policy
Copyright 2005 - 2008 www.java-tips.org
Java is a trademark of Sun Microsystems, Inc.