Reputation: 20889
Is there a possibility to "intercept" the Session timeout?
I tried the HttpSessionListener
, but as far as i can read, the Session is already destroyed, when the HttpSessionListener.sessionDestroyed()` Method is invoked. (So i have no chance to determine the user, owning the session that timed out)
Another Option would be a PhaseListener, checking if the Session is "new" in the restoreView-Phase.
However i need to perform some Actions "the second" the Session times out - not on any later refresh, and not on any future login.
(Background: Need to remove locks from certain objects, the user might have been working on when running into the timeout.)
Is there a way to achieve that?
Edit: Attempt 1: Using @PreDestroy on the SessionBeans in question:
@SessionScoped
@Named
public class SessionBean1 implements Serializable {
...
@PostConstruct
private void pconstruct(){
System.out.println("PostConstructing Session Bean 1");
}
@PreDestroy
public void destroy(){
System.out.println("PreDestroying Session Bean 1");
}
}
and
public class SessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
//nothing to do right here.
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("Session Listener says 'destroyed'.");
}
}
Expected Result: destroy() beeing caled when Session times out OR user logs out.
Result: Nothing of both is happening.
22:29:11,199 INFO [stdout] (http--0.0.0.0-8090-1) ---- Started RESTORE_VIEW 1 ----
22:29:11,208 INFO [stdout] (http--0.0.0.0-8090-1) ---- Started RENDER_RESPONSE 6 ----
22:29:11,890 INFO [stdout] (http--0.0.0.0-8090-1) PostConstructing Session Bean 1
22:29:11,898 INFO [stdout] (http--0.0.0.0-8090-1) -- Finished Request --
22:30:11,905 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Session Listener says 'destroyed'.
Attempt 2: Trying to intercept session timeout inside the SessionListener, which is obviously taking note of the timeout:
public class SessionListener implements HttpSessionListener {
@Inject
private MySession mySession;
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("Destroying Session of owner: " + mySession.getCurrentUser().getShortName());
}
}
expected result: Access to the Session bean still possible.
result: 'ContextNotActiveException':
22:38:57,948 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/test]] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Session event listener threw exception: org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type javax.enterprise.context.SessionScoped
at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:598) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:71) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:79) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at my.namespace.test$Proxy$_$$_WeldClientProxy.getCurrentUser(MySession$Proxy$_$$_WeldClientProxy.java) [classes:]
at my.namespace.listener.SessionListener.sessionDestroyed(SessionListener.java:16) [classes:]
at org.apache.catalina.session.StandardSession.expire(StandardSession.java:690) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.session.StandardSession.isValid(StandardSession.java:585) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.session.ManagerBase.processExpires(ManagerBase.java:390) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.session.ManagerBase.backgroundProcess(ManagerBase.java:375) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1316) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1601) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1590) [jbossweb-7.0.13.Final.jar:]
at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_33]
Attempt 3: Checking the Session Attrributes for anything to use:
public class SessionListener implements HttpSessionListener {
@Override
public void sessionDestroyed(HttpSessionEvent se) {
int i=0;
while (se.getSession().getAttributeNames().hasMoreElements()){
String name = se.getSession().getAttributeNames().nextElement();
System.out.println("Checking " + name);
Object value = se.getSession().getAttribute(name);
System.out.println("value was: " + value);
if (i++ == 20){
break;
}
}
}
@Override
public void sessionCreated(HttpSessionEvent se) {
// nothing to do right here.
}
}
expected result: List of available Attributes.
result: Infinite Loop:
22:47:48,025 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Checking org.jboss.weld.context.conversation.ConversationIdGenerator
22:47:48,025 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) value was: org.jboss.weld.context.conversation.ConversationIdGenerator@1edd87d
22:47:48,026 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Checking org.jboss.weld.context.conversation.ConversationIdGenerator
22:47:48,027 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) value was: org.jboss.weld.context.conversation.ConversationIdGenerator@1edd87d
22:47:48,028 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Checking org.jboss.weld.context.conversation.ConversationIdGenerator
22:47:48,029 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) value was: org.jboss.weld.context.conversation.ConversationIdGenerator@1edd87d
EDIT:
Finally i used the HttpSessionListener and created - beside all the Session Scoped beans - a manual entry in the SessionMap: FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("user_id", 5)
.
This value can be accessed in the SessionListener and allows me to close all locks for the given user.
Upvotes: 1
Views: 4411
Reputation: 310840
The way I do this is to make the UserBean itself an HttpSessionListener
. Then it still has all its own state, so it knows who it 'is', regardless of whether the session still has attributes when the callback is called or not.
Upvotes: 1
Reputation: 1108537
I tried the HttpSessionListener, but as far as i can read, the Session is already destroyed, when the HttpSessionListener.sessionDestroyed()` Method is invoked. (So i have no chance to determine the user, owning the session that timed out)
I'm not sure how that forms a problem. You have still the concrete HttpSession
instance at your hands via HttpSessionEvent
argument on which you can just invoke getAttribute()
method and like in order to check the logged-in user in case it's stored as a session attribute.
User user = (User) event.getSession().getAttribute("user");
// ...
Update: as per your failed attempts:
Not sure why @PreDestroy
isn't invoked. That'll be a CDI implementation specific issue. It's at least not related to JSF/Servlet.
You should not grab an injected @Named
instance. You should instead grab the concrete instance as session attribute directly. Use HttpSession#getAttribute()
on the concrete managed bean name.
You're recreating the iterator during every iteration. You should create it once and reuse it during every iteration. Put getAttributeNames()
outside the while
. This issue is not related to JSF/Servlet, just basic Java.
Upvotes: 1