JSF detect session timeouts with web filter

Standard

When working with JSF 2.0 you will encounter a situation in which the user’s session times out and ajax requests fail. The response on a ajax request will be a viewExpiredException. However, the root cause is the session has expired. They are essentially stuck on the page and are forced to reload.

The solution:

Using a WebFilter the user can gracefully be redirected to a view expired exception page. This solution is accomplished by checking if the users session is valid, and if the context path is within our required conditions, finally if it is a ajax request it overwrites the default JSF response with our own custom xml response that tells the browser to redirect to the view expired exception page.

@WebFilter(filterName = "SessionTimeoutFilter", urlPatterns = "*.jsf")
public class SessionTimeoutFilter implements Filter {

    private final String timeoutPage = "/errors/viewExpired.xhtml";

    private final String loginPage = "/login.jsf";
    
    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException,
    ServletException {

        if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;

            if (isRequireSessionControl(httpServletRequest) && isSessionInvalid(httpServletRequest)) {

                if (isAJAXRequest(httpServletRequest)) {
                    StringBuilder sb = new StringBuilder();
                    sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><partial-response><redirect url=\"")
                        .append(httpServletRequest.getContextPath() + timeoutPage).append("\"></redirect></partial-response>");
                    httpServletResponse.setHeader("Cache-Control", "no-cache");
                    httpServletResponse.setCharacterEncoding("UTF-8");
                    httpServletResponse.setContentType("text/xml");
                    PrintWriter pw = response.getWriter();
                    pw.println(sb.toString());
                    pw.flush();
                    return;
                }

                httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + timeoutPage);
                return;
            }
        }
        filterChain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    private boolean isAJAXRequest(HttpServletRequest request) {
        boolean check = false;
        String facesRequest = request.getHeader("Faces-Request");
        if (facesRequest != null && facesRequest.equals("partial/ajax")) {
            check = true;
        }
        return check;
    }

    private boolean isRequireSessionControl(HttpServletRequest httpServletRequest) {
        String requestPath = httpServletRequest.getRequestURI();
        return !requestPath.contains(timeoutPage) && !requestPath.contains(loginPage)
                        && !requestPath.contains("javax.faces.resource");
    }

    private boolean isSessionInvalid(HttpServletRequest httpServletRequest) {
        return httpServletRequest.getRequestedSessionId() != null && !httpServletRequest.isRequestedSessionIdValid();
    }
}

Note: This fix is required due to a bug that is set to be resolved in JSF 2.3 release: https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-790

What is a JSF component binding? How can I use it?

Standard

One of the more flexible features of Java Server Faces is the ability to use bindings within a view. Most developers omit the binding attribute and rely on a component libraries magic to display errors to the end user. Using the JSF binding component it is possible to specify the binding view component name for the UIComponent in the java backing bean. This binding refers to an instance of UIComponent in the EL scope allowing you to access certain properties #{mybinding.clientId}, #{mybinding.value},  #{mybinding.valid},  #{mybinding.submittedValue}

For example, lets assume you have a selectOneMenu with a list of items. These items are U.S states, then below you have a inputText area where the end user enters his/her city. We do not want to allow them to enter a city that is not in a state.

The problem can be solved using bindings. Consider this solution that binds the selected state value to the city entered. When submitted the validator will have access to both components.

The View

<h:selectOneMenu binding="#{state}" value="#{myBean.selectedState}">
    <f:selectItems value="#{myBean.states}" />
</h:selectOneMenu>
<h:inputText value="#{myBean.city}">
    <f:attribute name="state" value="#{state.value}" />
    <f:validator validatorId="locationValidator" />
</h:inputText>

Backing validator

@FacesValidator("locationValidator")
public class LocationValidator implements Validator {

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) {
        Object item = component.getAttributes().get("state");
        // Object value holds city name
    }

}

Using bindings as described provides a solution for more complex validation requirements.

Using bindings with Bootstrap 3

Arguably the most popular css library out is Boostrap 3. It provides a sleek look to web pages. Using component bindings you can easily marry JSF with Bootstrap CSS. This is because components have a isValid EL expression attached to them.

For example lets assume you have a inputText that requires a min length of 4 and a max of 6. If outside of that requirement you want the field to be marked as invalid.

To highlight invalid fields use the binding component together with a form-group. The form-group has a has-error CSS class that will highlight the field inside. Once the inputText validation fails and refreshes the screen it will call the EL expression #{name.valid} and render the has-error class.

<div class="form-group  #{!name.valid ? 'has-error' : 'none'}">
   <label for="name" class="control-label">Enter name</label>
   <h:inputText value="#{myController.name}" binding="#{name}" id="name" styleClass="form-control">
      <f:validateLength minimum="4" maximum="6" />
   </h:inputText>
</div>

Whats the difference between #{mybinding.value} and  #{mybinding.submittedValue}?

This can be answered by understanding that the order of components matters. JSF will process your components in the order they appear in the view. The backing javascript for JSF does this. So for example if I was to swap the order of my state / city example so that the selectOneMenu came after the city inputText I would need to use the bindings submittedValue as ordering would cause the binding to be empty on the validator.