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 arg1) throws 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 facesContext) throws 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