Skip to main content

Bundling Ajax into JSF components

June 7, 2007

{cs.r.title}



Any Java developer who has already worked with "http://java.sun.com/javaee/javaserverfaces/">Java Server Faces
has undoubtedly come across the need for a custom component. Most components in JSF implementations are rudimentary and don't really address real-world situations--if data-entry solutions for all problem domains were as simple as a login form, then JSF would be just the right tool out of the box. The saving grace of the
framework is the ability to create and extend custom components,
and if you couple that with the power and versatility of Ajax, you
really start to reap the benefits of the modern
Model-View-Controller architecture.

Why JSF and Ajax?

Ajax and JSF would on the surface seem to be two technologies
that would be difficult to marry. Ajax processing is predominantly
client-side, while JSF processing is predominantly server-side.
Ajax is mostly JavaScript and JSF is Java. While very different,
the two technologies can combine to create a powerful set of
reusable user interface tools for developers.

Let's look at an example. A developer is using JSF to create a
form element that requires some specific input. This form element
is just a simple input text field, but when the user tabs out of
the field, an Ajax validation routine is triggered from the
onblur event to test the validity of the typed data.
The developer has to use this input field in many places in the
application and has to embed the same JavaScript into the component
on page every time it is used. Now what if all that code could be
embedded into the component instead of the page? The page developer
could continue to drop components onto the page and everything else
would be taken care of. By shifting the validation processing into
the component itself, we've made an extremely reusable, reliable
component. The best benefit of this might be that we could also
treat the tag as an interface and the implementation would be at
the discretion of the tag developer. Any changes to the
implementation would be transparent to the page developer. These
benefits apply to all custom JSF components.

Now let's take a look at how to get started creating some of our
own.

Creating a JSF Component from Scratch

Creating a JSF component can be a bit of a challenge at first,
due to the steps involved and the considerations of the "http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JSFIntro10.html">JSF
lifecycle
. Knowing what is going on at a given time is
extremely important if you are going to make the proper
method calls when they are needed. Later on, we'll discuss a JSF
PhaseListener that will allow processing during JSF
lifecycle events. There are six events in the lifecycle. A deeper
discussion of these events is beyond the scope of this article, but
a detailed explanation of these events is located on Sun's "http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JSFIntro10.html">Java
Server Faces
site.

  1. Restore view.
  2. Apply request values; process events.
  3. Process validations; process events.
  4. Update model values; process events.
  5. Invoke application; process events.
  6. Render response.

Now that we've mentioned the lifecycle events, we'll continue
creating our custom component. Creating a component from
scratch involves four steps. Later on, we'll use these steps to
create our first custom component.

  1. Create a rendering class for your component.
  2. Define the component in faces-config.xml.
  3. Create a tag class for placing the component in a page.
  4. Create the tag library definition in a .tld file.

Extending Existing JSF Components

The simplest way to create your own JSF component is to find an
existing component that already takes care of most of the grunt
work for you. For example, say you want a text field to be a
calendar input, so you extend an existing component that renders an
input field to do the job. Why go through all the trouble of
creating your own from scratch when the largest portion of the
rendering work is done for you in an existing component?

Please note that the terms component and tag can be
used interchangeably depending on the context. In this article,
"component" refers the item we want to place on a page as a whole.
For example, an input text field on a JSF page is a component. "Tag" refers to the tag class or tag placed on the page by the
developer. The tag is what is responsible for placing and
configuring our component. Also, note that the renderer is the
class responsible for writing the component content.

Let's look at a renderer example for extending an existing
component. For this example, we are extending another renderer that
creates a input text field. Remember that it doesn't really matter
here which implementation of input text we are using because all
implementations carry the same attributes as the JSF reference
implementation, but most add more attributes for convenience or
enhanced functionality. "http://myfaces.apache.org/tomahawk/index.html">Apache MyFaces
Tomahawk
, for example, adds attributes for to handle the display
of content based on the user's security role.

[prettify]
public class MyHtmlInputTextRenderer extends HtmlInputTextRenderer

      public void encodeBegin(FacesContext context,
                 UIComponent component) throws IOException {

      super.encodeBegin(context, component);

    //We could create any other component and share attribute values
    //from this tag to another component
    //Renderer baseRenderer = 
    //  context.getRenderKit().getRenderer("javax.faces.Form", "javax.faces.Form");
    //baseRenderer.encodeBegin(context, component);
}

public void encodeEnd(FacesContext context,
                UIComponent component) throws IOException {

    ResponseWriter writer = context.getResponseWriter();
        
    // get properties from UIOutput that were set by the specific taghandler
    String myMessage  =
        (String)component.getAttributes().get("myattributemessage");

        writer.startElement("p", component);
        writer.writeText("myMessage");
        writer.endElement("p");
        writer.write("\n");
    }

    //We could create any other component and share attribute values
    //from this tag to another component
    //Renderer baseRenderer = 
    // context.getRenderKit().getRenderer("javax.faces.Form", "javax.faces.Form");
    //baseRenderer.encodeEnd(context, component);

super.encodeEnd(context, component);
}
[/prettify]

There's a lot of potential here in this code. We could
manipulate the existing component in any fashion we choose. Note
that in the encodeEnd method, a call to get the
property myattributemessage was retrieved and
displayed to the user. By extending an existing component, we not
only get all the existing attributes, but we can just add new ones
in our .tld definition.

In order to make extending existing components work, you've got
to put all the pieces together. The renderer and tag classes
should extend an existing tag and an existing component and you
still need to create the component definition in the
faces-config.xml and the tag library definition. Note,
however, a painful limitation of the JSP tag library
specification: if you extend an existing tag, you must create your
own tag library definition for that component. The simplest thing
to do is to find the .tld definition for the tag you are extending
and copy that tag's definition into your own .tld, and then you are
free to make modifications. This is cumbersome, especially when you
are looking at extending a component that has 50 attributes. A
useful future feature of creating tag libraries would be to give
the developer the capability to extend another tag's definition
through some XML element; this would bring the tenets of object-oriented programming into .tld files. Just be glad that you can pick
up all 50 of those attributes by extending an existing tag class, or
you might also have had to write all 50 getters and setters as
well.

Let's recap extending existing JSF components by laying out the
steps involved in doing so.

  1. Extend the rendering class for a component that is similar to
    the component you want to create.
  2. Define the component in faces-config.xml.
  3. Extend the tag class of the component you are mimicking.
  4. Copy the original .tld definition for the component you are
    mimicking into your .tld file. Remember to change it to point to
    your subclass.

Now that we know the steps to creating or extending our own JSF
components, we can move on creating more advanced components using
Ajax.

Use a PhaseListener to Deliver Ajax Content

A benefit of using faces is that you don't need to define
servlets to deliver content to Ajax calls. A
PhaseListener fires at each stage of the JSF
lifecycle, letting you intercept a request and write to the
response. Ajax data can be delivered in many ways, including XML,
HTML, and JSON (JavaScript Object Notation). By far the simplest way
to deliver content is JSON. JSON syntax is simpler to generate
using json_simple.jar, it requires less bandwidth than
XML, and doesn't require parsing by JavaScript on the client side
like XML does. You'll need to download the source code from
json.org and compile it
yourself. More information about the JSON syntax can be found at
the JSON home page.

Let's take a look at an example of a PhaseListener
and how it will deliver content to an XmlHttpRequest.

[prettify]
import java.io.IOException;

import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.*;
import java.io.*;

public class AjaxPhaseListener implements PhaseListener
{
  public void afterPhase(PhaseEvent event)
  {
    String viewId = event.getFacesContext().getViewRoot().getViewId();
    if (viewId.indexOf("Ajax") != -1)
    {
      handleAjaxRequest(event);
    }
  }
  private void handleAjaxRequest(PhaseEvent event)
  {
    FacesContext context = event.getFacesContext();
    HttpServletResponse response = (HttpServletResponse) context
        .getExternalContext().getResponse();
    Object object = context.getExternalContext().getRequest();
    if (!(object instanceof HttpServletRequest))
    {
      //Only handle HttpServletRequests
      return;
    }

    HttpServletRequest request = (HttpServletRequest) object;
    

    // actually render using JSON.
    try
    {
    JSONObject myMessage = new JSONObject();
    myMessage.put("message", "I am sending a message");
    response.setContentType("text/plain");
    response.setHeader("Cache-Control", "no-cache");
    
      response.getWriter().write(secureWrapJSON(myMessage));
      event.getFacesContext().responseComplete();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }
  public void beforePhase(PhaseEvent arg0)
  {
    //not used, but implemented to satisfy compiler
  }
  public PhaseId getPhaseId()
  {
    return PhaseId.RESTORE_VIEW;
  }
}

//Secure wrap the JSON to prevent hijacking
        public String secureWrapJSON(JSONObject json) {

                return "/*" + json + "*/";

        }




[/prettify]

Don't forget to configure the PhaseListener in the
faces-config.xml:

   
       com.oreilly.ajax.AjaxPhaseListener
  

The PhaseListener checks the request to see if the
view requested contains the word "Ajax." If it does, it delivers a
message to the response in the form of JSON text. It is that
simple. On the client side, this message can be read into a
JavaScript object by calling eval on the
responseText property of the parm of your callback
method. JSON can be as complex and as structured as you want it to
be. For the sake of this example, we just sent a one-line message.
In reality, you will typically be sending much larger data. Below
is the message you would see if you hit Ajax.faces with your
browser.

{"message":"I am sending a message"}

This could just as easily have been XML being returned on the
response, but then we would have to parse the XML with JavaScript,
making a simple task fairly arduous.

Creating Your Component and Embedding Your Ajax

The reality of creating an Ajax-enabled JSF component is that it
really isn't any different from creating any JSF component, except
that the Ajax code is written in the renderer class. For the sake
of simplicity, JavaScript functions should be included in a
.js file. Don't attempt to write JavaScript inside the
renderer directly. Below is the JavaScript to get the JSON message
from our PhaseListener.

[prettify]



function getMessage() {

var url = "Ajax.faces";

if (window.XMLHttpRequest)
     {
         // browser has native support for XMLHttpRequest object
         req = new XMLHttpRequest();
     }
     else if (window.ActiveXObject)
     {
         // try XMLHTTP ActiveX (Internet Explorer) version
         req = new ActiveXObject("Microsoft.XMLHTTP");
     }
     
     if(req)
     {
         req.onreadystatechange = responseHandler;
         req.open("Get", url, true);
         req.onreadystatechange = callback;
         req.setRequestHeader("content-type","text/plain");
         req.send(null);
     }
}

function callback() {
 
   var jsonData = req.responseText;
   //omitted code for stripped secure JSON /* json */

   var jsonObject = eval('(' + jsonData + ')');

   var message = jsonObject.message;

   alert(message);
      }
  }
[/prettify]

The code is pretty straightforward as Ajax goes. Remember that
Ajax is not some new language; it is just merely the concept of
making an asynchronous call from JavaScript behind the scenes to get
data. It doesn't really have to be any more complicated than
that.

The call to getMessage() will be embedded into our
JSF component in the renderer so that it fires with a certain
event; onblur(), for example. The
getMessage() method will make a call to the Ajax.faces
URL and get our JSON data, and the callback function will get the
message text and send an alert.

One thing to remember is that since the JavaScript function code
will be included in a .js file, you should write the
JavaScript call for the file into the renderer. Doing this will
make the component more modular, but it will also create a
redundancy if you have to include your component many times in one
JSF page. Another solution would be to create an initializer tag
that will write your JavaScript support classes into a page. Either
way, it needs to be easy for page developers to use your
component.

[prettify]
public class MyRenderer extends Renderer

      public void encodeBegin(FacesContext context,
           UIComponent component) throws IOException {
           ResponseWriter writer = context.getResponseWriter();
           writer.startElement("script", component);
           writer.writeAttribute("language", "text/javascript", null);
           writer.writeAttribute("src", "/js/ajax.js", null);
           writer.endElement("script");
           writer.write("\n");
    }

  }
[/prettify]

Another option to simplify matters would be to use an Ajax
framework like Dojo or
Prototype to ease the
pain of writing all that boilerplate Ajax code. Let's take a look
at what Dojo could do for us.

First we need to include the dojo.js file into our
component like we did above with our .js file. We still also
need our .js file, because it will contain our callback
function. Remember to write out the include for the dojo.js file
before our file or our JavaScript will be useless.

[prettify]
function getMessage(){
        dojo.io.bind({
                    url: ajax.faces,
                    sync: false,
                    load: function (type, data, evt){
                              callback(data); 
                              },
                    error: function(type, error){ 
                       dojo.debug('Error getting JSON data:' + error.message);
                    },
                    mimetype: "text/json-comment-filtered"
                    });
                    
}

function callback(type, data, evt){
    alert(data.message);
}

[/prettify]

Now we have seriously cut back on some code. We are now using
Dojo to hide all the nasty Ajax interactions for us. This will make
our code much cleaner.

Please make note that the code above is using the MIME type
text/jason-comment-filtered. This will tell Dojo to
expect the JSON to be commented and the framework will strip the
comments and eval the data for you. Also, note that
sync is set to false. If you set this to true, the
browser will lock until the call finishes. The default for this is
always false. There are several informational "http://today.java.net/pub/a/today/2006/04/27/building-ajax-with-dojo-and-json.html">
articles
on the Web to get you started using Dojo and JSON.

Let's take a look at the same article above written using
Prototype.

[prettify]
function getMessage(){

    //NOTE: Prototype expects secure as /*-secure- {json} */
    //NOTE: IF you send response.setHeader("X-JSON", jsonString)
    //from server, then AJAX will parse it into a JSON Object, protecting
    //your JSON from being exposed

        Ajax.Request({
             url: ajax.faces,
             //parameters: 
             method: 'get',
             onComplete: function (type, data, evt){
                   callback(data); },
             mimetype: "application/X-JSON"
        });
                    

}

function callback(type, data, evt){

    alert(data.message);

}
[/prettify]

Looking At It from Above

Now that we know what it takes to write a Ajax-enabled JSF
component, let's recap with a set of clearly defined steps.

  1. Decide whether you want a new JSF component or you want to
    extend an existing one and follow the steps for that process.
  2. Create and configure a PhaseListener to deliver
    Ajax content to the response.
  3. Embed JavaScript includes into the renderer class'
    encodeBegin() method.
  4. Embed your method call to trigger your Ajax method into the
    renderer or the tag class.

We have all the tools necessary to create our own Ajax-enabled
JSF components. We have also leveraged some open source tools to
simplify the process. Make note that there are already many
Ajax-enabled JSF components already out there and most are open
source. The ability to create reusable dynamic web components is
where the power in the coupling of JSF and Ajax lies.

Resources

width="1" height="1" border="0" alt=" " />
Chris Hardin is a Senior Java Architect in Birmingham, Alabama.
Related Topics >> Web Development Tools   |