I have a facelet that refreshes the browser window 30 seconds after session timeout e.g.
<a4j:region>
<h:form>
<a4j:poll id="poll" interval="#{(session.maxInactiveInterval + 30)*1000}" onbegin="window.document.location.href='/Patrac'"/>
</h:form>
</a4j:region>
The facelet, when reloaded, causes a method to be invoked on a SFSB e.g.
<ui:define name="title">PATRAC - #{workflowManager.currentWorkflow.screenTitle}</ui:define>
The SFSB is session scoped.
@SessionScoped
@Stateful
public class WorkflowManager {
...
public Workflow getCurrentWorkflow() { return currentWorkflow; }
@PreDestroy public void bye() { System.out.println("Destroying: "+ getClass().getName() +", ID = "+ getId()); }
}
85 percent of the time the screen is refreshed without incident:
15:56:44,951 INFO [stdout] (http-/127.0.0.1:8443-1) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -1906221148858801782
15:56:44,968 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/
15:58:01,343 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -3546919396833964128
15:58:15,288 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-3) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
15:58:15,319 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-4) NoCacheFilter.doFilter() URI: /Patrac/
15:58:15,349 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-3) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
15:58:15,389 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-4) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
15:59:45,771 INFO [stdout] (http-/127.0.0.1:8443-1) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -5655846827584878649
15:59:45,777 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
15:59:45,800 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-1) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
15:59:45,890 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:00:01,356 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = 4579100734353654546
16:01:01,363 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = 4317425328092070112
16:01:16,518 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-3) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:01:16,526 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-8) NoCacheFilter.doFilter() URI: /Patrac/
16:01:16,544 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-3) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
16:01:16,572 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-3) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:02:46,894 INFO [stdout] (http-/127.0.0.1:8443-1) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = 7360031599060690367
16:02:46,900 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:02:46,923 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-6) NoCacheFilter.doFilter() URI: /Patrac/
16:02:46,950 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-1) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
16:02:46,975 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:03:01,380 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -5741388414554084710
16:04:01,389 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -1149102875316717372
16:04:01,395 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -7198492156368620025
16:04:17,355 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-7) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:04:17,365 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-8) NoCacheFilter.doFilter() URI: /Patrac/
16:04:17,405 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-7) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
16:04:17,460 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-8) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:05:47,769 INFO [stdout] (http-/127.0.0.1:8443-7) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -8106288024707282506
16:05:47,773 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-7) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:05:47,808 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-6) NoCacheFilter.doFilter() URI: /Patrac/
16:05:47,809 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-7) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
16:05:47,856 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-7) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:06:01,409 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = 6737131848251158629
16:07:01,419 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -3248726216386741006
16:07:01,423 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -7798326820709515585
16:07:18,188 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-8) NoCacheFilter.doFilter() URI: /Patrac/
16:07:18,188 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:07:18,219 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-1) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
16:07:18,250 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
However, sometimes the following happens:
16:08:48,536 INFO [stdout] (http-/127.0.0.1:8443-7) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = 601708170643229812
16:08:48,537 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-7) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:08:48,540 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host]] (http-/127.0.0.1:8443-3) Exception sending request initialized lifecycle event to listener instance of class org.jboss.weld.servlet.WeldListener: javax.ejb.NoSuchEJBException: JBAS016055: EJB has been removed
at org.jboss.as.weld.ejb.StatefulSessionObjectReferenceImpl.getBusinessObject(StatefulSessionObjectReferenceImpl.java:124) [jboss-as-weld-7.2.0.Alpha1-SNAPSHOT.jar:7.2.0.Alpha1-SNAPSHOT]
at org.jboss.weld.bean.proxy.EnterpriseBeanProxyMethodHandler.invoke(EnterpriseBeanProxyMethodHandler.java:108) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at org.jboss.weld.bean.proxy.EnterpriseTargetBeanInstance.invoke(EnterpriseTargetBeanInstance.java:56) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:105) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at com.patrac.controller.statemachine.WorkflowManager$Proxy$_$$_Weld$Proxy$.toString(WorkflowManager$Proxy$_$$_Weld$Proxy$.java) [Patrac-ejb.jar:]
at java.lang.String.valueOf(String.java:2854) [rt.jar:1.7.0_07]
at java.lang.StringBuilder.append(StringBuilder.java:128) [rt.jar:1.7.0_07]
at org.jboss.weld.context.SerializableContextualInstanceImpl.toString(SerializableContextualInstanceImpl.java:60) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at java.lang.String.valueOf(String.java:2854) [rt.jar:1.7.0_07]
at java.lang.StringBuilder.append(StringBuilder.java:128) [rt.jar:1.7.0_07]
at org.jboss.weld.context.beanstore.AttributeBeanStore.attach(AttributeBeanStore.java:109) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at org.jboss.weld.context.AbstractBoundContext.activate(AbstractBoundContext.java:66) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at org.jboss.weld.servlet.WeldListener.requestInitialized(WeldListener.java:141) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) [jbossweb-7.0.17.Final.jar:]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.17.Final.jar:]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.17.Final.jar:]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:372) [jbossweb-7.0.17.Final.jar:]
at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:897) [jbossweb-7.0.17.Final.jar:]
at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:634) [jbossweb-7.0.17.Final.jar:]
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:2039) [jbossweb-7.0.17.Final.jar:]
at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_07]
16:08:48,561 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-7) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
The stack trace always appears in the browser window, so this happens after the browser makes a request when the session is timed out. It only happens when the request is received at nearly the same time that the SFSB is destroyed (within milliseconds). It never happens upon logout, although the 302 REDIRECT causes the brower to make a request only milliseconds after the SFSB is destroyed. It seems to be that not only is timing a factor but also a ViewExpiredException is thrown every time this happens.
It seems as though what's happening is that because the session times out but the EJB is not immediately removed, when the browser makes a request JBoss removes the EJB from the timed out session and then throws the exception that the EJB has been removed instead of first creating a new EJB and binding it to the new session.
How can I handle the NoSuchEJBException, or better yet to avoid it altogether?
The problem was solved by making the ViewExpiredExceptionHandler redirect to a facelet, viewExpired.xhtml.
Prior to this change, ViewExpiredExceptionHandler was redirecting to the root of the web app, /Patrac, and the following entry in web.xml was causing another redirect to index.xhtml:
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
Moreover, index.xhtml was configured to refresh to /Patrac, which would be redirected to /Patrac/index.xhtml, which would result in a ViewExpiredException, which would result in another redirect /Patrac, which would redirect to the welcome page, /Patrac/index.xhtml, all in rapid succession.
<a4j:poll id="poll" interval="#{(session.maxInactiveInterval + 30)*1000}" onbegin="window.document.location.href='/Patrac'"/>
Usually, there was no problem. But per the Servlet spec., sessions aren't necessarily destroyed exactly at the time specified in the deployment descriptor -- there is some variation. So, occasionally when when the browser refresh occurred within several milliseconds of the session being destroyed on the server side and JBoss hadn't finished cleaning up its state the NoSuchEJBExceptions were being thrown.
Changing the client side ajax poll/timeout in index.xhtml to the following and making sure that viewExpiredException.xhtml did not do any browser refresh/ ajax polling made the problem go away.
<a4j:poll id="poll" interval="#{(session.maxInactiveInterval + 30)*1000}" onbegin="window.document.location.href='/Patrac/viewExpired.xhtml"/>