Im currently using :
- Apache tomcat 7
- JBoss Weld servlet 1.0.1-Final
- empty beans.xml
<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
in the web.xml
I'm currently testing a simple counter @ConversationScoped bean, and the intention is, after beginning the conversation scope, to keep incrementing the counter whenever the button is clicked ..
But it seems that after submit, the bean will always be recreated, even after i've begin the conversation in the 1st place.
Here's my simple bean :
package user.ui;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Inject;
import javax.inject.Named;
@Named
@ConversationScoped
public class CounterBean implements Serializable {
@Inject
private Conversation conversation;
@PostConstruct
public void init() {
System.out.println("beginning conversation : " + this.conversation);
this.conversation.begin();
}
private int counter;
public int getCounter() {
return counter;
}
public void setCounter(int counter) {
this.counter = counter;
}
public void increment() {
this.counter++;
}
}
Here's my simple jsf view :
<ui:composition template="/template/masterlayout.xhtml">
<ui:define name="windowTitle">Test Conversation Scope</ui:define>
<ui:define name="heading">Test Conversation Scope</ui:define>
<ui:define name="content">
<h:form>
<p:messages id="messages" globalOnly="true" />
<p:panel header="Test Conversation Scope">
<h:outputText value="counter : " /> #{counterBean.counter}
</p:panel>
<h:commandButton value="Submit Data to Server" action="#{counterBean.increment}" />
</h:form>
</ui:define>
</ui:composition>
Here's the log file for the 1st access :
INFO: Server startup in 12055 ms
beginning conversation : ID: 1, transient: true, timeout: 600000ms
And after the view is displayed, i clicked on the button, and there goes the exception throwing with this log in catalina.out :
beginning conversation : ID: 2, transient: true, timeout: 600000ms
unhandled exception : org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type @ConversationScoped
cause exception : org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type @ConversationScoped, cause exception is BE : false
Here's the exception trace from tomcat log :
Apr 4, 2011 3:56:27 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [Faces Servlet] in context with path [/primebert] threw exception [WELD-001303 No active contexts for scope type @ConversationScoped] with root cause
org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type @ConversationScoped
at org.jboss.weld.conversation.ConversationImpl.checkConversationActive(ConversationImpl.java:79)
at org.jboss.weld.conversation.ConversationImpl.isTransient(ConversationImpl.java:234)
at org.jboss.weld.conversation.ConversationImpl.toString(ConversationImpl.java:199)
at java.text.MessageFormat.subformat(MessageFormat.java:1246)
at java.text.MessageFormat.format(MessageFormat.java:836)
at java.text.Format.format(Format.java:140)
at java.text.MessageFormat.format(MessageFormat.java:812)
at ch.qos.cal10n.MessageConveyor.getMessage(MessageConveyor.java:89)
at org.jboss.weld.logging.WeldMessageConveyor.getMessage(WeldMessageConveyor.java:78)
at org.slf4j.cal10n.LocLogger.debug(LocLogger.java:95)
at org.jboss.weld.conversation.ConversationImpl.switchTo(ConversationImpl.java:190)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:304)
at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:54)
at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:163)
at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:298)
at org.jboss.weld.bean.proxy.ClientProxyMethodHandler.invoke(ClientProxyMethodHandler.java:113)
at org.jboss.weld.util.CleanableMethodHandler.invoke(CleanableMethodHandler.java:43)
at org.jboss.weld.conversation.ConversationImpl_$$_javassist_2.switchTo(ConversationImpl_$$_javassist_2.java)
at org.jboss.weld.conversation.AbstractConversationManager.beginOrRestoreConversation(AbstractConversationManager.java:137)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:304)
at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:54)
at org.jboss.weld.util.reflection.SecureRe开发者_如何学CflectionAccess.runAsInvocation(SecureReflectionAccess.java:163)
at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:298)
at org.jboss.weld.bean.proxy.ClientProxyMethodHandler.invoke(ClientProxyMethodHandler.java:113)
at org.jboss.weld.util.CleanableMethodHandler.invoke(CleanableMethodHandler.java:43)
at org.jboss.weld.conversation.ServletConversationManager_$$_javassist_0.beginOrRestoreConversation(ServletConversationManager_$$_javassist_0.java)
at org.jboss.weld.jsf.WeldPhaseListener.initiateSessionAndConversation(WeldPhaseListener.java:171)
at org.jboss.weld.jsf.WeldPhaseListener.beforeRestoreView(WeldPhaseListener.java:118)
at org.jboss.weld.jsf.WeldPhaseListener.beforePhase(WeldPhaseListener.java:87)
at com.sun.faces.lifecycle.Phase.handleBeforePhase(Phase.java:228)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:99)
at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:111)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:306)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:541)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:383)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:288)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Any ideas what went wrong ?
Thank you !
To keep track of the long-running conversation Weld inserts the cid
parameter in the action
method of the HTML form.
In your case you start the long-running conversation in the PostConstruct
method of the counterBean
. But the counterBean
gets referenced first inside the h:form
, so by the time counterBean
gets initialized the h:form
's header was already rendered. You need to start the conversation earlier.
I'm not sure what's the best way to do that. Probably like that:
<f:metadata>
<f:event type="preRenderView" listener="#{someBean.init}"/>
</f:metadata>
You could start the conversation on GET request only:
public void init() {
if (!FacesContext.getCurrentInstance().isPostback()) {
conversation.begin();
}
}
JSF 2.2 has a <f:viewAction>
tag (analogous to Seam page actions), that could be used to accomplish the same thing.
Alternatively you can just place this EL expression above the form:
#{javax.enterprise.context.conversation.begin()}
But then you have to be careful not to re-render this expression again.
As a side note, a conversation is often started on some JSF action, such as a button click. One needs to keep in mind, that for a proper conversation propagation forms need to be re-rendered.
From a CDI point of view, your code should work (it actually works on a JBoss AS 6). What seems to happen is that the conversation isn't propagated between two requests, but that should be implicit when using JSF form submits. I assume your setup is wrong and Tomcat isn't configured as it should be.
As a first step, try to propagate the conversation id manually, as described here.
We've seen the same so work around it we are performing a redirect back to the page as soon as we start a conversation. We know which parts of our app need conversations based on form id prefix, so can do this in an early phase listener. After Restore View works well. I'm having trouble performing redirects from Before Restore View which would be more ideal.
I've ended up using HttpServletRequest from FacesContext.getExternalContext().getRequest() which can give the full URL to redirect to. I do break it down in code and recombine it - the structure of our code and a reusable class to contain the concept of a form and parameters. The sendRedirect with exception handling removed is
ExternalContext external = faces.getExternalContext();
String baseUrl = external.getRequestContextPath() + m_formId;
String target = external.encodeRedirectURL(baseUrl, m_requestParameters);
external.redirect(target);
精彩评论