Search code examples
javajsfjsf-2httpsessionservlet-listeners

Getting SessionScoped bean from HttpSessionListener?


Hey guys. I'm trying to get a session bean in a HttpSessionListener so that when the user logs out or the session expires I can delete some files that the user created in the application. I'm guessing the session bean doesn't exist because the session is destroyed. I was hoping to still delete these files some how. Thanks for the help.

   @WebListener
    public class SessionListener implements HttpSessionListener {

        @Override
        public void sessionCreated(HttpSessionEvent se) {
            HttpSession session = se.getSession();
            System.out.print(getTime() + " (session) Created:");
            System.out.println("ID=" + session.getId() + " MaxInactiveInterval="
                    + session.getMaxInactiveInterval());
        }

        @Override
        public void sessionDestroyed(HttpSessionEvent se) {
            HttpSession session = se.getSession();

            FacesContext context = FacesContext.getCurrentInstance();
            //UserSessionBean userSessionBean = (UserSessionBean) context.getApplication().evaluateExpressionGet(context, "#{userSessionBean}", UserSessionBean.class)
            UserSessionBean userSessionBean = (UserSessionBean) session.getAttribute("userSessionBean");

            System.out.println(session.getId());
            System.out.println("File size :" + userSessionBean.getFileList().size());

            for (File file : userSessionBean.getFileList()) {
                file.delete();
            }
        } 
    }

To BalusC: I'm back to the method you previously had in mind. Streaming the bytes to the user wasn't flexible in my application. I found that I needed to do a lot of things in ajax on the page that was not possible if I had to send a non ajax request to stream a file to be downloaded. This way the heavy lifting is done with an ajax call(generating the document) and the fast and easy work is can be done with a non ajax call.

   @ManagedBean(name = "userSessionBean")
@SessionScoped
public class UserSessionBean implements Serializable, HttpSessionBindingListener {

    final Logger logger = LoggerFactory.getLogger(UserSessionBean.class);
    @Inject
    private User currentUser;
    @EJB
    UserService userService;
    private List<File> fileList;

    public UserSessionBean() {

        fileList = new ArrayList<File>();
    }

    @PostConstruct
    public void onLoad() {

        Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
        String email = principal.getName();

        if (email != null) {
            currentUser = userService.findUserbyEmail(email);
        } else {

            logger.error("Couldn't find user information from login!");
        }
    }

    public User getCurrentUser() {
        return currentUser;
    }

    public void setCurrentUser(User currentUser) {
        this.currentUser = currentUser;
    }

    public List<File> getFileList() {
        return fileList;
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {

        logger.info("UserSession unbound");
        logger.info(String.valueOf(fileList.size()));
        for (File file : fileList) {
            logger.info(file.getName());
            file.delete();
        }
    }

    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        logger.info("UserSessionBean bound");
    }
}

Solution

  • This code should work fine. Note that the FacesContext isn't necessarily available there since there's not necessarily means of a HTTP request in the thread running at that point, but you already outcommented that. Are you sure that you was actually running the code as shown in the question? Clean, rebuild, redeploy, etc.

    An alternative is to let your UserSessionBean implement HttpSessionBindingListener and then do the job in the valueUnbound() method.

    @ManagedBean
    @SessionScoped
    public class UserSessionBean implements HttpSessionBindingListener {
    
        @Override
        public void valueUnbound(HttpSessionBindingEvent event) {
            for (File file : files) {
                file.delete();
            }
        }
    
        // ...
    }