All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mortbay.jetty.servlet.HashSessionManager Maven / Gradle / Ivy

There is a newer version: 7.0.0.pre5
Show newest version
// ========================================================================
// Copyright 1996-2005 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// 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.mortbay.jetty.servlet;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletRequest;

import org.mortbay.log.Log;
import org.mortbay.util.LazyList;


/* ------------------------------------------------------------ */
/** An in-memory implementation of SessionManager.
 *
 * @author Greg Wilkins (gregw)
 */
public class HashSessionManager extends AbstractSessionManager
{
    private static int __id;
    private Timer _timer;
    private TimerTask _task;
    private int _scavengePeriodMs=30000;
    private int _savePeriodMs=0; //don't do period saves by default
    private TimerTask _saveTask;
    protected Map _sessions;
    private File _storeDir;
    
    /* ------------------------------------------------------------ */
    public HashSessionManager()
    {
        super();
    }

    /* ------------------------------------------------------------ */
    /* (non-Javadoc)
     * @see org.mortbay.jetty.servlet.AbstractSessionManager#doStart()
     */
    public void doStart() throws Exception
    {
        _sessions=new ConcurrentHashMap(); // TODO: use syncronizedMap for JDK 1.4
        super.doStart();

        _timer=new Timer("HashSessionScavenger-"+__id++, true);
        
        setScavengePeriod(getScavengePeriod());

        if (_storeDir!=null)
        {
            if (!_storeDir.exists())
                _storeDir.mkdir();
            restoreSessions();
        }
 
        setSavePeriod(getSavePeriod());
    }

    /* ------------------------------------------------------------ */
    /* (non-Javadoc)
     * @see org.mortbay.jetty.servlet.AbstractSessionManager#doStop()
     */
    public void doStop() throws Exception
    {
        
        if (_storeDir != null)
            saveSessions();
        
        super.doStop();
 
        _sessions.clear();
        _sessions=null;

        // stop the scavenger
        synchronized(this)
        {
            if (_saveTask!=null)
                _saveTask.cancel();
            if (_task!=null)
                _task.cancel();
            if (_timer!=null)
                _timer.cancel();
            _timer=null;
        }
    }

    /* ------------------------------------------------------------ */
    /**
     * @return seconds
     */
    public int getScavengePeriod()
    {
        return _scavengePeriodMs/1000;
    }

    
    /* ------------------------------------------------------------ */
    public Map getSessionMap()
    {
        return Collections.unmodifiableMap(_sessions);
    }


    /* ------------------------------------------------------------ */
    public int getSessions()
    {
        return _sessions.size();
    }


    /* ------------------------------------------------------------ */
    public void setMaxInactiveInterval(int seconds)
    {
        super.setMaxInactiveInterval(seconds);
        if (_dftMaxIdleSecs>0&&_scavengePeriodMs>_dftMaxIdleSecs*1000)
            setScavengePeriod((_dftMaxIdleSecs+9)/10);
    }

    /* ------------------------------------------------------------ */
    public void setSavePeriod (int seconds)
    {
        int oldSavePeriod = _savePeriodMs;
        int period = (seconds * 1000);
        if (period < 0)
            period=0;
        _savePeriodMs=period;
        
        if (_timer!=null)
        {
            synchronized (this)
            {
                if (_saveTask!=null)
                    _saveTask.cancel();
                if (_savePeriodMs > 0 && _storeDir!=null) //only save if we have a directory configured
                {
                    _saveTask = new TimerTask()
                    {
                        public void run()
                        {
                            try
                            {
                                saveSessions();
                            }
                            catch (Exception e)
                            {
                                Log.warn(e);
                            }
                        }   
                    };
                    _timer.schedule(_saveTask,_savePeriodMs,_savePeriodMs);
                }
            }
        }
    }

    /* ------------------------------------------------------------ */
    public int getSavePeriod ()
    {
        if (_savePeriodMs<=0)
            return 0;
        
        return _savePeriodMs/1000;
    }
    
    /* ------------------------------------------------------------ */
    /**
     * @param seconds
     */
    public void setScavengePeriod(int seconds)
    {
        if (seconds==0)
            seconds=60;

        int old_period=_scavengePeriodMs;
        int period=seconds*1000;
        if (period>60000)
            period=60000;
        if (period<1000)
            period=1000;

        _scavengePeriodMs=period;
        if (_timer!=null && (period!=old_period || _task==null))
        {
            synchronized (this)
            {
                if (_task!=null)
                    _task.cancel();
                _task = new TimerTask()
                {
                    public void run()
                    {
                        scavenge();
                    }   
                };
                _timer.schedule(_task,_scavengePeriodMs,_scavengePeriodMs);
            }
        }
    }
    
    /* -------------------------------------------------------------- */
    /**
     * Find sessions that have timed out and invalidate them. This runs in the
     * SessionScavenger thread.
     */
    private void scavenge()
    {
        //don't attempt to scavenge if we are shutting down
        if (isStopping() || isStopped())
            return;
        
        Thread thread=Thread.currentThread();
        ClassLoader old_loader=thread.getContextClassLoader();
        try
        {
            if (_loader!=null)
                thread.setContextClassLoader(_loader);

            long now=System.currentTimeMillis();

            // Since Hashtable enumeration is not safe over deletes,
            // we build a list of stale sessions, then go back and invalidate
            // them
            Object stale=null;

            synchronized (HashSessionManager.this)
            {
                // For each session
                for (Iterator i=_sessions.values().iterator(); i.hasNext();)
                {
                    Session session=(Session)i.next();
                    long idleTime=session._maxIdleMs;
                    if (idleTime>0&&session._accessed+idleTime0;)
            {
                // check it has not been accessed in the meantime
                Session session=(Session)LazyList.get(stale,i);
                long idleTime=session._maxIdleMs;
                if (idleTime>0&&session._accessed+idleTime 0)
        {
            ArrayList keys = new ArrayList();
            for (int i=0; i0&&(_maxIdleMs/10)<_scavengePeriodMs)
                HashSessionManager.this.setScavengePeriod((secs+9)/10);
        }
        
        /* ------------------------------------------------------------ */
        protected Map newAttributeMap()
        {
            return new HashMap(3);
        }
        

        /* ------------------------------------------------------------ */
        public void invalidate ()
        throws IllegalStateException
        {
            super.invalidate();
            
            remove();
        }

        /* ------------------------------------------------------------ */
        public void remove()
        {
            String id=getId();
            if (id==null)
                return;
            
            //all sessions are invalidated when jetty is stopped, make sure we don't
            //remove all the sessions in this case
            if (isStopping() || isStopped())
                return;
            
            if (_storeDir==null || !_storeDir.exists())
            {
                return;
            }
            
            File f = new File(_storeDir, id);
            f.delete();
        }

        /* ------------------------------------------------------------ */
        public void save(OutputStream os)  throws IOException 
        {
            DataOutputStream out = new DataOutputStream(os);
            out.writeUTF(_clusterId);
            out.writeUTF(_nodeId);
            out.writeBoolean(_idChanged);
            out.writeLong( _created);
            out.writeLong(_cookieSet);
            out.writeLong(_accessed);
            out.writeLong(_lastAccessed);
            /* Don't write these out, as they don't make sense to store because they
             * either they cannot be true or their value will be restored in the 
             * Session constructor.
             */
            //out.writeBoolean(_invalid);
            //out.writeBoolean(_doInvalidate);
            //out.writeLong(_maxIdleMs);
            //out.writeBoolean( _newSession);
            out.writeInt(_requests);
            if (_values != null)
            {
                out.writeInt(_values.size());
                Iterator itor = _values.keySet().iterator();
                while (itor.hasNext())
                {
                    String key = (String)itor.next();
                    out.writeUTF(key);
                }
                itor = _values.values().iterator();
                ObjectOutputStream oos = new ObjectOutputStream(out);
                while (itor.hasNext())
                {
                    oos.writeObject(itor.next());
                }
                oos.close();
            }
            else
                out.writeInt(0);
            out.close();
        }
        
    }

    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    protected class ClassLoadingObjectInputStream extends ObjectInputStream
    {
        /* ------------------------------------------------------------ */
        public ClassLoadingObjectInputStream(java.io.InputStream in) throws IOException
        {
            super(in);
        }

        /* ------------------------------------------------------------ */
        public ClassLoadingObjectInputStream () throws IOException
        {
            super();
        }

        /* ------------------------------------------------------------ */
        public Class resolveClass (java.io.ObjectStreamClass cl) throws IOException, ClassNotFoundException
        {
            try
            {
                return Class.forName(cl.getName(), false, Thread.currentThread().getContextClassLoader());
            }
            catch (ClassNotFoundException e)
            {
                return super.resolveClass(cl);
            }
        }
    }

    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy