Search |
||
Spring, ICEFaces, and the dreaded thread-bound request issuePosted by felipeal on March 6, 2008 at 12:21 AM PST
In this blog, I provide a quick solution for an issue that arises when you use ICEFaces server-push technology combined with Spring JSF integration.
Normally, I would provide a detailed context of the issue at hand (with links to relevant pages like the java.net blog entitled "Sample Application using JSF, Spring 2.5, and Java Persistence APIs", forum posts, etc), and would spend more time polishing the text (specialyty for grammar erros that mades I luke lick a idiotic :-), etc.. But, unfortunately, I'm in a rush, so I will provide just the bare details. Long story short, a nice feature of Spring 2.5 is that you can eliminate almost completely the XML configuration hell, replacing it by annotations. And I mean not only the Spring XML files, but also faces-config.xml. Instead of defining your managed beans on faces-config.xml, you delegate the task to Spring, and your "face" is reduced to:
This setup works fine with "normal" requests served by JSF pages, but if you use ICEFaces, once it pushes an event to your page, you get a nasty exception similar to this:
I googled for it and found some developers complaining about the same issue, but didn't find any solution. After some further research and debugging, I realized what the problem is. Normally, Spring intercepts each request (through the org.springframework.web.context.request.RequestContextListener, which must be added to web.xml), and add its BeanFactory to the request thread context (using a ThreadLocal reference). But when ICEFaces does a server push, RequestContextListener interception is not triggered.The solution? First, adding a JSF phase listener that mimics RequestContextListener behavior:
Then on your managed bean, clean up the context after ICEFaces rendered the page. For instance:
And the final step, adding the listener to faces-config.xml:
The solution is relatively simple and straightforward; hopefully this blog will help others facing the same issue.On a side note, it would be nice to add a test case for such class, something like this:
The problem is, setting a mock FacesContext is not trivial. Initially, I thought I could use Easymock, but it would require half-a-dozen mocks, and I wasn't in the mood for that. Then I tried to use Spring Mock, but looks like it doesn't provide a MockFacesContext anymore. Other options might be Shale or JSFUnit, but I haven't had the time to play with these tools yet.So, I'd like to finish this blog with a question - which tool/framework would you recommend for such test case? »
Related Topics >>
Web Applications Comments
Comments are listed in date ascending order (oldest first)
Submitted by sbridges on Thu, 2008-03-06 10:32.
Should you clear the ThreadLocal's at some point by doing,
LocaleContextHolder.setLocale(null);
RequestContextHolder.setRequestAttributes(null);
Submitted by felipeal on Thu, 2008-03-06 12:51.
Yes, it does, good catch. I updated the blog.
Thanks for pointing it out... -- Felipe
Submitted by tedgoddard on Fri, 2008-03-07 09:12.
Thanks Felipe, this is very useful information. We'll look at setting the ThreadLocal automatically when ICEfaces detects a Spring environment.
Submitted by felipeal on Fri, 2008-03-07 09:50.
Ted,
An out-of-the-box support by either ICEFaces and/or Spring would be great, but I don't think ICEFaces should set these ThreadLocals directly, it would be a hack suited to a specific integration (Spring), not to mention the classes dependencies. A more generic approach would be making sure the request listeners registered in the web application have their requestInitialized()/requestDestroyed() called at the proper times when ICEFaces do a server push. This solution not only wouldn't introduce any Spring dependency, but would avoid other frameworks (or even custom RequestListeners) face this same issue. -- Felipe
Submitted by jdijkmeijer on Thu, 2008-12-04 09:19.
Thanks great stuff! one little thing though...
By doing:
final ServletRequestAttributes attributes = new ServletRequestAttributes(request);
You lose authorization information, which in our case made our page render partially. We changed it to:
final ServletRequestAttributes attributes = new ServletWebRequest(request); Which also exposed user authorization.
I'm not sure about the impact but for us it works now!
Submitted by jdijkmeijer on Thu, 2008-12-04 10:02.
Hmm apparently it works on jetty, not on Websphere 6.1...
|
||
|
|