June 23, 2004

What your mama don't tell you about JSF

... or how to access faces context and backing beans in a servlet filter

No updates for awhile, sorry. I've actually been busy coding, but let's get to the business of blogging now. So the thing is that for some reason or the other you would like to populate values in your Javaserver Faces backing beans in a servlet filter. Ur big fat mama in this case is Craig McClanaghan (much kudos to him btw for all the work he has done for Struts and JSF). Craig happily explains how to get a reference to your bean from the faces context, but then bluntly states that sorry, because a filter is running before a Faces servlet the context hasn't been set up for this request, so you cannot access it in a filter. Stupid as I am, I didn't believe that.

JSF people probably forgot the whole filter spec, which is SOO useful for all handly things, such as authorization and for supporting stupid devices that only know how to generate GET requests. Anyway, the code to set up a faces context in a filter:


// You need an inner class to be able to call FacesContext.setCurrentInstance
// since it's a protected method
private abstract static class InnerFacesContext extends FacesContext
{
  protected static void setFacesContextAsCurrentInstance(FacesContext facesContext) {
    FacesContext.setCurrentInstance(facesContext);
  }
}

private FacesContext getFacesContext(ServletRequest request, ServletResponse response) {
  // Try to get it first
  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);

  // Either set a private member servletContext = filterConfig.getServletContext();
  // in you filter init() method or set it here like this:
  // ServletContext servletContext = ((HttpServletRequest)request).getSession().getServletContext();
  // Note that the above line would fail if you are using any other protocol than http

  // Doesn't set this instance as the current instance of FacesContext.getCurrentInstance
  facesContext = contextFactory.getFacesContext(servletContext, request, response, lifecycle);

  // Set using our inner class
  InnerFacesContext.setFacesContextAsCurrentInstance(facesContext);

  // set a new viewRoot, otherwise context.getViewRoot returns null
  UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext, "yourOwnID");
facesContext.setViewRoot(view);

  return facesContext;
}

// You can even use a NavigationHandler
  NavigationHandler navigationHandler = facesContext.getApplication().getNavigationHandler();

  navigationHandler.handleNavigation(facesContext,"getrequest", "works");

// you could just render the page here but since we are still in filter, it might be
// a better idea to forward to the actual page
// facesContext.getApplication().getViewHandler().renderView(facesContext, facesContext.getViewRoot() );

  request.getRequestDispatcher(facesContext.getViewRoot().getViewId() ).forward(request, response);

Neat, huh?

Posted by thoughts at June 23, 2004 05:25 PM | TrackBack
Comments

How is using a Filter compared with using a PhaseListener?

Implementing a PhaseListener requires implementing 3 methods:
- public void beforePhase (PhaseEvent event)
- public void beforePhase (PhaseEvent event)
- public PhaseId getPhaseId () //the choice of Faces phase to handle

The 1st 2 methods allow a use of the PhaseEvent parameter, which is very useful to get a FacesContext (FacesContext context = event.getFacesContext();).

Could you please comment on the differences between using a Filter and using a PhaseListener?

Posted by: Ophir Radnitz at August 16, 2004 03:07 AM

Thanks for comments Ophir. Check out my response, a new post on filters and PhaseListeners. You can click on "posted by" to get there.

Posted by: Alphageek at August 19, 2004 12:33 AM

On URL http://www.thoughtsabout.net/blog/archives/000033.html

Reference was made to the "servletContext" in Statement:

facesContext = contextFactory.getFacesContext(servletContext, request, response, lifecycle);
but it was never instaniated in the method???

I'm trying to obtain the "ActionEvent" from the Request via a Filter.. I believe this is possible based on your comments???? How could this be accomplished

Posted by: Dan Harth at September 24, 2004 10:47 PM

Thanks Dan for your comments. Yeah, sorry about not mentioning anything about that. "servletContext" actually happened to be a private member that I set in the filter's init(FilterConfig filterConfig) method, by calling filterConfig.getServletContext(), that's why it wasn't instantiated anywhere in the method. I fixed the code in the blog post. Unlike FacesContext, which is set up per every request, servletContext is set up once during the application start-up. If you are using a container confirming to servlet 2.3 spec, you can get a reference to servlet context from HttpServletRequest.getSession().getServletContext() as well.

And to answer your question, yes, getting an ActionEvent in a filter should be possible once you get the facesContext set up.

Posted by: Alphageek at September 27, 2004 07:09 PM

thank you
thank you
thank you

as a matter of fact, i am using a filter to do authorization, and i ran into the problem you outlined above. your solution worked like a champ.

Posted by: tomas at January 4, 2005 12:48 PM

Nice site, good job.

Posted by: Sylvester at October 28, 2005 03:31 PM

Hi.

Can you tell me how I can get the backing beans from my servlet?

Thanks

Posted by: Rune at January 12, 2006 05:10 AM

So I have started in on my project. If this works, this will be a very cool and elegant solution. It involves a ton of experimentation, but hopefully the end result will pay off bigtime. I’m using Chaperon to parse the data. The cool part is that Chaperon includes Cocoon Generators and Transformers, so, hopefully, if I can wrap my head around the workings of Chaperon, I will be able to do all this parsing and decoding from within Cocoon.

Posted by: eminem curtain call at January 28, 2006 06:19 PM

Saved my day !
Ive created an http based OCSP responder with JSF for the gui part.

The oscp servlet now can access jsf managed beans thanks to your example.

Posted by: Rickard at April 4, 2006 09:14 AM

It is said in JSF spec that for non-faces generated request a new life cycle of jsf should be created.can u elaborate on this.I am new to jsf.My requirement is an external web application should send parameters to portal jsf but in my jsf i get null parameter values.Can u pls help me out in this regard

Posted by: Lakshmi at May 24, 2006 11:45 PM

How to use the variable resolver? I like to have a class for storing and retrieving some data at application level, not at page level.

Posted by: Huib Valstar at September 23, 2006 01:37 AM

Wonderful articles. Thanks for such a nice information http://anne.messageboard.nl/25247

Posted by: Levitra at April 5, 2007 01:46 AM

I found lots of intresting things here. Please more updates.

Posted by: Albert Bibingo at May 4, 2007 03:49 PM
Post a comment









Remember personal info?