9 Replies Latest reply on Sep 10, 2009 10:02 AM by Jun Li

    get session context in session listener.

    Jun Li Newbie

      Hi there,


      I'm trying to get seam session context with Contexts.getSessionContext() in a HttpSessionListener that I created myself and defined in web.xml, but resulting null.


      As I understand it's probably a thread thing, as seam contexts are bound to ThreadLocal, so my question is, is there a way to retrive the session context in my HttpSessionListener?


      Actually, I found sometimes the listener is running within the same thread but still can't get the context, please help me understand this.


      Thanks.

        • 1. Re: get session context in session listener.
          Nikolay Elenkov Master

          Just use the session directly:


          HttpSessionEvent.getSession().get/setAttribute()
          

          • 2. Re: get session context in session listener.
            Jun Li Newbie

            Thanks for the reply. That's what I'm using at the moment, but that means I have to pass the httpsession around, which is not always applicable.

            • 3. Re: get session context in session listener.
              Nikolay Elenkov Master

              Why not applicable? If you are within a HttpSessionListener you are either in sessionCreated or sessionDestoryed, you always have access to the session. Isn't passing the Context you get from Contexts.getSessionContext() essentially the same thing? Or are you doing something special? Please provide more Context :)

              • 4. Re: get session context in session listener.
                Jun Li Newbie

                OK, what I'm doing is in sessionDestroyed, update a session record like this.



                     public void sessionDestroyed(HttpSessionEvent event) {
                           Object sessionId =  httpSession.getAttribute("session_id");          
                           Session session = em.find(Session.class, sessionId);
                           session.setEndDate(new Date());
                           em.merge(session)
                     }
                



                And session extends baseModel which used across the application to encapsulate some auditing stuff.



                public class Session extends BaseModel {
                    // some fields
                 }
                




                public abstract class BaseModel implements Serializable {
                    private String modifiedBy;
                    private Date modifiedOn;
                
                  @PreUpdate
                  private void auditForUpdate() {
                    this.modifiedOn = new Date();
                
                    // seam context is requried here
                    this.modifiedBy = Identity.instance().getCredentials().getUsername();  
                  }
                
                 }
                




                As you can see, when session object is updated in listener, the modifiedBy field will be set from BaseModel, that's where seam context is required to get the login user info.


                I'm not sure if this is something special, but there's no way I can get the user name set to modifiedBy field in this structure. What I had to do is to change session not extending baseModel, and set those fields in listener.


                But it would be much nicer if I can leave those auditing fields to baseModel, wouldn't it?




                • 5. Re: get session context in session listener.
                  Nikolay Elenkov Master

                  Allan Li wrote on Sep 10, 2009 06:03:


                  OK, what I'm doing is in sessionDestroyed, update a session record like this.

                  ...

                  public abstract class BaseModel implements Serializable {
                      private String modifiedBy;
                      private Date modifiedOn;
                  
                    @PreUpdate
                    private void auditForUpdate() {
                      this.modifiedOn = new Date();
                  
                      // seam context is requried here
                      this.modifiedBy = Identity.instance().getCredentials().getUsername();  
                    }
                  
                   }
                  


                  ...
                  But it would be much nicer if I can leave those auditing fields to baseModel, wouldn't it?



                  Well, I don't know how your application is wired but, coupling your model to Seam API's is not a very good idea, IMHO.
                  If the API changes (like it did in 2.1), you have to change your model classes. It is better to have the Seam related
                  stuff done from the outside, (i.e., in the listener). To set your modifiedOn and modifiedBy you could use a
                  Hibernate listener instead of PreUpdate, there is a thread about this somewhere here, if you decide to go that way.

                  • 6. Re: get session context in session listener.
                    Jun Li Newbie

                    To set your modifiedOn and modifiedBy you could use a Hibernate listener instead of PreUpdate

                    Did you mean hibernate interceptor?


                    I thought using PreUpdate annotation is a better approach as it's JPA standard, therefore, the model is not rely on the actually implementation.


                    The challenage here is actually where I can get the user info before updating my model.
                    You can't pass httpSession into hibernate interceptor, can you?


                    • 7. Re: get session context in session listener.
                      Nikolay Elenkov Master

                      Allan Li wrote on Sep 10, 2009 09:01:


                      To set your modifiedOn and modifiedBy you could use a Hibernate listener instead of PreUpdate

                      Did you mean hibernate interceptor?

                      I thought using PreUpdate annotation is a better approach as it's JPA standard, therefore, the model is not rely on the actually implementation.



                      Sorry, yes I meant Hibernate interceptor. If you want to stick with JPA, you can use entity listeners.



                      The challenage here is actually where I can get the user info before updating my model.
                      You can't pass httpSession into hibernate interceptor, can you?


                      Correct me if I am wrong, but it looks like you have two separate use cases:


                      1. update modifiedOn and modifiedBy fields when you update an entity from the UI: this will work fine with @PreUpdate, HB interceptor
                      or whatever, since you have access to the Seam contexts.


                      2. update modifiedOn and modifiedBy from your HttpSessionListener: only for one entity (Session?). This doesn't just work, because you
                      don't have direct access to the Seam contexts; you need to get the actual HttpSession and extract Identity from there.


                      1. will work whatever approach you choose, it is just a matter of where to put your auditing logic: in the entity or
                      in a separate class (interceptor, listener). For 2., you don't have much choice right now, you have to update your fields
                      in the HttpSessionListener. At least until JBSEAM-2257 is fixed. That should
                      allow you to listen for Seam events and you will have access to contexts in your observer.


                      This might also be helpful Handling repetitive fields in your db schema


                      Have fun.



                      • 8. Re: get session context in session listener.
                        Jun Li Newbie

                        For 2., you don't have much choice right now, you have to update your fields in the HttpSessionListener. At least until JBSEAM-2257 is fixed.

                        That's absoluately right.


                        Actually, I felt a bit upset that the sessionExpired event is still not implemented, it's fairly easy to do I think.


                        As for the use cases, I see updating modifiedOn and modifiedBy as auditing logic which is common for all entities in the application, that's why it's coded in the BaseModel.


                        But in the case of setting session end time on the session entity when httpSession ends, the auditing couldn't be done properly because of the seam context model (bound to threadLocal). I had to set the audit field in listener which was not intened as a use case.

                        • 9. Re: get session context in session listener.
                          Jun Li Newbie

                          Thanks for all the info you provided, Nikolay!