Вывод из bean

Я хочу, чтобы мой сеанс был тайм-аутом через определенный промежуток времени. В web.xml я использовал код вроде:

<session-config>   
  <session-timeout>20</session-timeout>   
</session-config>   

где 20 - период ожидания в минутах, который работает правильно.

Что бы я хотел сделать, это сделать это программно, используя такой код внутри одного из моих beans, как показано ниже:

@ManagedBean(name="login")   
@SessionScoped  
public class MyLoginBean implements HttpSessionListener, Serializable {   

    // private variables etc.   

    HttpServletRequest request;   
    HttpSession session  = request.getSession();   

    // Constructor
    public MyLoginBean() {   
        session.setMaxInactiveInterval(1200);   
    }   

// The rest of the code   

}  

где время ожидания составляет 1200 секунд, т.е. 20 минут. К сожалению, при открытии браузера для просмотра приложения он выходит из строя с сообщением:

com.sun.faces.mgbean.ManagedBeanCreationException: Cant instantiate class: com.csharp.MyLoginBean. 

Далее следуют:

java.lang.NullPointerException 

Что я здесь делаю неправильно? Я знаю, что setMaxInactiveInterval() относится к определенному сеансу, который в этом случае является логином bean, а не всем, что указывает код в файле web.xml. У меня есть несколько beans, но выбор времени входа в систему bean является единственным, что имеет значение.

Я использую JSF 2.0 с Glassfish 3.1.1 и Eclipse Indigo, поэтому некоторые советы будут очень оценены.

Ответ 1

NullPointerException имеет чрезвычайно простую причину. Это одно из самых простых исключений. Чтобы узнать о причине произвольного исключения, просто посмотрите его javadoc. Все исключения Java имеют свои причины, объясненные в javadoc. Здесь выдержка javadoc NullPointerException:

Брошено, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  • Вызов метода экземпляра объекта null.
  • Доступ или изменение поля объекта null.
  • Взятие длины null, как будто это массив.
  • Доступ или изменение слотов null, как если бы это был массив.
  • Бросок null, как если бы это было значение Throwable.

Приложения должны бросать экземпляры этого класса, чтобы указать на другие незаконные действия нулевого объекта.

Ваша проблема вызвана точкой 1. Здесь

HttpServletRequest request;   
HttpSession session  = request.getSession();   

вы пытаетесь вызвать метод getSession() на null вместо конкретного экземпляра HttpServletRequest. Фактически, вы должны были получить HttpServletRequest через ExternalContext#getRequest() и назначить его request.

Однако у вас большие проблемы: вы абсолютно не должны улавливать текущий запрос сервлета в качестве свойства сеанса bean (который живет дольше, чем HTTP-запрос!). Вы должны получить его внутри локальной области потока (т.е. Полностью внутри конструктора или блока метода). Вы также не должны позволять вашему JSF bean реализовать HttpSessionListener. Это не имеет никакого смысла. У вас будет 2 экземпляра, один из которых будет создан в качестве слушателя контейнером, а другой - как управляемый bean JSF.

Просто так:

@ManagedBean(name="login")
@SessionScoped
public class MyLoginBean implements Serializable {

    public MyLoginBean() {
        HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession();
        session.setMaxInactiveInterval(1200);
    }

    // ...
}

Или, если вы используете JSF 2.1, используйте тот, который предоставляется ExternalContext:

FacesContext.getCurrentInstance().getExternalContext().setSessionMaxInactiveInterval(1200);