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 2 of 5

AjaxCommand on the server-side

The AjaxCommand strategy uses a phase listener, which seems to be the most common approach to handling Ajax requests in JSF. AjaxCommand is the key interface.

Figure 1 shows the classes involved.

 

A class diagram of the AjaxCommand strategy

Figure 1. A class diagram of the AjaxCommand strategy

All of this is pretty straightforward. What you can't see in the diagram is that the PhaseListener gains its reference to the AjaxCommand instance by pulling a class name out of the request. Setting up the PhaseListener is easy, I'll walk through it in just a moment. In the meantime, Listing 1 shows the phase-listener method that does the work:

Listing 1. A hard-working PhaseListener method

public void beforePhase (PhaseEvent event){
...
if (AjaxRequestUtil.isAjaxCommand(context)){ // 1)
  if (log.isTraceEnabled()) { log.trace("Got ajax command..."); }
  String ajaxCommandBean = AjaxRequestUtil.getAjaxCommandBeanName(context); // 2)
  if (ajaxCommandBean == null){
    throw new NullPointerException(
      "This was an ajaxCommand request but no ajaxCommandBean name was found under key: " + AjaxCommand.AJAX_COMMAND_BEAN_KEY);
  }
  ValueBinding vb = context.getApplication().createValueBinding(
    "#{"+ajaxCommandBean+"}"); // 3)
  AjaxCommand command = (AjaxCommand)vb.getValue(context);
  command.handleAjaxRequest(context); // 4)
  // Call response complete, we are going to handle the response ourselves
  context.responseComplete();
}

The PhaseListener does the following in Listing 1 (note the numbered references in the above code sample):

  1. Checks to see if the event is an AjaxCommand request.
  2. Gets the AjaxCommand bean name from the request (throwing an exception if not found).
  3. Gets the AjaxCommand bean from a value binding.
  4. Executes the handleAjaxRequest method (you might check for null first).

I'll break each of these steps out into some detail in the next sections.

Step 1. Check to see if the event is an AjaxCommand request

The AjaxRequestUtil.isAjaxCommand() is called by the phase listener in Listing 2.

Listing 2. AjaxRequestUtil.isAjaxCommand()

public class AjaxRequestUtil {
...
public static boolean isAjaxCommand(FacesContext context){
  HttpServletRequest request =
    (HttpServletRequest)context.getExternalContext().getRequest();
  Map requestMap = request.getParameterMap();

  boolean ajaxKeyIsTrue = false;

  if (requestMap.containsKey(AjaxCommand.AJAX_COMMAND_KEY)){
    ajaxKeyIsTrue = "true".equals(request
      .getParameter(AjaxCommand.AJAX_COMMAND_KEY));
  }

  return ajaxKeyIsTrue;
}

In Listing 2 you check the request for a parameter under a given key (a constant AjaxCommand.AJAX_COMMAND_KEY that should be something unique, like: public static final String AjaxCommand.AJAX_COMMAND_KEY = "com.companyname.jsf.AJAX_COMMAND";). If that key is present and has the value you want, you return true.

Step 2. Get the AjaxCommand bean name from the request

Next, you use AjaxRequestUtil.getAjaxCommandBeanName() to pull the AjaxCommand bean name out of the request. Note that AjaxRequestUtil also uses a straightforward parameter in the request, as shown in Listing 3.

Listing 3. AjaxRequestUtil.getAjaxCommandBeanName()

public class AjaxRequestUtil {
...
public static String getAjaxCommandBeanName(FacesContext context){
  HttpServletRequest request =
    (HttpServletRequest)context.getExternalContext().getRequest();
  Map requestMap = request.getParameterMap();

  String ajaxCommandId = request.getParameter(AjaxCommand.AJAX_COMMAND_BEAN_KEY);

  if (ajaxCommandId == null){
    if (log.isWarnEnabled()) {
      log.warn("There was NO AjaxCommand bean name found under key: " +
        AjaxCommand.AJAX_COMMAND_BEAN_KEY); }
    }

    return ajaxCommandId;
  }
}

Step 3. Get the AjaxCommand bean from a value binding

In Step 3 you leverage JSF's managed bean facility. With the bean name in hand you do a programmatic lookup, which basically says, "Give me the bean bound under this name."

Here's the declaration of the bean in faces-config.jsf:

Listing 4. faces-config, DeleteItemCommand bean definition

<faces-config>
...
  <managed-bean>
    <description>Command to delete item from Ajax Request</description>
    <managed-bean-name>DeleteItemCommand</managed-bean-name>
    <managed-bean-class>
      ajaxcommand.jsf.ajax.DeleteWithId
    </managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
    <managed-property>
    <property-name>businessObjectUtil</property-name>
      <value>#{idUtil}</value>
    </managed-property>
    <managed-property>
      <property-name>deleter</property-name>
      <value>#{DeleteVoAction}</value>
    </managed-property>
  </managed-bean>
...



<faces-config>

In Listing 4 you find the class under the logical name DeleteItemCommand. The class DeleteWithId implements the AjaxCommand interface. The "WithId" part of the name signifies that what you are deleting will be designated by an "Id", regardless of where the delete is called from. Note that if you needed to use more information than just an ID to identify the objects, it would be trivial to do that.

Note that you also parameterize DeleteWithId with a couple classes. The first, businessObjectUtil, is a utility class that allows you to look up the object based on Id.

  • Print
  • Feedback

Resources