stateful session beans and clustering
fsotest Jan 12, 2011 9:40 AMI am testing the clustering features of JBoss AS 6.0 Final and I have a problem with stateful session bean (EJB) and clustering. I got a local stateful session bean which I want to use from a servlet and keep a reference to the session bean inside the http session. Ok the servlet looks up the stateful bean via JNDI and stores the returned proxy (the proxy returned from JNDI) into an attribute at the HttpSession. The next time the servlet is requested, it takes the proxy from the HttpSession and uses it. This works fine as long as the request doesn't switch server (another Jboss AS instance in the same cluster). If I switch node (due to a server crash) the servlet gets the proxy from the session (since session is replicated to between servers). But as soon as the servlet tries to use the proxy an exception is thrown (see below). It states that the object reference is not found. This makes since since the object reference was created at another server. But how can I overcome this problem. My question is "how do I use a stateful session beans from a shared object like a servlet and I want it to be session scoped"? Any comments are appreciated.
14:33:06,000 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/jb.tes.cluster.web].[dk.jyskebank.cluster.statefulsession.StatefulTestServlet]] Servlet.service() for servlet dk.jy
skebank.cluster.statefulsession.StatefulTestServlet threw exception: javax.ejb.EJBException: java.lang.RuntimeException: java.io.IOException
at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.handleExceptionInOurTx(CMTTxInterceptor.java:183) [:0.0.1]
at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:251) [:0.0.1]
at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.required(CMTTxInterceptor.java:349) [:0.0.1]
at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.invoke(CMTTxInterceptor.java:209) [:0.0.1]
at org.jboss.ejb3.tx2.aop.CMTTxInterceptorWrapper.invoke(CMTTxInterceptorWrapper.java:52) [:0.0.1]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:76) [:1.0.0.GA]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
at org.jboss.aspects.remoting.ReplicantsManagerInterceptor.invoke(ReplicantsManagerInterceptor.java:56) [:1.0.1.GA]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.tx.NullInterceptor.invoke(NullInterceptor.java:42) [:1.0.3]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.security.Ejb3AuthenticationInterceptorv2.invoke(Ejb3AuthenticationInterceptorv2.java:182) [:1.7.17]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:41) [:1.7.17]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.BlockContainerShutdownInterceptor.invoke(BlockContainerShutdownInterceptor.java:67) [:1.7.17]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.core.context.CurrentInvocationContextInterceptor.invoke(CurrentInvocationContextInterceptor.java:47) [:1.7.17]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
at org.jboss.aspects.currentinvocation.CurrentInvocationInterceptor.invoke(CurrentInvocationInterceptor.java:67) [:1.0.1]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.interceptor.EJB3TCCLInterceptor.invoke(EJB3TCCLInterceptor.java:86) [:1.7.17]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.session.SessionSpecContainer.invoke(SessionSpecContainer.java:323) [:1.7.17]
at org.jboss.ejb3.session.SessionSpecContainer.invoke(SessionSpecContainer.java:380) [:1.7.17]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_23]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [:1.6.0_23]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [:1.6.0_23]
at java.lang.reflect.Method.invoke(Method.java:597) [:1.6.0_23]
at org.jboss.ejb3.proxy.impl.handler.session.SessionLocalProxyInvocationHandler$LocalContainerInvocation.invokeTarget(SessionLocalProxyInvocationHandler.java:184) [:1.0.11]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:111) [jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.async.impl.interceptor.AsynchronousClientInterceptor.invoke(AsynchronousClientInterceptor.java:143) [:1.7.17]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.proxy.impl.handler.session.SessionLocalProxyInvocationHandler$LocalInvokableContextHandler.invoke(SessionLocalProxyInvocationHandler.java:159) [:1.0.11]
at $Proxy237.invoke(Unknown Source) at org.jboss.ejb3.proxy.impl.handler.session.SessionProxyInvocationHandlerBase.invoke(SessionProxyInvocationHandlerBase.java:185) [:1.0.11]
at $Proxy238.get(Unknown Source) at dk.jyskebank.cluster.statefulsession.StatefulTestServlet.doGet(StatefulTestServlet.java:64) [:]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:734) [:1.0.0.Final]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [:1.0.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:324) [:6.0.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.0.0.Final]
at org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:67) [:6.0.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:274) [:6.0.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.0.0.Final]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [:6.0.0.Final]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) [:6.0.0.Final]
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:181) [:6.0.0.Final]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:593) [:6.0.0.Final]
at org.jboss.web.tomcat.service.session.ClusteredSessionValve.handleRequest(ClusteredSessionValve.java:135) [:6.0.0.Final]
at org.jboss.web.tomcat.service.session.ClusteredSessionValve.invoke(ClusteredSessionValve.java:94) [:6.0.0.Final]
at org.jboss.web.tomcat.service.session.JvmRouteValve.invoke(JvmRouteValve.java:88) [:6.0.0.Final]
at org.jboss.web.tomcat.service.session.LockingValve.invoke(LockingValve.java:62) [:6.0.0.Final]
at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.event(CatalinaContext.java:285) [:1.1.0.Final]
at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.invoke(CatalinaContext.java:261) [:1.1.0.Final]
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:88) [:6.0.0.Final]
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:100) [:6.0.0.Final]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) [:6.0.0.Final]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [:6.0.0.Final]
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158) [:6.0.0.Final]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [:6.0.0.Final]
at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53) [:6.0.0.Final]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362) [:6.0.0.Final]
at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:504) [:6.0.0.Final]
at org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:437) [:6.0.0.Final]
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951) [:6.0.0.Final]
at java.lang.Thread.run(Thread.java:662) [:1.6.0_23]
Caused by: java.lang.RuntimeException: java.io.IOException
at org.jboss.ejb3.stateful.StatefulBeanContext.extractBeanAndInterceptors(StatefulBeanContext.java:1011) [:1.7.17]
at org.jboss.ejb3.stateful.StatefulBeanContext.postReplicate(StatefulBeanContext.java:689) [:1.7.17]
at org.jboss.ejb3.cache.infinispan.InfinispanStatefulCache.get(InfinispanStatefulCache.java:409) [:1.0.0-alpha-4]
at org.jboss.ejb3.stateful.StatefulInstanceAssociationInterceptor.invoke(StatefulInstanceAssociationInterceptor.java:50) [:1.7.17]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.core.context.SessionInvocationContextAdapter.proceed(SessionInvocationContextAdapter.java:95) [:1.7.17]
at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:247) [:0.0.1]
... 66 more
Caused by: java.io.IOException
at org.jboss.serial.persister.RegularObjectPersister.readSlotWithMethod(RegularObjectPersister.java:107) [:6.0.0.Final]
at org.jboss.serial.persister.RegularObjectPersister.defaultRead(RegularObjectPersister.java:269) [:6.0.0.Final]
at org.jboss.serial.persister.RegularObjectPersister.readData(RegularObjectPersister.java:241) [:6.0.0.Final]
at org.jboss.serial.objectmetamodel.ObjectDescriptorFactory.readObjectDescriptionFromStreaming(ObjectDescriptorFactory.java:412) [:6.0.0.Final]
at org.jboss.serial.objectmetamodel.ObjectDescriptorFactory.objectFromDescription(ObjectDescriptorFactory.java:82) [:6.0.0.Final]
at org.jboss.serial.objectmetamodel.DataContainer$DataContainerDirectInput.readObject(DataContainer.java:643) [:6.0.0.Final]
at org.jboss.serial.persister.ArrayPersister.readObjectArray(ArrayPersister.java:196) [:6.0.0.Final]
at org.jboss.serial.persister.ArrayPersister.readData(ArrayPersister.java:172) [:6.0.0.Final]
at org.jboss.serial.objectmetamodel.ObjectDescriptorFactory.readObjectDescriptionFromStreaming(ObjectDescriptorFactory.java:412) [:6.0.0.Final]
at org.jboss.serial.objectmetamodel.ObjectDescriptorFactory.objectFromDescription(ObjectDescriptorFactory.java:82) [:6.0.0.Final]
at org.jboss.serial.objectmetamodel.DataContainer$DataContainerDirectInput.readObject(DataContainer.java:643) [:6.0.0.Final]
at org.jboss.serial.io.JBossObjectInputStream.readObjectOverride(JBossObjectInputStream.java:163) [:6.0.0.Final]
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:344) [:1.6.0_23]
at org.jboss.serial.io.MarshalledObject.get(MarshalledObject.java:68) [:6.0.0.Final]
at org.jboss.ejb3.stateful.StatefulBeanContext.extractBeanAndInterceptors(StatefulBeanContext.java:982) [:1.7.17]
... 72 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_23]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [:1.6.0_23]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [:1.6.0_23]
at java.lang.reflect.Method.invoke(Method.java:597) [:1.6.0_23]
at org.jboss.serial.persister.RegularObjectPersister.readSlotWithMethod(RegularObjectPersister.java:103) [:6.0.0.Final]
... 86 more
Caused by: org.jboss.serial.exception.SerializationException: Object reference 9 was not found
at org.jboss.serial.objectmetamodel.ObjectDescriptorFactory.objectFromDescription(ObjectDescriptorFactory.java:118) [:6.0.0.Final]
at org.jboss.serial.objectmetamodel.DataContainer$DataContainerDirectInput.readObject(DataContainer.java:643) [:6.0.0.Final]
at org.jboss.serial.persister.RegularObjectPersister.readSlotWithFields(RegularObjectPersister.java:353) [:6.0.0.Final]
at org.jboss.serial.persister.RegularObjectPersister.defaultRead(RegularObjectPersister.java:273) [:6.0.0.Final]
at org.jboss.serial.persister.RegularObjectPersister.readData(RegularObjectPersister.java:241) [:6.0.0.Final]
at org.jboss.serial.objectmetamodel.ObjectDescriptorFactory.readObjectDescriptionFromStreaming(ObjectDescriptorFactory.java:412) [:6.0.0.Final]
at org.jboss.serial.objectmetamodel.ObjectDescriptorFactory.objectFromDescription(ObjectDescriptorFactory.java:82) [:6.0.0.Final]
at org.jboss.serial.objectmetamodel.DataContainer$DataContainerDirectInput.readObject(DataContainer.java:643) [:6.0.0.Final]
at org.jboss.serial.persister.ObjectInputStreamProxy.readObjectOverride(ObjectInputStreamProxy.java:68) [:6.0.0.Final]
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:344) [:1.6.0_23]
at java.util.ArrayList.readObject(ArrayList.java:593) [:1.6.0_23]
... 91 more
The session bean looks like this:
@Local
public interface StatefulTest extends Serializable {
int get();
@Remove
void reset();
@Init
void initialize(int value);
}
@Stateful
@Clustered()
public class StatefulTestBean implements Serializable, StatefulTest {
private static Logger logger = LoggerFactory.getLogger(StatefulTestBean.class);
private int balance = 0;
public StatefulTestBean() {
}
@Init
@Override
public void initialize(int value) {
balance = value;
}
@Override
public int get() {
return balance;
}
@Override
@Remove
public void reset() {
logger.info("reset");
}
}
The servlet looks like this:
@WebServlet("/stateful")
@ServletSecurity(@HttpConstraint(rolesAllowed = {"jbwindowsusers"}))
@DeclareRoles("jbwindowsusers")
public class StatefulTestServlet extends HttpServlet {
private static final String STATEFULTEST_JNDI_PATH = "jb.tes.cluster/StatefulTestBean/local";
private static final String SESSION_ATTRIBUTE_NAME = "statefultest";
private static final Logger logger = LoggerFactory.getLogger(StatefulTestBean.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss");
public StatefulTestServlet() {
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
String action = request.getParameter("action");
PrintWriter out = null;
try {
out = response.getWriter();
out.println("Invoked at '" + System.getProperty("jboss.jvmRoute") + "' by user '" + request.getUserPrincipal().getName() + "' with session id '" + request.getSession().getId() + "' at '" + dateFormat.format(new Date()) + "'");
StatefulTest bean = getBean(request.getSession());
if ("init".equalsIgnoreCase(action)) {
String initData = request.getParameter("data");
int initializationValue = 17;
try {
initializationValue = Integer.parseInt(initData);
} catch(NumberFormatException e) {
}
bean.initialize(initializationValue);
out.println("Initialize to : '" + initializationValue + "' for " + bean);
} else if ("remove".equalsIgnoreCase(action)) {
request.getSession().invalidate();
out.println("session has been invalidated");
} else { // get action is the default action
out.println("balance : '" + bean.get() + "'");
}
} catch (IOException e) {
throw new ServletException("failed to get an output stream", e);
} finally {
if (out != null) {
out.close();
}
}
}
private StatefulTest getBean(HttpSession session) {
try {
StatefulTest bean = (StatefulTest) session.getAttribute(SESSION_ATTRIBUTE_NAME);
if (bean == null) {
// lookup bean in JNDI
InitialContext ic = new InitialContext();
bean = (StatefulTest) ic.lookup(STATEFULTEST_JNDI_PATH);
logger.info("Found bean '" + bean + "' of type '" + bean.getClass().getName() + "'");
// add to session
session.setAttribute(SESSION_ATTRIBUTE_NAME, bean);
}
return bean;
} catch (NamingException e) {
throw new RuntimeException("Failed to retrieve stateful session bean", e);}
}