The Source for Java Technology Collaboration
User: Password:



Felipe Leme's Blog

Felipe Leme Felipe Leme has worked professionally with Java since 1996, and in the last years had became an active enthusiastic of the technology: he is a frequent speaker in the main Brazilian Java conferences, presented at JavaOne for 3 years in a row, is a developer of a few Java-based open-source projects (like DbUnit and Jakarta Cactus), and is an individual member of the Java Community Process, where he took part of the JSP 2.1 and Java EE 5.0 expert groups.

He is a father of two, and in his spare time likes to assemble jigsaw puzzles and collect Marvel comic books with his older son, Thomas. He used to scuba dive as well, but have not dove yet in this new millennium.

Currently, he works as an independent consultant and Java instructor in Brazil, but is planning to move back to the US, where he worked from 1999 to 2002.



Spring, ICEFaces, and the dreaded thread-bound request issue

Posted by felipeal on March 06, 2008 at 12:21 AM | Permalink | Comments (4)

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:

<faces-config>   
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
  </application>
</faces-config>
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:

Mar 5, 2008 11:51:14 PM com.sun.faces.lifecycle.LifecycleImpl phase
WARNING: executePhase(RENDER_RESPONSE 6,com.icesoft.faces.context.BridgeFacesContext@9b774e) threw exception
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myBean': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request? If you are actually operating within a web request and still receive this message,your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:293)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:888)
	at org.springframework.web.jsf.el.SpringBeanFacesELResolver.getValue(SpringBeanFacesELResolver.java:94)
	at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:53)
	at com.sun.faces.el.FacesCompositeELResolver.getValue(FacesCompositeELResolver.java:58)
	at org.apache.el.parser.AstIdentifier.getValue(AstIdentifier.java:45)
	at org.apache.el.parser.AstValue.getValue(AstValue.java:86)
	at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:186)
	at com.sun.faces.application.ValueBindingValueExpressionAdapter.getValue(ValueBindingValueExpressionAdapter.java:95)
	at com.icesoft.faces.component.tree.TreeRenderer.encodeBegin(TreeRenderer.java:142)
	at javax.faces.component.UIComponentBase.encodeBegin(UIComponentBase.java:809)
	at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:536)
	at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:543)
	at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:543)
	at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:543)
	at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:543)
	at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:519)
	at com.icesoft.faces.application.D2DViewHandler.renderView(D2DViewHandler.java:161)
	at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:108)
	at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:266)
	at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:159)
	at com.icesoft.faces.webapp.xmlhttp.PersistentFacesState.render(PersistentFacesState.java:152)
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:

import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.HttpServletRequest;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import static org.springframework.web.context.request.RequestContextHolder.*;

/**
 * This class is necessary to set the Spring context on ICEFaces server pushes.
 * 
 * @author felipeal
 *
 */
public class SpringICEFacesIntegrationPhaseListener implements PhaseListener {

  public void afterPhase(PhaseEvent event) {
    // do nothing
  }

  public void beforePhase(PhaseEvent event) {
    if ( getRequestAttributes() == null ) {
      final FacesContext context = event.getFacesContext();
      final HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
      final ServletRequestAttributes attributes = new ServletRequestAttributes(request);
      LocaleContextHolder.setLocale(request.getLocale());
      RequestContextHolder.setRequestAttributes(attributes);
    }
  }

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

  /**
    * This method must be explicitiy called by Managed Beans after they
    * rendered ICEFaces stuff.
    */ 
  public static void releaseContext() {
    if ( getRequestAttributes() != null ) {
      RequestContextHolder.setRequestAttributes(null);
      LocaleContextHolder.setLocale(null);
    }
  }

}
Then on your managed bean, clean up the context after ICEFaces rendered the page. For instance:
protected class AbstractManagedBean {

  private PersistentFacesState persistentFacesState = null;

  public AbstractManagedBean {
    persistentFacesState = PersistentFacesState.getInstance();
  }
  
  /**
   * Initiates server-push
   */
  protected void render() throws RenderingException {
      try {
        persistentFacesState.render();
      } finally {
        SpringICEFacesIntegrationPhaseListener.releaseContext();
      }
  }
}
And the final step, adding the listener to faces-config.xml:

<faces-config>
  <lifecycle>    
<phase-listener>SpringICEFacesIntegrationPhaseListener</phase-listener>
  </lifecycle>
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
  </application>
</faces-config>
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:

public class SpringICEFacesIntegrationPhaseListenerTest {
  
  private final SpringICEFacesIntegrationPhaseListener listener = new SpringICEFacesIntegrationPhaseListener();
  
  public void testBeforePhase() {
    // set mock context
  final PhaseEvent event = new PhaseEvent(context,PhaseId.RENDER_RESPONSE,lifecycle);
  assertNull( "context was already set", getRequestAttributes() );
    final PhaseEvent event = new PhaseEvent(context,PhaseId.RENDER_RESPONSE,lifecycle);
    assertNull( "context was already set", getRequestAttributes() );
    listener.beforePhase(event);
    assertNotNull( "listener did not set context", getRequestAttributes() );
  }

  public void testCalledOnce() {
    // set mock context
    assertNull( "context should be set before", getRequestAttributes() );
    final PhaseEvent event = new PhaseEvent(context,PhaseId.RENDER_RESPONSE,lifecycle);
    listener.beforePhase(event);
    // verify mocks to assert listener didn't call methods
  }
}
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?

April 2008
Sun Mon Tue Wed Thu Fri Sat
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30      


Search this blog:
  

Categories
Business
Community
Community: Java Enterprise
Community: Java Specification Requests
Community: Java Tools
Community: Mac Java Community
Deployment
Distributed
J2EE
J2SE
JavaOne
Linux
Open Source
Tools
Web Applications
Archives

March 2008
July 2007
June 2007
May 2007
February 2007
November 2006
July 2006
June 2006
March 2006
June 2005
January 2005
December 2004
October 2004
July 2004
March 2004
January 2004
November 2003
October 2003
September 2003

Recent Entries

Spring, ICEFaces, and the dreaded thread-bound request issue

JSP is not dead!

My suggestion for Servlet 3.0

Articles

Creating EL-Aware Taglibs Using XDoclet
Passing dynamic values to taglibs via the JSP expression language (EL) is convenient, but is hard on the taglib developer and is therefore little-supported. Felipe Leme shows how code generation might solve that problem. Jun. 18, 2004

Validating Custom Tags at Translation Time
While typical JSP taglibs are held to a set of well known rules, many developers aren't aware that new rules can be defined and enforced by the developer. Felipe Leme examines these underappreciated JSP features. Feb. 4, 2004

All articles by Felipe Leme »



Powered by
Movable Type 3.01D


 Feed java.net RSS Feeds