ServletSessionStore.java

/***************************************************************************
   Copyright 2012 Emily Estes

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
***************************************************************************/
package net.metanotion.web.servlets;


import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

import net.metanotion.util.Unknown;

import net.metanotion.web.RequestObject;
import net.metanotion.web.SessionStore;

/** This implementation of SessionStore uses the {@link javax.servlet.http.HttpSession} context of a
{@link javax.servlet.http.HttpServletRequest} to store the app provided session instance. If you are using this with
more traditional servlet code, you should be aware that the application session instance is stored under the attribute
name "cell" in the {@link javax.servlet.http.HttpSession} to avoid clobbering it with your own state. This is the only
code in the entire framework that uses the {@link javax.servlet.http.HttpSession}, so there will be no "clobbering"
issues with our framework. (Your libraries will call {@link net.metanotion.util.Unknown#lookupInterface} to find
"attributes" or "services" exposed by your application. Of course that exposes services by TYPE. If you want to expose
services by NAME have your app session provide an instance of {@link net.metanotion.scripting.ObjectServer} via
<code>lookupInterface</code>.) */
public final class ServletSessionStore implements SessionStore {
	private static final String cellName = "cell";
	/** We can only store {@link javax.servlet.http.HttpSessionBindingListener} instances in the
		session attributes, so this class exists to provide a minimal implementation to just hold
		our session instance. Also, the fact that our sessions are an app provided
		object that can be type checked versus string-indexed attributes that are
		not type checked and can suffer from unknown name collisions with other
		libraries is one example of the sort of the problems this framework's design
		was meant to solve. */
	private static final class Cell implements HttpSessionBindingListener {
		/** The application session instance/component. */
		public final Unknown session;
		/** Create a new instance to wrap our session object so we can store it in the {@link javax.servlet.http.HttpSession}.
			@param o The application session/component instance we're wrapping.
		*/
		public Cell(final Unknown o) { this.session = o; }

		// HttpSessionBindingListener methods
		@Override public void valueBound(final HttpSessionBindingEvent event) { }
		@Override public void valueUnbound(final HttpSessionBindingEvent event) { }
	}

	@Override public Unknown getSession(final RequestObject ro) {
		final ServletRequestObject sro = (ServletRequestObject) ro;
		final HttpSession session = sro.getServletRequest().getSession();
		if(session.isNew()) { return null; }
		final Cell cell = (Cell) session.getAttribute(cellName);
		if(cell == null) { return null; }
		return cell.session;
	}

	@Override public Unknown setSession(RequestObject ro, Unknown u) {
		final ServletRequestObject sro = (ServletRequestObject) ro;
		sro.getServletRequest().getSession().setAttribute(cellName, new Cell(u));
		return u;
	}
}