title: JSF Session Expired Phase Listener If Browser Is Closed
body: <p>In cases where the user has closed the browser and walked away, I want to log when the session times out. For example as a system induced log out as opposed to user request (I already have working and tested code to log a user requested logout). </p>
  
  <p>Since the user isn't actively submitting requests (especially if it is just a matter of the now unused session timing out on the server) I don't think a filter is possible. Can this be done with a phase listener? If so can you provide some insight or a skeleton, or at least point me in the right direction on how this might be done. </p>
  
  <p>My understanding is that the session on the server is still active until it times out or some other mechanism invalidates it. I am assuming therefore that a phase listener will also be able to tell if as part of your login method, you kill any existing session prior to the user logging in again with a fresh view, other machine, etc.</p>
  
  <p>I am OK with research, but would like to at least start while pointed in the right direction. :)</p>
  
  <p>On a second note: Is it possible to differentiate between a session time out and a view expired?<br /><br /></p>
  
  <hr>
  
  <p>Thought I'd post the solution I ended up with based on the suggestions:</p>
  
  <pre><code>public class ElsSoulardSessionListener implements HttpSessionListener {
  
      @EJB
      private SessionLogger sessionLogger = new SessionLogger();
      private SessionLogDTO sessionData = new SessionLogDTO();
      private ElsDateTimeFunctions ts = new ElsDateTimeFunctions();
      private static final Logger logger = Logger.getLogger(ElsSoulardSessionListener.class.getSimpleName());
  
      @Override
      public void sessionCreated(HttpSessionEvent se) {
          // Nothing to do yet
      }
  
      @Override
      public void sessionDestroyed(HttpSessionEvent se) {
          logger.log(Level.FINE, "SESSION DESTROYED LISTENER");
  
          HttpSession session = se.getSession();
          finalizeUserSessionLog(session);
      }
  
      /**
       * Utility method to finalize user's session log entry. Returns 
       * early if the session log isn't found or more than one is returned.
       * @param session 
       */
      private void finalizeUserSessionLog(HttpSession session) {
  
          String sessionId = session.getId();
          LogoutReasonType logoutReason = (LogoutReasonType) session.getAttribute("logoutreason");
  
          if (logoutReason == null) {
              logoutReason = LogoutReasonType.SESSION_TIMEOUT;
          }
  
          try {
              sessionData = sessionLogger.findBySessionId(sessionId);
          } catch (NonexistentEntityException | UnexpectedResultSetSizeException ex) {
              logger.log(Level.WARNING, " sessionDestroyed ", ex);
              return;
          }
  
          Calendar now = ts.getUtcDateTimeAsCalendar();
          sessionData.setLogoutTimestamp(now);
          sessionData.setLogoutReason(logoutReason);
          sessionLogger.update(sessionData);
  
      }
  }
  </code></pre>