Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

The AjaxCommand strategy for JSF

Update the Command pattern to handle common Ajax requests

  • Print
  • Feedback

Page 3 of 5

A note about AjaxAction

"deleter" (DeleteVoAction) is an implementation of AjaxAction, as you can see if you refer back to Figure 1. The idea is to separate the actual knowledge of how to delete an object from the user interface layer and also allow the delete logic to be used elsewhere. That is, the AjaxCommand interface subclass, whose job it is to deal with the nuts and bolts of the request, employs the AjaxAction to decouple itself from the business logic.

In this example, the DeleteVoAction just delegates to a facade call. You might start out with the facade call in the AjaxCommand itself and refactor it out later.

You make some gains by moving the facade call into the AjaxAction. First, implementing an interface means the object that knows about the facade (which is presumably in the core of the application) can be placed into that package or project. That is to say, you may not want to include a reference from an AjaxAction subclass (which might be in a JSF/front-end specific project) to the facade class.

Another benefit of moving the logic out into an interface implementation is that you can defer the actual subclass to someone else, who may not even be a member of your team. This flexibility is useful if you are creating a framework for someone else. Such flexibility is the core motivation behind the GOF Command pattern, although it isn't such a common requirement for Web application developers.

Step 4. Execute the handleAjaxRequest method

Looking at the handleAjaxRequest method from the DeleteWithId will give you a more concrete idea of how the backing bean deals with the Ajax request.

Listing 5. DeleteWithId.handleAjaxRequest()

public class DeleteWithId implements AjaxCommand {
...
public void handleAjaxRequest(FacesContext context) {
  HttpServletRequest request =
    (HttpServletRequest)context.getExternalContext().getRequest();

  String id = request.getParameter("com.company.jsf.id"); // Get id

  BusinessObject bo = businessObjectUtil.getNodeFromId(id);

  if (bo == null){ log.info("Didn't find object with id: " + id); return; }
  boolean success = true;
  String detail = vo.getLiteralName() + " deleted.";

  try {
    deleter.action(bo);
  } catch (Exception e){
    if (log.isWarnEnabled()) { log.warn("Failed to delete entity: ", e); }
    success = false;
    detail = e.getMessage(); // Get error message for response
  }

    HttpServletResponse response =
      (HttpServletResponse)context.getExternalContext().getResponse();

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

    try {
      if (success){
        String responseString = new String("<message>"+
          "<status>OK</status>"+
          "<detail>"+detail+"</detail>"+
          "<id>"+id+"</id>"+
          "</message>");

          response.getWriter().write(responseString);
      } else {
        String responseString = new String("<message>"+
    "<status>ERROR</status>"+
    "<detail>"+detail+"</detail>"+
    "<detail>"+detail+"</detail>"+
    "<id>"+id+"</id>"+
    "</message>");
    response.getWriter().write(responseString);
      }
    } catch (IOException ioe){
      if (log.isErrorEnabled()) { log.error(
        "Exception writing ajax response: ", ioe); }
    }
  }
...
}




The essence of this method is as follows:

  1. Get the ID for the object to delete from the request in string form.
  2. Get the Object from the ID (using the util class you parameterized in the managed bean declaration).
  3. Call the action method of deleter (which was also parameterized), passing it the object ID.
  4. Send a response to the user interface. Remember that JSF is now done with this request because you called responseComplete() back on the PhaseListener.

A quick look at deleter.action() (DeleteVoAction.action()) shows that this method just delegates the job:

Listing 6. DeleteVoAction.action()

public class DeleteVoAction implements JsfAction{
...
public void action(Object o){
  CoreVO[] nodePath = (CoreVO[])o;

  VOHelper.getFacade().deleteVO(nodePath);
}
...

Setting up the PhaseListener

The last step for the server side is to set up the phase listener, which is easy. Your first step is to define the listener in your faces-config.xml file, as shown in Listing 7.

Listing 7. faces-config, phase-listener

<faces-config>
...
<lifecycle>
  <phase-listener>
    ajaxcommand.toolbox.jsf.listeners.AjaxListener
  </phase-listener>
</lifecycle>
...

</faces-config>


Next, in the listener itself, you tell JSF when to execute the listener. Start by telling it what phase to run in, like so:

public PhaseId getPhaseId() {
        return PhaseId.RESTORE_VIEW;
    }

You then have a choice of running in the public void afterPhase (PhaseEvent event) method or the public void beforePhase (PhaseEvent event).

In this case you'll choose to run the listener in the RESTORE_VIEW phase. You are handling an Ajax request, so you want to avoid the rest of the processing life cycle. In this example, you implement the event handling in the beforePhase method. Because you aren't relying on any view components, you don't even require the view to be present. The managed bean does the work for you.

  • Print
  • Feedback

Resources