Environment:
Because of the number of requests I am expecting, I want to implement async request on top of the FacesServlet, and did this:
public class AsyncFacesServlet extends HttpServlet {
private static final long serialVersionUID = 111966573758921845L;
private FacesServlet delegate;
@Inject
private BeanManager beanManager;
@Inject
private ServletContext servletContext;
@Override
public void init(final ServletConfig servletConfig) throws ServletException {
delegate = new FacesServlet();
delegate.init(servletConfig);
}
@Override
public void destroy() {
delegate.destroy();
}
@Override
public ServletConfig getServletConfig() {
return delegate.getServletConfig();
}
@Override
public String getServletInfo() {
return delegate.getServletInfo();
}
@Override
public void service(final ServletRequest request, final ServletResponse response) throws ServletException, IOException {
final AsyncContext asyncContext = request.isAsyncStarted()
? request.getAsyncContext() : request.startAsync(request, response);
final Runnable runnable = () -> {
try {
delegate.service(request, response);
} catch (final IOException | ServletException ex) {
throw Throwables.propagate(ex);
}
};
asyncContext.start(runnable);
}
}
And then updated my web.xml as:
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>com.mycompany.service.faces.AsyncFacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
When I deploy, I get the following exceptions, which indicates that Weld was not correctly initialized inside the asynccontext.
SEVERE [javax.enterprise.resource.webcontainer.jsf.application] (default task-38) Error Rendering View[/login.xhtml]: org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped
at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:708)
at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.get(ContextualInstanceStrategy.java:95)
at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.get(ContextualInstanceStrategy.java:178)
at org.jboss.weld.bean.ContextualInstance.get(ContextualInstance.java:50)
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:761)
at org.jboss.weld.el.AbstractWeldELResolver.lookup(AbstractWeldELResolver.java:107)
at org.jboss.weld.el.AbstractWeldELResolver.getValue(AbstractWeldELResolver.java:90)
at org.jboss.as.jsf.injection.weld.ForwardingELResolver.getValue(ForwardingELResolver.java:46)
at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:188)
at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
at com.sun.el.parser.AstIdentifier.getValue(AstIdentifier.java:116)
at com.sun.el.parser.AstValue.getBase(AstValue.java:151)
at com.sun.el.parser.AstValue.getValue(AstValue.java:200)
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:226)
at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:182)
at javax.faces.component.UIOutput.getValue(UIOutput.java:174)
at javax.faces.component.UIInput.getValue(UIInput.java:291)
at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getValue(HtmlBasicInputRenderer.java:205)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getCurrentValue(HtmlBasicRenderer.java:355)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeEnd(HtmlBasicRenderer.java:164)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:920)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1863)
at javax.faces.render.Renderer.encodeChildren(Renderer.java:176)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:890)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1856)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:458)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:134)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:659)
at com.mycompany.service.faces.servlet.AsyncFacesServlet.lambda$service$17(AsyncFacesServlet.java:61)
Whats happening is that, Weld is not properly initialized or context is not propagated to the async context execution.
How can I be able to propagate or recreate the weld context upon async-request call?
I'll prefix my answer with a note that there is an open CDI spec issue to make async behavior more portable, Specify that web scoped (request, session, application) beans are injectable in async servlets
What you can do, in a Weld specific way, is start the context. Apache DeltaSpike has some utilities that will make this container in-specific as well, http://deltaspike.apache.org/documentation/container-control.html#ContextControlUsage
If your runnable is a managed bean, you can use BoundRequestContext
in weld to start a request context for that thread. More here. The downside is that its a new context, not a bridged context.