BestPractices
BestPractices

Reputation: 12876

Why is Phase Listener-based JSF redirect not working for AJAX requests when session has timed-out?

I have a JSF Phase Listerner that checks to see if the user is logged in, and if not, redirects them to the login page. This is working fine for non-ajax requests. However, if the user is on a page, in my case, one that has a primefaces data table, and clicks on a button that invokes an ajax request -- but their session has timed out -- the code gets executed that issues the redirect (using ExternalContext#redirect), however the user is not navigated to the login page.

Any idea why this is not working?

Here is my phase listener:

private static final String IS_LOGGED_IN_INDICATOR = "loggedIn";
private static final String LOGIN_PAGE = "/login.jsp";

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

public void beforePhase(PhaseEvent event) {
    ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
    HttpSession session = (HttpSession)ec.getSession(false);

    if (session==null || session.getAttribute(IS_LOGGED_IN_INDICATOR) == null) {
       try {
            ec.redirect(LOGIN_PAGE);
       }
       catch(IOException e) {
           // log exception...
       }            
    }
}

public void afterPhase(PhaseEvent event) {
    // no-op
}   

}

Upvotes: 1

Views: 4836

Answers (2)

BalusC
BalusC

Reputation: 1108742

It failed because the ajax context is trying to obtain the render kit from the view root, while there is no view root at all. It has not been restored at that point yet. This resulted in a NullPointerException in PartialViewContext#createPartialResponseWriter(). This exception is in turn not been thrown, but instead been put in an ajax exception queue which is supposed to be handled by a custom ExceptionHandler. You apparently don't have any one. This exception is visible if you create/use such one like the FullAjaxExceptionHandler (see also this blog for more detail).

To fix the particular problem, do the job in afterPhase() instead. The view root is then fully restored and the ajax context can obtain the render kit from it in order to write a specialized XML response which instructs the JSF ajax engine in JavaScript to change the window location. Without ajax, a render kit was not necessary as a redirect is basically just a matter of setting a response header.

Whether the particular NullPointerException is in turn a bug in Mojarra or not is a different question which can better be posted in flavor of an issue report at their own issue tracker.

Upvotes: 3

FMQ
FMQ

Reputation: 418

this is because you have to send a special response in XML for Ajax request in order to do redirect (check this answer) , I have implemented this in a Filter like this..

// Check if it's an Ajax Request 
if ("partial/ajax".equals(((HttpServletRequest) request).getHeader("Faces-Request"))) {
      //redirect 
      response.setContentType("text/xml");
      response.getWriter()
           .append("<?xml version=  \"1.0\" encoding=\"UTF-8\"?>")
           .printf("<partial-response><redirect url=\"%s\"></redirect></partial-response>",url);

you should port this to your Phase Listener.

Upvotes: -1

Related Questions