The AjaxComponent strategy for JSF: The best of both worlds

Ajax-enable your components with a phase listener

1 2 3 4 5 6 7 Page 2
Page 2 of 7

The Component class and the AjaxInterface

Let's begin with the extremely simple and essential interface: the AjaxInterface, shown in Listing 1. This is the interface that will be implemented by the sample JSF component you'll build over the course of this article.

Listing 1. The AjaxInterface

public interface AjaxInterface {

    public void handleAjaxRequest(FacesContext context);
}

Nice and simple, just how we like it.

If you are familiar with how the JSF component model works, you know that the Component class is essentially a state-holding mechanism, and the real work is done by the Renderer. The Component class defines what the Component is, while the Renderer defines what it does. (Just to avoid confusion, I should point out that when people talk about a JSF component in general, they usually mean the whole bundled thing: the Component class, the Renderer, tag handler, and so on, as opposed to the Component class alone.)

Now take a look at the Component class itself, shown in Listing 2.

Listing 2. The Component class

public class AjaxComponent extends UIComponentBase implements AjaxInterface {
  private static final transient Log log = LogFactory.getLog(tutorial.jsf.ajax.component.AjaxComponent.class);

  public static final String DEFAULT_RENDERER_TYPE = "tutorial.jsf.ajax.component.AjaxComponentRenderer";
  public static final String COMPONENT_FAMILY = "tutorial.jsf.ajax.component.AjaxComponent";
  public static final String COMPONENT_TYPE = "tutorial.jsf.ajax.component.AjaxComponent"; // Used by Tag Handler

  public AjaxComponent() {
    this.setRendererType(AjaxComponent.DEFAULT_RENDERER_TYPE);
  }

  public String getFamily() {
    return COMPONENT_FAMILY;

  /**
   * This method is executed by the Ajax listener when an Ajax call for this component is detected.
   */
  public void handleAjaxRequest(FacesContext context){
    // Delegate to the Renderer
    AjaxRendererInterface renderer = (AjaxRendererInterface)this.getRenderer(context);
    renderer.handleAjaxRequest(context, this);
  }
}

Again, this is a very simple class. Of course, much of the complexity exists in the UIComponentBase base class; but the work you'll be concerned with is just delegated to the Renderer, in order to keep the code that handles the request in the same place as the code that sets up the request.

The Renderer and AjaxRendererInterface

The Renderer in a JSF component is responsible for outputting whatever is necessary to display the component, and for handling the input coming from the user for that component. In this case (and for most cases, really), the output is HTML and JavaScript. For the standard (non-Ajax) request processing, the decode() method processes the input. In this case, as you saw above, the component delegated the handling of the Ajax response to the renderer.

Again, the AjaxRendererInterface defines one method, handleAjaxRequest(). Listing 3 demonstrates how that method works.

Listing 3. The Renderer: handleAjaxRequest()

public void handleAjaxRequest(FacesContext context, UIComponent component){
  if (log.isInfoEnabled()) { log.info("BEGIN handleAjaxRequest()"); }
  HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();

  String textField = request.getParameter(INPUT_NAME);
  String serverContribution = "SERVER RESPONSE: ";
  StringBuffer xml = null;

  if (textField == null){
      if (log.isInfoEnabled()) { log.info("No parameter found for text field."); }
  } else {
    if (log.isTraceEnabled()) { log.trace("textField: " + textField); }
    // We now have the new value entered by the user
    // Now we create our XML response
    xml = new StringBuffer("<response>");

    xml.append("<message>" + serverContribution + textField + "</message>");

    xml.append("<status>OK</status></response>");
  }

  if (xml == null){
    if (log.isInfoEnabled()) { log.info("Response is null."); }
    xml = new StringBuffer(this.getErrorString());
  }
  // Now we are ready to send the response
  HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getResponse();

  response.setContentType("text/xml");
      response.setHeader("Cache-Control", "no-cache");

      try {
        response.getWriter().write(xml.toString());
        if (log.isInfoEnabled()) { log.info("Response sent: " + xml); }
      } catch (IOException e){
        if (log.isErrorEnabled()) { log.error("Error writing ajax response.", e); }
      }
}

protected String getErrorString(){
    return new String("<response><message>There was a problem</message><status>ERROR</status></response>");
}


Remember, the handleAjaxRequest() method is invoked when the user has submitted an Ajax request to the component. The method is responsible for doing everything necessary, both receiving data and formulating the response. This sample method is very simple, but it communicates the idea that you get some data from the user, do some processing on the server, and return a response. All this method does is take whatever the user sent and return it back as SERVER RESPONSE: <USER INPUT> to demonstrate that the server had its say.

1 2 3 4 5 6 7 Page 2
Page 2 of 7