Access and change property (s) of an application-controlled Bean from a session listener

I need to access an application-controlled bean to change certain properties from an HttpSessionListener.

I already used something like the following:

@Override public void sessionDestroyed(HttpSessionEvent se) { HttpSession session = se.getSession(); User user = userService.findBySessionId(session.getId()); ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); ApplicationScopedBean appBean = (ApplicationScopedBean) externalContext.getApplicationMap().get("appBean"); appBean.getConnectedUsers().remove(user); } 

externalContext = FacesContext.getCurrentInstance (). getExternalContext () throws a null pointer exception here, and even if it is not, I'm not sure if appBean may be available above.

Any ideas?

0
source share
1 answer

FacesContext is only available in the stream serving the HTTP request initiated by the web browser that called FacesServlet . During a session, destruction does not necessarily mean an HTTP request. Sessions are usually destroyed by the background thread controlled by the container. This does not trigger an HTTP request through FacesServlet . Therefore, you should not expect that FacesContext will always be present during the destroy session. Only when you call session.invalidate() inside a JSF managed bean is FacesContext available.

If your managed application is controlled by a bean, controlled by JSF @ManagedBean , then it’s good to know that JSF stores it under covers as a ServletContext attribute. ServletContext in turn, is available in the HttpSession#getServletContext() session listener.

So this should do:

 @Override public void sessionDestroyed(HttpSessionEvent se) { HttpSession session = se.getSession(); User user = userService.findBySessionId(session.getId()); ApplicationScopedBean appBean = (ApplicationScopedBean) session.getServletContext().getAttribute("appBean"); appBean.getConnectedUsers().remove(user); } 

If you use a container compatible with Servlet 3.0, the alternative is to simply let your application have a bean to implement the HttpSessionListener and register itself as such when building. This way you have a direct reference to the connectedUsers property.

 @ManagedBean @ApplicationScoped public class AppBean implements HttpSessionListener { public AppBean() { ServletContext context = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext(); context.addListener(this); } @Override public void sessionDestroyed(HttpSessionEvent se) { HttpSession session = se.getSession(); User user = userService.findBySessionId(session.getId()); connectedUsers.remove(user); } // ... } 

Again, another alternative is to save the User in the session area as a session-controlled bean. You can then use the @PreDestroy annotation to mark the method that should be called when the session is destroyed.

 @ManagedBean @SessionScoped public class User { @ManagedProperty("#{appBean}") private AppBean appBean; @PreDestroy public void destroy() { appBean.getConnectedUsers().remove(this); } // ... } 

This has the added benefit that User is in an EL context, available as #{user} .

+3
source

All Articles