"Simple Software"

OcpSoft

JSF 2.0 Extension Development: Accessing FacesContext in a Filter

January 3rd, 2009 by Lincoln

The Problem:

So you need a way to instantiate the 2.0 FacesContext in a Filter, but when you use the same method that you have in the past, you get NullPointerExceptions all over the place when attempting to access any values through El. The ScopedAttributeElResolver bombs when attempting to set values or access methods in backing beans.) It’s not too hard to get this working again.

The Answer:

It turns out that it’s not much different from how we may have solved this in the past, but our new JSF2.0 ScopedAttributeElResolver expects a ViewRoot object to be set so that we can gain access to the new ViewScope attributes. However… so the first thing we need to do is set a blank UIViewRoot in the FacesContext so that we will not crash when ScopedAttributeElResolver tries to do this:

Map<String,Object> viewMap = facesContext.getViewRoot().getViewMap(false);

See our little FacesContextBuilder class here:

import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
 
public class FacesContextBuilder
{
    public FacesContext getFacesContext(final ServletRequest request, final ServletResponse response)
    {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        if (facesContext != null)
        {
            return facesContext;
        }
 
        FacesContextFactory contextFactory = (FacesContextFactory) FactoryFinder
                .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
        LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
                .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
        Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
 
        ServletContext servletContext = ((HttpServletRequest) request).getSession().getServletContext();
        facesContext = contextFactory.getFacesContext(servletContext, request, response, lifecycle);
        InnerFacesContext.setFacesContextAsCurrentInstance(facesContext);
        if (null == facesContext.getViewRoot())
        {
            facesContext.setViewRoot(new UIViewRoot());
        }
 
        return facesContext;
    }
 
    private abstract static class InnerFacesContext extends FacesContext
    {
        protected static void setFacesContextAsCurrentInstance(final FacesContext facesContext)
        {
            FacesContext.setCurrentInstance(facesContext);
        }
    }
}

Just one more thing to worry about:

Once you hand off your request to the FacesServlet, if you try to do any work in a PhaseListener before the RESTORE_VIEW phase (in the beforePhase() method) you will again experience the null ViewRoot issue, but this time, you cannot set a new UIViewRoot object, so you must wait until the afterPhase() method is called to do your work. ViewRoot will have been initialized by the JSF application at that point.

Happy Extension Writing!

Post to Twitter Post to Delicious Post to Digg Post to StumbleUpon

Posted in JSF

One Comment

  1. [...] you are manipulating any FacesContext when doing any kind of Sevlet Forwards – such as from a filter – you MUST release() any FacesContext you’ve created. The consequences of forgetting this are [...]

Leave a Comment




Please note: In order to submit code or special characters, wrap it in <pre lang="java"> </pre> - or your tags will be eaten.

Please note: Comment moderation is enabled and may delay your comment from appearing. There is no need to resubmit your comment.

Search

Recent Posts

Recent Comments

OcpSoft Agile Management

Recent Tweets:

Posting tweet...

Sponsored By:

Resources

Meta