dognose
dognose

Reputation: 20889

JSF Catch Session Timeout

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

Answers (2)

user207421
user207421

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

BalusC
BalusC

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:

  1. Not sure why @PreDestroy isn't invoked. That'll be a CDI implementation specific issue. It's at least not related to JSF/Servlet.

  2. 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.

  3. 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

Related Questions