6 Replies Latest reply on Sep 6, 2010 3:03 AM by Adrian Mitev

    capturing session information after a session ends

    gebuh Newbie

      I'm trying to capture a user's start and end of a session and enter a timestamp and status in the database.  I'm using an application scoped component that implements HttpSessionBindingListener and is created from a session scoped component. I can capture the start of the session, but not the end.  It appears that when the session ends the entityManager no longer holds the component and generates a EntityManager is closed message or a context error if I use @Observer or LifeCycle.  Is there any way to use the entityManager to do this?


      this is where the code is blowing up:


      @Name("userStatsSession")
      @Scope(ScopeType.APPLICATION)
      public class UserStatsSession implements Serializable, HttpSessionBindingListener {
      ...
      public void valueUnbound(HttpSessionBindingEvent event) {
                System.out.println("in userStatsSession.valueUnbound, not in if statement");
                if(this.userstats.getUserId() != null){
      
                     System.out.println("in userStatsSession.valueUnbound, entityManager is " + this.entityManager);
                     userMon.stop();
                    sessionMon.stop();
                    this.userstats.setLoggedOn(new BigDecimal(0));
                    UserStats chkStats = this.entityManager.merge(this.userstats);// code go BOOM!!!
                    this.entityManager.flush();
                    System.out.println("userStatsSession.valueUnbound");
                    chkStats.printStats();
                }
      }
      ...
      }




      Error generated:



      13:11:50,622 INFO  [STDOUT] in userStatsSession.valueUnbound, entityManager is org.jboss.seam.persistence.EntityManagerProxy@841307
      13:11:50,638 WARN  [ContainerBase] Exception processing manager org.apache.catalina.session.StandardManager@c3ff07 background process
      java.lang.IllegalStateException: EntityManager is closed
           at org.hibernate.ejb.EntityManagerImpl.getSession(EntityManagerImpl.java:66)
           at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:235)
           at org.jboss.seam.persistence.EntityManagerProxy.merge(EntityManagerProxy.java:132)
           at com.raytheon.AtcotsEmployee.criteria.UserStatsSession.valueUnbound(UserStatsSession.java:153)
           at org.apache.catalina.session.StandardSession.removeAttributeInternal(StandardSession.java:1649)
           at org.apache.catalina.session.StandardSession.expire(StandardSession.java:756)
           at org.apache.catalina.session.StandardSession.isValid(StandardSession.java:592)
           at org.apache.catalina.session.ManagerBase.processExpires(ManagerBase.java:682)
           at org.apache.catalina.session.ManagerBase.backgroundProcess(ManagerBase.java:667)
           at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1327)
           at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1612)
           at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1621)
           at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1621)
           at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1601)
           at java.lang.Thread.run(Thread.java:619)







      I'm using Seam 2.20 with jboss 5.1



        • 1. Re: capturing session information after a session ends
          Neil Richardson Newbie

          Hi,


          How are you getting hold of your EntityManager? Are you using something like:


          @In
          private EntityManager entityManager;
          




          Instead of holding your entity manager as a field in your component (which is bad practice in an application scoped component because it's very difficult to provide synchronised access to it - a requirement because it's not thread-safe) you may find it better to just get hold of an entity manager when you need it inside the method using the Component API:




          public void valueUnbound(HttpSessionBindingEvent event) {
                    EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
                    System.out.println("in userStatsSession.valueUnbound, not in if statement");
                    if(this.userstats.getUserId() != null){
          
                         System.out.println("in userStatsSession.valueUnbound, entityManager is " + this.entityManager);
                         userMon.stop();
                        sessionMon.stop();
                        this.userstats.setLoggedOn(new BigDecimal(0));
                        UserStats chkStats = entityManager.merge(this.userstats);// code go BOOM!!!
                        entityManager.flush();
                        System.out.println("userStatsSession.valueUnbound");
                        chkStats.printStats();
                    }
          }
          



          Note that you need to remove the entityManager field from your class and just have a local entityManager variable in your method.

          • 2. Re: capturing session information after a session ends
            gebuh Newbie

            thanx for the reply and info about the entityManager.  I was creating a field for the entityManager, but used the Component method to create it in a separate method.
            When I remove the class field and create it in the method:



            public EntityManager getEntityManager() {
                      System.out.println("in userStatsSession.getEntityManager");
                      
                      EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
            
                      return entityManager;
                 }





            I get the context error:




            WARN  [ContainerBase] Exception processing manager org.apache.catalina.session.StandardManager@8189ca background process
            java.lang.IllegalStateException: No application context active
                 at org.jboss.seam.Component.forName(Component.java:1945)
                 at org.jboss.seam.Component.getInstance(Component.java:2005)
                 at org.jboss.seam.Component.getInstance(Component.java:1983)
                 at org.jboss.seam.Component.getInstance(Component.java:1977)
                 at org.jboss.seam.Component.getInstance(Component.java:1972)
                 at com.raytheon.AtcotsEmployee.criteria.UserStatsSession.getEntityManager(UserStatsSession.java:169)
                 at com.raytheon.AtcotsEmployee.criteria.UserStatsSession.valueUnbound(UserStatsSession.java:139)
                 at org.apache.catalina.session.StandardSession.removeAttributeInternal(StandardSession.java:1649)
                 at org.apache.catalina.session.StandardSession.expire(StandardSession.java:756)
                 at org.apache.catalina.session.StandardSession.isValid(StandardSession.java:592)
                 at org.apache.catalina.session.ManagerBase.processExpires(ManagerBase.java:682)
                 at org.apache.catalina.session.ManagerBase.backgroundProcess(ManagerBase.java:667)
                 at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1327)
                 at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1612)
                 at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1621)
                 at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1621)
                 at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1601)
                 at java.lang.Thread.run(Thread.java:619)
            



            I either get an entityManager closed or the context error no matter how I code this.  Could it be because this class is called by a session scoped component?






            Neil Richardson wrote on Aug 25, 2010 16:42:


            Hi,

            How are you getting hold of your EntityManager? Are you using something like:

            @In
            private EntityManager entityManager;
            




            Instead of holding your entity manager as a field in your component (which is bad practice in an application scoped component because it's very difficult to provide synchronised access to it - a requirement because it's not thread-safe) you may find it better to just get hold of an entity manager when you need it inside the method using the Component API:



            public void valueUnbound(HttpSessionBindingEvent event) {
                      EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
                      System.out.println("in userStatsSession.valueUnbound, not in if statement");
                      if(this.userstats.getUserId() != null){
            
                           System.out.println("in userStatsSession.valueUnbound, entityManager is " + this.entityManager);
                           userMon.stop();
                          sessionMon.stop();
                          this.userstats.setLoggedOn(new BigDecimal(0));
                          UserStats chkStats = entityManager.merge(this.userstats);// code go BOOM!!!
                          entityManager.flush();
                          System.out.println("userStatsSession.valueUnbound");
                          chkStats.printStats();
                      }
            }
            



            Note that you need to remove the entityManager field from your class and just have a local entityManager variable in your method.


            Click HELP for text formatting instructions. Then edit this text and check the preview.

            • 3. Re: capturing session information after a session ends
              Rocky S Master

              If these solutions are not working for you. I can give you an idea inside this your method, send an jms message(passing the user id param) or raise an custom event(passing the user id param). Inside your jms consumer or observer, try to commit the state.
              Also note that you could also pass more than 1 parameters as per your need.


              Hope this helps in some sense.

              • 4. Re: capturing session information after a session ends
                Neil Richardson Newbie

                Try


                Lifecycle.beginCall();
                EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
                
                // rest of method here
                
                Lifecycle.endCall();



                • 5. Re: capturing session information after a session ends
                  gebuh Newbie

                  just wanted to update, still not having any luck with this. Tried Lifecycle previously and again with the locally created entityManager and this thing still won't work.  How can it be so difficult to update a db table outside of direct Seam access?



                  Neil Richardson wrote on Aug 26, 2010 15:20:


                  Try

                  Lifecycle.beginCall();
                  EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
                  
                  // rest of method here
                  
                  Lifecycle.endCall();






                  • 6. Re: capturing session information after a session ends
                    Adrian Mitev Master

                    Try the regular way:


                    @PersistenceContext
                    private EntityManager entityManager;