ISPOSTBACK in JSF

Although this kind of mechanism is not necessary as it’s in other frameworks like asp.net, I’ve observed in many places where people are demanding such a feature to understand a postback in JSF. I still don’t belive this need is a good practice since developers should not need to care about http cycles and consider them in the development process, but in the end it seemed challenging to figure out a way. I thought the best place to check for the postback is a view handler. In JSF using the decorator design pattern you can change the default behavior of the view handler.

A view handler has several methods like creating, rendering and restoring the view. This reveals the answer actually, when create view is called than it is simply not a postback. Here is the custom view handler.

package extensions;

import java.io.IOException;
import java.util.Locale;
import java.util.Map;

import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;

public class CustomViewHandler extends ViewHandler {

  protected ViewHandler baseViewHandler;

  public CustomViewHandler(ViewHandler viewHandler) {
    super();
    this.baseViewHandler = viewHandler;
  }

  public Locale calculateLocale(FacesContext facesContext) {
    return baseViewHandler.calculateLocale(facesContext);
  }

  public String calculateRenderKitId(FacesContext facesContext) {
    return baseViewHandler.calculateRenderKitId(facesContext);
  }

  public UIViewRoot createView(FacesContext facesContext, String arg1) {
    setPostback(facesContext, false);
    return baseViewHandler.createView(facesContext, arg1);
  }

  public String getActionURL(FacesContext facesContext, String arg1) {
    return baseViewHandler.getActionURL(facesContext, arg1);
  }

  public String getResourceURL(FacesContext facesContext, String arg1) {
    return baseViewHandler.getResourceURL(facesContext, arg1);
  }

  public void renderView(FacesContext facesContext, UIViewRoot arg1throws IOException, FacesException {
    baseViewHandler.renderView(facesContext, arg1);
    
  }

  public UIViewRoot restoreView(FacesContext facesContext, String arg1) {
    setPostback(facesContext, true);
    return baseViewHandler.restoreView(facesContext, arg1);
  }

  public void writeState(FacesContext facesContextthrows IOException&nbs
p;
{
    baseViewHandler.writeState(facesContext);
  }
  
  public Map getRequestScope(FacesContext facesContext) {
    return (Map)facesContext.getApplication().createValueBinding("#{requestScope}").getValue(facesContext);
  }
  
  public void setPostback(FacesContext facesContext, boolean value) {
    getRequestScope(facesContext).put("ispostback"new Boolean(value));
  }

}
      

To plug-in this view handler to the application following decleration goes into the faces-config.

 <application>
   <view-handler>extensions.CustomViewHandler</view-handler>
</application>

In order to get the info set by the view handler, the following method can be used;

    public boolean isPostback() {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    Map requestScope = (Map)facesContext.getApplication().createValueBinding("#{requestScope}").getValue(facesContext);
    boolean ispostback = ((Boolean)requestScope.get("ispostback")).booleanValue();
    return ispostback;
  }
      

Important: The view handler approach won’t work when the state saving is set to server because the views are cached in session and create view is not called. I guess a better alternative to the viewhandler is hacking the navigation handler. I don’t think same issue will occur when a navigation handler is used to check for a postback.

11 Responses to ISPOSTBACK in JSF

  1. Jim Hazen says:

    A tip for 1.1 users is to check the ExternalContext’s requestParameterMap and return true if its size is greater than 0.

    This should work in both client and server side state saving modes.

  2. Cagatay says:

    Well,that’s what I call a trick Jim.

  3. Nice post. I just want to add that IBM has attached page events in its JSF implementation.
    You can attach logic to the page load and post events.
    The page events are attached to the tag of a JSF page. The events are:
    1. Page Load Begin?Before rendering (changes to managed beans take effect).
    2. Page Load End?After rendering (changes to managed beans have no effect).
    3. Page Post?When the page is submitted.

  4. Cagatay,

    Shale’s viewController has such a method included. and jsf 1.2 too (as mentioned before)

    Using Shale is what I prefer instead of using IBM’s JSF impl🙂

    -Matthias

  5. Cagatay says:

    Yes, I know Shale has it. I don’t know 1.2 has it too but anyway I’ve done this because I wondered how it can be done. Also I’ll prefer anything instead of IBM’s JSF:)

  6. Cagatay says:

    I just realized that requestParamMap trick won’t work when a navigation happens without a redirect. It does not always works.

  7. alberto coletti says:

    I think a phase listener can make the trick..
    putting a listener after the restore phase it will be invoked only if the page is a postback…i’m wrong?

  8. Cagatay says:

    Don’t think so, it will be invoked for a new request too.

  9. Seshu says:

    what if the backing bean is session scoped?

%d bloggers like this: