alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*   
 *  Copyright 1999-2004 The Apache Sofware Foundation.
 *
 *  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 org.apache.tomcat.modules.session;

import java.io.Serializable;
import java.util.Enumeration;
import java.util.Hashtable;

import org.apache.tomcat.core.BaseInterceptor;
import org.apache.tomcat.core.Context;
import org.apache.tomcat.core.ContextManager;
import org.apache.tomcat.core.Request;
import org.apache.tomcat.core.ServerSession;
import org.apache.tomcat.core.TomcatException;
import org.apache.tomcat.util.ObjectSerializer;
import org.apache.tomcat.util.buf.TimeStamp;
import org.apache.tomcat.util.collections.SimplePool;


/**
 * A simple session store plugin. It will create, store and maintain
 * session objects using a simple in-memory pool.
 *
 * It must be inserted after SessionId, which does common
 * session stuff ( cookie, rewrite, etc)
 *
 * @author costin@eng.sun.com
 * @author hans@gefionsoftware.com
 * @author pfrieden@dChain.com
 * @author Shai Fultheim [shai@brm.com]
 */
public final class SimpleSessionStore  extends BaseInterceptor {
    int manager_note;
    int maxActiveSessions = -1;
    int size=16;
    int max=256;
    static final String SESSIONS_RELOAD = "tomcat.sessions.reload";
    
    public SimpleSessionStore() {
    }

    // -------------------- Configuration properties --------------------

    public void setMaxActiveSessions( int count ) {
	maxActiveSessions=count;
    }

    public void setInitialPool( int initial ) {
	size=initial;
    }

    public void setMaxPool( int max ) {
	this.max=max;
    }
    
    // -------------------- Tomcat request events --------------------
    public void engineInit( ContextManager cm ) throws TomcatException {
	// set-up a per/container note for StandardManager
	manager_note = cm.getNoteId( ContextManager.CONTAINER_NOTE,
				     "tomcat.standardManager");
    }

    
    public void copyContext(Request req, Context oldC, Context newC)
	throws TomcatException {
	contextInit(newC);
	ClassLoader oldLoader = oldC.getClassLoader();
	SimpleSessionManager sM = getManager( oldC );    
	SimpleSessionManager sMnew = getManager( newC );

	// remove all non-serializable objects from session
	Enumeration sessionEnum=sM.getSessions();
	while( sessionEnum.hasMoreElements() ) {
	    ServerSession session = (ServerSession)sessionEnum.nextElement();
	    ServerSession newS = sMnew.cloneSession(req, newC, 
						    session.getId().toString());
	    Enumeration e = session.getAttributeNames();
	    while( e.hasMoreElements() ) {
		String key = (String) e.nextElement();
		Object value = session.getAttribute(key);
		newS.setAttribute(key, value);
	    }
	}
	newC.getContainer().setNote(SESSIONS_RELOAD, req);
    }

    private void processSession(ServerSession session, 
				ClassLoader oldCL, ClassLoader newCL)
	throws TomcatException {

	Hashtable newSession=new Hashtable();
	Enumeration e = session.getAttributeNames();
	while( e.hasMoreElements() )   {
	    String key = (String) e.nextElement();
	    Object value = session.getAttribute(key);
	    if ( value instanceof Serializable ) {
		Object newValue =
		    ObjectSerializer.doSerialization( newCL,
						      value);
		newSession.put( key, newValue );
	    } 
	    else if( value.getClass().getClassLoader() != oldCL ) {
		// it's loaded by the parent loader, no need to reload
		newSession.put( key, value );
	    } 
	}
	// If saving back to the same session.
	// Remove all objects we know how to handle
	e=newSession.keys();
	while( e.hasMoreElements() )   {
	    String key = (String) e.nextElement();
	    session.removeAttribute(key);
	}

	if( debug > 0 ) log("Prepare for reloading, SUSPEND " + session );
	// If anyone can save the rest of the attributes or at least notify
	// the owner...
	session.setState( ServerSession.STATE_SUSPEND, null );
	    
	if( debug > 0 ) log("After reloading, RESTORED " + session );
	session.setState( ServerSession.STATE_RESTORED, null );

	/* now put back all attributes */
	e=newSession.keys();
	while(e.hasMoreElements() ) {
	    String key = (String) e.nextElement();
	    Object value=newSession.get(key );
	    session.setAttribute( key, value );
	}
    }

    public void reload( Request req, Context ctx ) throws TomcatException {
	ClassLoader newLoader = ctx.getClassLoader();
	ClassLoader oldLoader=(ClassLoader)ctx.getContainer().
	    getNote("oldLoader");
	SimpleSessionManager sM = getManager( ctx );    

	// remove all non-serializable objects from session
	Enumeration sessionEnum=sM.getSessions();
	while( sessionEnum.hasMoreElements() ) {
	    ServerSession session = (ServerSession)sessionEnum.nextElement();
	    processSession(session,  oldLoader, newLoader);
	}
    }

    /** The session store hook
     */
    public ServerSession findSession( Request request,
				      String sessionId, boolean create)
    {
	Context ctx=request.getContext();
	if( ctx==null ) return null;
	
	SimpleSessionManager sM = getManager( ctx );    
	
	ServerSession sess=sM.findSession( sessionId );
	if( sess!= null ) return sess;

	if( ! create ) return null; // not found, don't create

	if ((maxActiveSessions >= 0) &&
	    (sM.getSessionCount() >= maxActiveSessions)) {
	    log( "Too many sessions " + maxActiveSessions );
	    return null;
	}

	ServerSession newS=sM.getNewSession(request, ctx);
	if( newS==null ) {
	    log( "Create session failed " );
	    return null;
	}
	
	return newS;
    }

    //--------------------  Tomcat context events --------------------


    /** Init session management stuff for this context. 
     */
    public void contextInit(Context ctx) throws TomcatException {
	// Defaults !!
	SimpleSessionManager sm= getManager( ctx );

	if( sm == null ) {
	    sm=new SimpleSessionManager();
	    sm.setDebug( debug );
	    sm.setModule( this );
	    ctx.getContainer().setNote( manager_note, sm );
	}
	if(ctx.getContainer().getNote(SESSIONS_RELOAD) != null ) {
	    Request req = (Request)ctx.getContainer().getNote(SESSIONS_RELOAD);
	    reload(req, ctx);
	    // Dump for GC.
	    ctx.getContainer().setNote(SESSIONS_RELOAD,null);
	}
		
    }

    /** Notification of context shutdown.
     *  We should clean up any resources that are used by our
     *  session management code. 
     */
    public void contextShutdown( Context ctx )
	throws TomcatException
    {
	if( debug > 0 )
	    log("Removing sessions from " + ctx );

	SimpleSessionManager sm=getManager(ctx);
	Enumeration ids = sm.getSessionIds();
	while (ids.hasMoreElements()) {
	    String id = (String) ids.nextElement();
	    ServerSession session = sm.findSession(id);
	    if (!session.getTimeStamp().isValid())
		continue;
	    if( debug > 0 )
		log( "Shuting down " + id );
	    session.setState( ServerSession.STATE_SUSPEND );
	    session.setState( ServerSession.STATE_EXPIRED );
	    session.setState( ServerSession.STATE_INVALID );
	}
    }

    public int sessionState( Request req, ServerSession session, int state ) {
	TimeStamp ts=session.getTimeStamp();

	if( state==ServerSession.STATE_INVALID ) {
	    // session moved to expire state - remove all attributes from
	    // storage
	    SimpleSessionManager ssm=(SimpleSessionManager)session.getManager();
	    ssm.removeSession( session );
	}
	return state;
    }

    // -------------------- State Info -------------------- 
    public Enumeration getSessionIds(Context ctx) {
	SimpleSessionManager sm= getManager( ctx );
	return sm.getSessionIds();
    }
    
    public Enumeration getSessions(Context ctx) {
	SimpleSessionManager sm= getManager( ctx );
	return sm.getSessions();
    }
    
    public int getSessionCount(Context ctx) {
	SimpleSessionManager sm= getManager( ctx );
	return sm.getSessionCount();
    }
    
    public int getRecycledCount(Context ctx) {
	SimpleSessionManager sm= getManager( ctx );
	return sm.getRecycledCount();
    }

    public ServerSession findSession( Context ctx, String sessionId)
    {
	SimpleSessionManager sM = getManager( ctx );    
	return sM.findSession( sessionId );
    }

    
    // -------------------- Internal methods --------------------

    
    private SimpleSessionManager getManager( Context ctx ) {
	return (SimpleSessionManager)ctx.getContainer().getNote(manager_note);
    }

    /**
     * The actual "simple" manager
     * 
     */
    public static class SimpleSessionManager  
    {
	private int debug=0;
	private BaseInterceptor mod;
	/** The set of previously recycled Sessions for this Manager.
	 */
	protected SimplePool recycled = new SimplePool();
	
	/**
	 * The set of currently active Sessions for this Manager, keyed by
	 * session identifier.
	 */
	protected Hashtable sessions = new Hashtable();

	public SimpleSessionManager() {
	}

	public void setDebug( int l ) {
	    debug=l;
	}

	public void setModule( BaseInterceptor bi ) {
	    mod=bi;
	}

	// --------------------------------------------- Public Methods

	public Enumeration getSessionIds() {
	    return sessions.keys();
	}

	public Enumeration getSessions() {
	    return sessions.elements();
	}

	public int getSessionCount() {
	    return sessions.size();
	}

	public int getRecycledCount() {
	    return recycled.getCount();
	}
	
	public ServerSession findSession(String id) {
	    if (id == null) return null;
	    return (ServerSession)sessions.get(id);
	}

	/**
	 * Remove this Session from the active Sessions for this Manager.
	 *
	 * @param session Session to be removed
	 */
	public void removeSession(ServerSession session) {
	    if( debug>0 ) mod.log( "removeSession " + session );
	    sessions.remove(session.getId().toString());
	    recycled.put(session);
	    session.setValid(false);
	    // Do not recycle it yet - whoever expires it should also recyle.
	    // Otherwise we may miss something
	    // session.recycle();
	    //	    session.removeAllAttributes();
	}

	public ServerSession getNewSession(Request req, Context ctx) {
	    // Recycle or create a Session instance
	    ServerSession session = (ServerSession)recycled.get();
	    if (session == null) {
		session = ctx.getContextManager().createServerSession();
		session.setManager( this );
		session.setDebug( debug );
	    }
	    session.setContext( ctx );

	    session.setState( ServerSession.STATE_NEW, req );
	    
	    // The id will be set by one of the modules
	    String newId=session.getId().toString();
	    
//XXXXX - the following is a temporary fix only!  Underlying problem
//        is:  Why is the newId==null?

	    newId=(newId==null)?"null":newId;
	    
	    // What if the newId belongs to an existing session ?
	    // This shouldn't happen ( maybe we can try again ? )
	    ServerSession oldS=findSession( newId );
	    if( oldS!=null) {
		// that's what the original code did
		oldS.setState( ServerSession.STATE_EXPIRED );
		oldS.recycle();
		oldS.setState( ServerSession.STATE_INVALID );
	    }
	    sessions.put( newId, session );
	    return (session);
	}
	public ServerSession cloneSession(Request req, Context ctx, String oldS) {
	    // Recycle or create a Session instance
	    ServerSession session = (ServerSession)recycled.get();
	    if (session == null) {
		session = ctx.getContextManager().createServerSession();
		session.setManager( this );
		session.setDebug( debug );
	    }
	    session.setContext( ctx );

	    session.setState( ServerSession.STATE_NEW, req );
	    
	    session.getId().setString(oldS);

	    // The id will be set by one of the modules
	    String newId=session.getId().toString();
	    
//XXXXX - the following is a temporary fix only!  Underlying problem
//        is:  Why is the newId==null?

	    newId=(newId==null)?"null":newId;
	    
	    sessions.put( newId, session );
	    return (session);
	}

    }
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.