I'm having trouble working out how to correctly handle automatic destruction of a session in JSF. Of course, at this time, the session gets invalidated by the container, resulting in @PreDestroy methods being called on the session scoped beans as well.
At PreDestroy of some session scoped beans, we're unregistering some listeners, like below:
@PreDestroy
public void destroy() {
getWS().removeLanguageChangeListener(this);
}
However, the getWS() method actually attempts to get a reference to another session scoped bean, but that fails, as FacesContext.getCurrentInstance() returns null.
The latter appears to be normal JSF behaviour, according to Ryan Lubke:
We're true to the specification here. I'm not sure it's safe to assume that the FacesContext will be available in all @PreDestroy cases. Consider session scoped beans. The session could be timed out by the container due to inactivity. The FacesContext cannot be available at that time.
Fine by me, but how should one then make sure all objects are correctly cleared? Is it bad practice to remove self as listener in PreDestroy?
Or would we only have to do this for request/view scoped beans, as they live less long than the session scope of WS (from getWS() ) ?
Note that I get this behaviour on Tomcat7, but I expect this problem happens on every container.
I think session beans are cleaned in a dedicated thread on a servlet container and thus are outside of FacesContext (which is associated with a JSF Request). You could use HttpSessionListener to overcome the problem and cleanup session resources. Something like:
@WebListener
public class LifetimeHttpSessionListener implements HttpSessionListener {
@Override
public void sessionCreated(final HttpSessionEvent e) {
// create some instance here and save it in HttpSession map
HttpSession session = e.getSession();
session.setAttribute("some_key", someInstance);
// or elsewhere in JSF context:
// FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("some_key", someInstance);
}
@Override
public void sessionDestroyed(final HttpSessionEvent e) {
// get resources and cleanup them here
HttpSession session = e.getSession();
Object someInstance = session.getAttribute("some_key");
}
}
Hope this can be helpful for you
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With