httpsessionlistener resolved my session persistence issue

I’ve moved from Resin-3.0 to Tomcat-5.5 for a while now. So far, it’s actually been easier to deploy and run my web applications. However, I started to see some NotSerializableExceptions during shutdowns, and subsequent startups. After some research, it became clear that I was inadvertently storing Spring-proxied items into http sessions. If they still existed during serialization of the current session, Tomcat would complain, being that Tomcat actually expects truly serializable items in its sessions – how dare they 🙂

I knew the item being placed in the http session held a reference to a spring-wrapped DAO (the item’s a data view helper). So, after some cups of coffee it finally came to me: have my custom listener defined in the web.xml, which currently only implements ServletContextListener, also implement HttpSessionListener. With that, I was able clear out the culprit on sessionDestroyed(…). I wish all my technical problems were this straight forward.

Update: Anjan, in response to your question, I’m embedding the web.xml declaration and the actual Listener code. Hope this helps.

web.xml listener declaration


   <!--    Our custom system initializing listener     -->
   <listener>
      <listener-class>com.some.company.SomeInitListener</listener-class>
   </listener>

Listener Implementations


public class SomeInitListener extends BosenInitListener {

	private static final Logger LOG = Logger.getLogger(SomeInitListener.class);

	@Override
	protected void customInitForServlet(ServletContextEvent event) {
		super.customInitForServlet(event);

		ServletContext servletContext = event.getServletContext();
		SomeResourceInitializer resourceInitializer = (SomeResourceInitializer) getBean(servletContext, "resourceInitializer");

		// Make default menus
		String menuConfig = servletContext.getInitParameter(AppConstants.MENU_CONFIG);
		if (null != menuConfig) {
                    ...
		} else {
			LOG.warn("Could not find a menu configuration.");
		}

		resourceInitializer.init();
	}
}

public abstract class BosenInitListener implements ServletContextListener, HttpSessionListener {

	private static final Logger LOG = Logger.getLogger(BosenInitListener.class);

	public final void contextInitialized(final ServletContextEvent event) {
		String servletContextName = event.getServletContext().getServletContextName();
		if (LOG.isInfoEnabled()) {
			LOG.info("Initializing [ " + servletContextName + " ]");
		}

		customInitForServlet(event);

		if (LOG.isInfoEnabled()) {
			LOG.info("Initialized [ " + servletContextName + " ]\n\n");
		}
	}

	public final void contextDestroyed(final ServletContextEvent event) {
		String servletContextName = event.getServletContext().getServletContextName();
		if (LOG.isInfoEnabled()) {
			LOG.info("Destroying [ " + servletContextName + "]");
		}

		customDestroyForServlet(event);

		if (LOG.isInfoEnabled()) {
			LOG.info("Destroyed [ " + servletContextName + "]\n\n");
		}
	}

	protected void customInitForServlet(final ServletContextEvent event) {
		ServletContext servletContext = event.getServletContext();
		String appContextName = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
		Object webCtxAttribute = servletContext.getAttribute(appContextName);
		if (null != webCtxAttribute) {
			if (webCtxAttribute instanceof Exception) {
				LOG.error(webCtxAttribute);
			}

		} else {
			throw new IllegalStateException("Could not read applicationContext.xml.");
		}
	}

	protected void customDestroyForServlet(final ServletContextEvent event) {
		//no-op
	}

	public final void sessionCreated(final HttpSessionEvent event) {
		String sessionId = event.getSession().getId();
		if (LOG.isDebugEnabled()) {
			LOG.debug("Initializing a new Session [" + sessionId + "]");
		}

		customInitForSession(event);

		if (LOG.isDebugEnabled()) {
			LOG.debug("Initialized a new Session [" + sessionId + "]");
		}
	}

	public final void sessionDestroyed(final HttpSessionEvent event) {
		String sessionId = event.getSession().getId();
		if (LOG.isDebugEnabled()) {
			LOG.debug("Destroying an existing Session [" + sessionId + "]");
		}

		customDestroyForSession(event);

		if (LOG.isDebugEnabled()) {
			LOG.debug("Destroyed an existing Session [" + sessionId + "]\n\n");
		}
	}

	protected void customInitForSession(final HttpSessionEvent event) {
		//no-op
	}

	protected void customDestroyForSession(final HttpSessionEvent event) {
		HttpSession session = event.getSession();
		session.removeValue(BosenConstants.SESSION_PAGINATED_SEARCH_RESULTS);
		session.removeAttribute(BosenConstants.SESSION_PAGINATED_SEARCH_RESULTS);
	}

	protected static ApplicationContext getApplicationContext(ServletContext servletContext) {
		String appContextName = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
		return (ApplicationContext) servletContext.getAttribute(appContextName);
	}

	protected static Object getBean(ServletContext servletContext, String name) {
		return getApplicationContext(servletContext).getBean(name);
	}

This entry was posted in Technical stuff. Bookmark the permalink.

2 Responses to httpsessionlistener resolved my session persistence issue

  1. anjan bacchu says:

    hi there,

    thanks for sharing with us.

    I am getting these errors some times as well and though that I must be having some non-serializable object in the session.

    “have my custom listener defined in the web.xml, which currently only implements ServletContextListener, also implement HttpSessionListener. ”
    Can you elaborate on that ? I’m not sure I understand exactly what steps you took.

    thank you,

    BR,
    ~A

  2. Jay says:

    @Anjan: Thanks for your question. I’ve updated the post with an answer.

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.