Вызывать метод непосредственно перед истечением сеанса

У моего webapp есть пользователи, которые заходят в систему. Существует тайм-аут. До истечения срока действия сессии я хотел бы выполнить метод для очистки некоторых блокировок.

Я реализовал sessionListener, но после того, как я дошел до public void sessionDestroyed(HttpSessionEvent event), сеанс уже исчез, и мне нужны некоторые данные из него, поэтому я хотел бы выполнить метод (который нуждается в сеансе и доступ к нему FacesConfig.getCurrentInstance()) до истечения срока действия сеанса.

Как я могу это сделать? Есть идеи? Это мой прослушиватель сеансов:

public class MySessionListener implements HttpSessionListener {

    private static final Logger log = LoggerFactory.getLogger(MySessionListener.class);

    public MySessionListener() {

    }

    public void sessionCreated(HttpSessionEvent event) {
        log.debug("Current Session created : "
              + event.getSession().getId()+ " at "+ new Date());
    }

    public void sessionDestroyed(HttpSessionEvent event) {
        // get the destroying session...

        HttpSession session = event.getSession();
        prepareLogoutInfoAndLogoutActiveUser(session);

        log.debug("Current Session destroyed :"
              + session.getId()+ " Logging out user...");

        /*
         * nobody can reach user data after this point because 
         * session is invalidated already.
         * So, get the user data from session and save its 
         * logout information before losing it.
         * User redirection to the timeout page will be 
         * handled by the SessionTimeoutFilter.
         */

         // Only if needed
    }

    /**
     * Clean your logout operations.
     */
    public void prepareLogoutInfoAndLogoutActiveUser(HttpSession httpSession) {
        UserBean user = FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{user}", UserBean.class);
        LockBean lock = FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{lock}", LockBean.class);
        lock.unlock(user.getUsername());
        log.info("Unlocked examination for user: "+user.getUsername());
    }
}

Но я получаю NullPointerException в FacesContext.getCurrentInstance().getApplication(), потому что либо getCurrentInstance имеет значение null, либо getApplication возвращает null

Ответы

Ответ 1

Вы можете добиться этого, выполнив HttpSessionBindingListener, вам нужно зарегистрировать сеанс, который содержит блокировку, вызывая registerSession (строка "sessionBindingListener" не может быть изменена). Контейнер обратится к методу valueUnbound() после истечения времени ожидания сеанса и до, когда сеанс будет уничтожен.

public class ObjectLock implements Serializable,HttpSessionBindingListener {
    public void valueBound(HttpSessionBindingEvent event) {
        log.info("valueBound:" + event.getName() + " session:" + event.getSession().getId() );

    }

    public void registerSession() {
        FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put( "sessionBindingListener", this  );
        log.info( "registered sessionBindingListener"  );
    }

    public void valueUnbound(HttpSessionBindingEvent event) {
        log.info("valueUnBound:" + event.getName() + " session:" + event.getSession().getId() );
               // add you unlock code here:
        clearLocksForSession( event.getSession().getId() );
    }
}

Ответ 2

Еще одно элегантное решение:

Просто добавьте аннотацию @PreDestroy к сеансу Bean! Если сеанс будет уничтожен, он предварительно вызовет PreDestroy на всех SessionBeans, там вы можете выйти и все!

Хотя в настоящее время это не работает со многими ApplicationServers, кажется, это нечеткий сегмент Спецификации JSF. Таким образом, переход с принятым ответом (HttpSessionBindingListener) будет необходим, пока @PreDestroy не будет работать на всех серверах.