Package winstone

Source Code of winstone.WinstoneSession

/*
* Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
* Distributed under the terms of either:
* - the common development and distribution license (CDDL), v1.0; or
* - the GNU Lesser General Public License, v2.1 or later
*/
package winstone;

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.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
* Http session implementation for Winstone.
*
* @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
* @version $Id: WinstoneSession.java,v 1.10 2006/08/27 07:19:47 rickknowles Exp $
*/
public class WinstoneSession implements HttpSession, Serializable {
    public static final String SESSION_COOKIE_NAME = "JSESSIONID";

    private String sessionId;
    private WebAppConfiguration webAppConfig;
    private Map sessionData;
    private long createTime;
    private long lastAccessedTime;
    private int maxInactivePeriod;
    private boolean isNew;
    private boolean isInvalidated;
    private HttpSessionAttributeListener sessionAttributeListeners[];
    private HttpSessionListener sessionListeners[];
    private HttpSessionActivationListener sessionActivationListeners[];
    private boolean distributable;
    private Object sessionMonitor = new Boolean(true);
    private Set requestsUsingMe;

    /**
     * Constructor
     */
    public WinstoneSession(String sessionId) {
        this.sessionId = sessionId;
        this.sessionData = new HashMap();
        this.requestsUsingMe = new HashSet();
        this.createTime = System.currentTimeMillis();
        this.isNew = true;
        this.isInvalidated = false;
    }

    public void setWebAppConfiguration(WebAppConfiguration webAppConfig) {
        this.webAppConfig = webAppConfig;
        this.distributable = webAppConfig.isDistributable();
    }
   
    public void sendCreatedNotifies() {
        // Notify session listeners of new session
        for (int n = 0; n < this.sessionListeners.length; n++) {
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader());
            this.sessionListeners[n].sessionCreated(new HttpSessionEvent(this));
            Thread.currentThread().setContextClassLoader(cl);
        }
    }

    public void setSessionActivationListeners(
            HttpSessionActivationListener listeners[]) {
        this.sessionActivationListeners = listeners;
    }

    public void setSessionAttributeListeners(
            HttpSessionAttributeListener listeners[]) {
        this.sessionAttributeListeners = listeners;
    }

    public void setSessionListeners(HttpSessionListener listeners[]) {
        this.sessionListeners = listeners;
    }

    public void setLastAccessedDate(long time) {
        this.lastAccessedTime = time;
    }

    public void setIsNew(boolean isNew) {
        this.isNew = isNew;
    }
   
    public void addUsed(WinstoneRequest request) {
        this.requestsUsingMe.add(request);
    }
   
    public void removeUsed(WinstoneRequest request) {
        this.requestsUsingMe.remove(request);
    }
   
    public boolean isUnusedByRequests() {
        return this.requestsUsingMe.isEmpty();
    }
   
    public boolean isExpired() {
        // check if it's expired yet
        long nowDate = System.currentTimeMillis();
        long maxInactive = getMaxInactiveInterval() * 1000;
        return ((maxInactive > 0) && (nowDate - this.lastAccessedTime > maxInactive ));
    }

    // Implementation methods
    public Object getAttribute(String name) {
        if (this.isInvalidated) {
            throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession"));
        }
        Object att = null;
        synchronized (this.sessionMonitor) {
            att = this.sessionData.get(name);
        }
        return att;
    }

    public Enumeration getAttributeNames() {
        if (this.isInvalidated) {
            throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession"));
        }
        Enumeration names = null;
        synchronized (this.sessionMonitor) {
            names = Collections.enumeration(this.sessionData.keySet());
        }
        return names;
    }

    public void setAttribute(String name, Object value) {
        if (this.isInvalidated) {
            throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession"));
        }
        // Check for serializability if distributable
        if (this.distributable && (value != null)
                && !(value instanceof java.io.Serializable))
            throw new IllegalArgumentException(Launcher.RESOURCES.getString(
                    "WinstoneSession.AttributeNotSerializable", new String[] {
                            name, value.getClass().getName() }));

        // valueBound must be before binding
        if (value instanceof HttpSessionBindingListener) {
            HttpSessionBindingListener hsbl = (HttpSessionBindingListener) value;
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader());
            hsbl.valueBound(new HttpSessionBindingEvent(this, name, value));
            Thread.currentThread().setContextClassLoader(cl);
        }

        Object oldValue = null;
        synchronized (this.sessionMonitor) {
            oldValue = this.sessionData.get(name);
            if (value == null) {
                this.sessionData.remove(name);
            } else {
                this.sessionData.put(name, value);
            }
        }

        // valueUnbound must be after unbinding
        if (oldValue instanceof HttpSessionBindingListener) {
            HttpSessionBindingListener hsbl = (HttpSessionBindingListener) oldValue;
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader());
            hsbl.valueUnbound(new HttpSessionBindingEvent(this, name, oldValue));
            Thread.currentThread().setContextClassLoader(cl);
        }

        // Notify other listeners
        if (oldValue != null)
            for (int n = 0; n < this.sessionAttributeListeners.length; n++) {
                ClassLoader cl = Thread.currentThread().getContextClassLoader();
                Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader());
                this.sessionAttributeListeners[n].attributeReplaced(
                        new HttpSessionBindingEvent(this, name, oldValue));
                Thread.currentThread().setContextClassLoader(cl);
            }
               
        else
            for (int n = 0; n < this.sessionAttributeListeners.length; n++) {
                ClassLoader cl = Thread.currentThread().getContextClassLoader();
                Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader());
                this.sessionAttributeListeners[n].attributeAdded(
                        new HttpSessionBindingEvent(this, name, value));
                Thread.currentThread().setContextClassLoader(cl);
               
            }
    }

    public void removeAttribute(String name) {
        if (this.isInvalidated) {
            throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession"));
        }
        Object value = null;
        synchronized (this.sessionMonitor) {
            value = this.sessionData.get(name);
            this.sessionData.remove(name);
        }

        // Notify listeners
        if (value instanceof HttpSessionBindingListener) {
            HttpSessionBindingListener hsbl = (HttpSessionBindingListener) value;
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader());
            hsbl.valueUnbound(new HttpSessionBindingEvent(this, name));
            Thread.currentThread().setContextClassLoader(cl);
        }
        if (value != null)
            for (int n = 0; n < this.sessionAttributeListeners.length; n++) {
                ClassLoader cl = Thread.currentThread().getContextClassLoader();
                Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader());
                this.sessionAttributeListeners[n].attributeRemoved(
                        new HttpSessionBindingEvent(this, name, value));
                Thread.currentThread().setContextClassLoader(cl);
            }
    }

    public long getCreationTime() {
        if (this.isInvalidated) {
            throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession"));
        }
        return this.createTime;
    }

    public long getLastAccessedTime() {
        if (this.isInvalidated) {
            throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession"));
        }
        return this.lastAccessedTime;
    }

    public String getId() {
        return this.sessionId;
    }

    public int getMaxInactiveInterval() {
        return this.maxInactivePeriod;
    }

    public void setMaxInactiveInterval(int interval) {
        this.maxInactivePeriod = interval;
    }

    public boolean isNew() {
        if (this.isInvalidated) {
            throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession"));
        }
        return this.isNew;
    }

    public ServletContext getServletContext() {
        return this.webAppConfig;
    }

    public void invalidate() {
        if (this.isInvalidated) {
            throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession"));
        }
        // Notify session listeners of invalidated session -- backwards
        for (int n = this.sessionListeners.length - 1; n >= 0; n--) {
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader());
            this.sessionListeners[n].sessionDestroyed(new HttpSessionEvent(this));
            Thread.currentThread().setContextClassLoader(cl);
        }

        List keys = new ArrayList(this.sessionData.keySet());
        for (Iterator i = keys.iterator(); i.hasNext();)
            removeAttribute((String) i.next());
        synchronized (this.sessionMonitor) {
            this.sessionData.clear();
        }
        this.isInvalidated = true;
        this.webAppConfig.removeSessionById(this.sessionId);
    }

    /**
     * Called after the session has been serialized to another server.
     */
    public void passivate() {
        // Notify session listeners of invalidated session
        for (int n = 0; n < this.sessionActivationListeners.length; n++) {
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader());
            this.sessionActivationListeners[n].sessionWillPassivate(
                    new HttpSessionEvent(this));
            Thread.currentThread().setContextClassLoader(cl);
        }

        // Question: Is passivation equivalent to invalidation ? Should all
        // entries be removed ?
        // List keys = new ArrayList(this.sessionData.keySet());
        // for (Iterator i = keys.iterator(); i.hasNext(); )
        // removeAttribute((String) i.next());
        synchronized (this.sessionMonitor) {
            this.sessionData.clear();
        }
        this.webAppConfig.removeSessionById(this.sessionId);
    }

    /**
     * Called after the session has been deserialized from another server.
     */
    public void activate(WebAppConfiguration webAppConfig) {
        this.webAppConfig = webAppConfig;
        webAppConfig.setSessionListeners(this);

        // Notify session listeners of invalidated session
        for (int n = 0; n < this.sessionActivationListeners.length; n++) {
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader());
            this.sessionActivationListeners[n].sessionDidActivate(
                    new HttpSessionEvent(this));
            Thread.currentThread().setContextClassLoader(cl);
        }
    }
   
    /**
     * Save this session to the temp dir defined for this webapp
     */
    public void saveToTemp() {
        File toDir = getSessionTempDir(this.webAppConfig);
        synchronized (this.sessionMonitor) {
            OutputStream out = null;
            ObjectOutputStream objOut = null;
            try {
                File toFile = new File(toDir, this.sessionId + ".ser");
                out = new FileOutputStream(toFile, false);
                objOut = new ObjectOutputStream(out);
                objOut.writeObject(this);
            } catch (IOException err) {
                Logger.log(Logger.ERROR, Launcher.RESOURCES,
                        "WinstoneSession.ErrorSavingSession", err);
            } finally {
                if (objOut != null) {
                    try {objOut.close();} catch (IOException err) {}
                }
                if (out != null) {
                    try {out.close();} catch (IOException err) {}
                }
            }
        }
    }
   
    public static File getSessionTempDir(WebAppConfiguration webAppConfig) {
        File tmpDir = (File) webAppConfig.getAttribute("javax.servlet.context.tempdir");
        File sessionsDir = new File(tmpDir, "WEB-INF" + File.separator + "winstoneSessions");
        if (!sessionsDir.exists()) {
            sessionsDir.mkdirs();
        }
        return sessionsDir;
    }
   
    public static void loadSessions(WebAppConfiguration webAppConfig) {
        int expiredCount = 0;
        // Iterate through the files in the dir, instantiate and then add to the sessions set
        File tempDir = getSessionTempDir(webAppConfig);
        File possibleSessionFiles[] = tempDir.listFiles();
        for (int n = 0; n < possibleSessionFiles.length; n++) {
            if (possibleSessionFiles[n].getName().endsWith(".ser")) {
                InputStream in = null;
                ObjectInputStream objIn = null;
                try {
                    in = new FileInputStream(possibleSessionFiles[n]);
                    objIn = new ObjectInputStream(in);
                    WinstoneSession session = (WinstoneSession) objIn.readObject();
                    session.setWebAppConfiguration(webAppConfig);
                    webAppConfig.setSessionListeners(session);
                    if (session.isExpired()) {
                        session.invalidate();
                        expiredCount++;
                    } else {
                        webAppConfig.addSession(session.getId(), session);
                        Logger.log(Logger.DEBUG, Launcher.RESOURCES,
                                "WinstoneSession.RestoredSession", session.getId());
                    }
                } catch (Throwable err) {
                    Logger.log(Logger.ERROR, Launcher.RESOURCES,
                            "WinstoneSession.ErrorLoadingSession", err);
                } finally {
                    if (objIn != null) {
                        try {objIn.close();} catch (IOException err) {}
                    }
                    if (in != null) {
                        try {in.close();} catch (IOException err) {}
                    }
                    possibleSessionFiles[n].delete();
                }
            }
        }
        if (expiredCount > 0) {
            Logger.log(Logger.DEBUG, Launcher.RESOURCES,
                    "WebAppConfig.InvalidatedSessions", expiredCount + "");
        }
    }

    /**
     * Serialization implementation. This makes sure to only serialize the parts
     * we want to send to another server.
     *
     * @param out
     *            The stream to write the contents to
     * @throws IOException
     */
    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
        out.writeUTF(sessionId);
        out.writeLong(createTime);
        out.writeLong(lastAccessedTime);
        out.writeInt(maxInactivePeriod);
        out.writeBoolean(isNew);
        out.writeBoolean(distributable);

        // Write the map, but first remove non-serializables
        Map copy = new HashMap(sessionData);
        Set keys = new HashSet(copy.keySet());
        for (Iterator i = keys.iterator(); i.hasNext();) {
            String key = (String) i.next();
            if (!(copy.get(key) instanceof Serializable)) {
                Logger.log(Logger.WARNING, Launcher.RESOURCES,
                                "WinstoneSession.SkippingNonSerializable",
                                new String[] { key,
                                        copy.get(key).getClass().getName() });
            }
            copy.remove(key);
        }
        out.writeInt(copy.size());
        for (Iterator i = copy.keySet().iterator(); i.hasNext();) {
            String key = (String) i.next();
            out.writeUTF(key);
            out.writeObject(copy.get(key));
        }
    }

    /**
     * Deserialization implementation
     *
     * @param in
     *            The source of stream data
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private void readObject(java.io.ObjectInputStream in) throws IOException,
            ClassNotFoundException {
        this.sessionId = in.readUTF();
        this.createTime = in.readLong();
        this.lastAccessedTime = in.readLong();
        this.maxInactivePeriod = in.readInt();
        this.isNew = in.readBoolean();
        this.distributable = in.readBoolean();

        // Read the map
        this.sessionData = new Hashtable();
        this.requestsUsingMe = new HashSet();
        int entryCount = in.readInt();
        for (int n = 0; n < entryCount; n++) {
            String key = in.readUTF();
            Object variable = in.readObject();
            this.sessionData.put(key, variable);
        }
        this.sessionMonitor = new Boolean(true);
    }

    /**
     * @deprecated
     */
    public Object getValue(String name) {
        return getAttribute(name);
    }

    /**
     * @deprecated
     */
    public void putValue(String name, Object value) {
        setAttribute(name, value);
    }

    /**
     * @deprecated
     */
    public void removeValue(String name) {
        removeAttribute(name);
    }

    /**
     * @deprecated
     */
    public String[] getValueNames() {
        return (String[]) this.sessionData.keySet().toArray(new String[0]);
    }

    /**
     * @deprecated
     */
    public javax.servlet.http.HttpSessionContext getSessionContext() {
        return null;
    } // deprecated
}
TOP

Related Classes of winstone.WinstoneSession

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.