org.ireland.jnetty.server.session.HttpSessionImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.ireland.jnetty.server.session.HttpSessionImpl.java

Source

/*
 * Copyright (c) 1998-2012 Caucho Technology -- all rights reserved
 *
 * This file is part of Resin(R) Open Source
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Resin Open Source is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Resin Open Source is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Resin Open Source; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Scott Ferguson
 */

package org.ireland.jnetty.server.session;

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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.ireland.jnetty.webapp.WebApp;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.TreeMap;

/**
 * Implements a HTTP session.
 */
public class HttpSessionImpl implements HttpSession {
    private static final Log log = LogFactory.getLog(HttpSessionImpl.class.getName());

    private static final boolean debug = log.isDebugEnabled();

    // the session's identifier
    private String _id;

    // the owning session manager
    protected SessionManager _manager;
    // the session objectStore

    // Map containing the actual values.
    protected Map<String, Object> _values;

    // time the session was created
    private long _creationTime;

    // time the session was last accessed
    private long _accessTime;

    // maximum time the session may stay alive.
    private long _idleTimeout;

    private long _lastUseTime;

    // true if the session is new
    private boolean _isNew = true;

    // true if the session is still valid, i.e. not invalidated
    private boolean _isValid = true;

    /**
     * Create a new session object.
     * 
     * @param manager
     *            the owning session manager.
     * @param id
     *            the session identifier.
     * @param creationTime
     *            the time in milliseconds when the session was created.
     */
    public HttpSessionImpl(SessionManager manager, String id, long creationTime) {
        _manager = manager;

        _creationTime = creationTime;

        _accessTime = _creationTime;

        _lastUseTime = _accessTime;
        _idleTimeout = manager.getSessionTimeout();

        _id = id;

        _values = createValueMap();

        if (debug)
            log.debug(this + " new");
    }

    /**
     * Create the map used to objectStore values.
     */
    protected Map<String, Object> createValueMap() {
        return new TreeMap<String, Object>();
    }

    /**
     * Returns the time the session was created.
     */
    @Override
    public long getCreationTime() {
        // this test forced by TCK
        if (!_isValid)
            throw new IllegalStateException(
                    this + ": can't call getCreationTime() when session is no longer valid.");

        return _creationTime;
    }

    /**
     * Returns the session identifier.
     */
    @Override
    public String getId() {
        return _id;
    }

    /**
     * Returns the last objectAccess time.
     */
    @Override
    public long getLastAccessedTime() {
        // this test forced by TCK
        if (!_isValid)
            throw new IllegalStateException(
                    this + ": can't call getLastAccessedTime() when session is no longer valid.");

        return _accessTime;
    }

    /**
     * Returns the time the session is allowed to be alive.
     * 
     * @return time allowed to live in seconds
     */
    @Override
    public int getMaxInactiveInterval() {
        if (Long.MAX_VALUE / 2 <= _idleTimeout)
            return -1;
        else
            return (int) (_idleTimeout / 1000);
    }

    /**
     * Sets the maximum time a session is allowed to be alive.
     * 
     * @param value
     *            time allowed to live in seconds
     */
    @Override
    public void setMaxInactiveInterval(int value) {
        if (value < 0)
            _idleTimeout = Long.MAX_VALUE / 2;
        else
            _idleTimeout = ((long) value) * 1000;
    }

    /**
     * Returns the session context.
     * 
     * @deprecated
     */
    @Override
    public HttpSessionContext getSessionContext() {
        return null;
    }

    /**
     * Returns the servlet context.
     */
    @Override
    public ServletContext getServletContext() {
        return _manager.getWebApp();
    }

    /**
     * Returns the session manager.
     */
    public SessionManager getManager() {
        return _manager;
    }

    /**
     * Returns true if the session is new.
     */
    @Override
    public boolean isNew() {
        if (!_isValid)
            throw new IllegalStateException(this + " can't call isNew() when session is no longer valid.");

        return _isNew;
    }

    /**
     * Returns true if the session is valid.
     */
    public boolean isValid() {
        return _isValid;
    }

    public boolean isTimeout() {
        return isTimeout(System.currentTimeMillis());
    }

    boolean isTimeout(long now) {
        long maxIdleTime = _idleTimeout;

        long lastUseTime = getLastUseTime();

        return lastUseTime + maxIdleTime < now;
    }

    private long getLastUseTime() {
        return _lastUseTime;
    }

    /**
     * Returns true if the session is empty.
     */
    public boolean isEmpty() {
        return _values == null || _values.size() == 0;
    }

    //
    // Attribute API
    //

    /**
     * Returns the named attribute from the session.
     */
    @Override
    public Object getAttribute(String name) {
        if (!_isValid)
            throw new IllegalStateException(this + ": can't call getAttribute() when session is no longer valid.");

        synchronized (_values) {
            Object value = _values.get(name);

            return value;
        }
    }

    /**
     * Sets a session attribute. If the value is a listener, notify it of the objectModified. If the value has changed
     * mark the session as changed for persistent sessions.
     * 
     * @param name
     *            the name of the attribute
     * @param value
     *            the value of the attribute
     */
    @Override
    public void setAttribute(String name, Object value) {
        if (!_isValid)
            throw new IllegalStateException(
                    this + ": can't call setAttribute(String, Object) when session is no longer valid.");

        Object oldValue;

        if (value != null && !(value instanceof Serializable) && debug) {
            log.debug(this + " attribute '" + name + "' value is non-serializable type '"
                    + value.getClass().getName() + "'");
        }

        synchronized (_values) {
            if (value != null)
                oldValue = _values.put(name, value);
            else
                oldValue = _values.remove(name);
        }

        if (oldValue instanceof HttpSessionBindingListener) {
            HttpSessionBindingListener listener;
            listener = (HttpSessionBindingListener) oldValue;

            listener.valueUnbound(new HttpSessionBindingEvent(HttpSessionImpl.this, name, oldValue));
        }

        if (value instanceof HttpSessionBindingListener) {
            HttpSessionBindingListener listener;
            listener = (HttpSessionBindingListener) value;

            listener.valueBound(new HttpSessionBindingEvent(HttpSessionImpl.this, name, value));
        }

        // Notify the attribute listeners
        ArrayList listeners = _manager.getAttributeListeners();

        if (listeners != null && listeners.size() > 0) {
            HttpSessionBindingEvent event;

            if (oldValue != null)
                event = new HttpSessionBindingEvent(this, name, oldValue);
            else
                event = new HttpSessionBindingEvent(this, name, value);

            for (int i = 0; i < listeners.size(); i++) {
                HttpSessionAttributeListener listener;
                listener = (HttpSessionAttributeListener) listeners.get(i);

                if (oldValue != null)
                    listener.attributeReplaced(event);
                else
                    listener.attributeAdded(event);
            }
        }
    }

    /**
     * Remove a session attribute. If the value is a listener, notify it of the objectModified.
     * 
     * @param name
     *            the name of the attribute to objectRemove
     */
    @Override
    public void removeAttribute(String name) {
        if (!_isValid)
            throw new IllegalStateException(
                    this + ": can't call removeAttribute(String) when session is no longer valid.");

        Object oldValue;

        synchronized (_values) {
            oldValue = _values.remove(name);
        }

        notifyAttributeRemoved(name, oldValue);
    }

    /**
     * Notify any Attribute unbound listeners.
     */
    private void notifyAttributeRemoved(String name, Object oldValue) {
        if (oldValue == null)
            return;

        if (oldValue instanceof HttpSessionBindingListener) {
            HttpSessionBindingListener listener;
            listener = (HttpSessionBindingListener) oldValue;

            listener.valueUnbound(new HttpSessionBindingEvent(this, name, oldValue));
        }

        // Notify the attributes listeners
        ArrayList listeners = _manager.getAttributeListeners();
        if (listeners != null) {
            HttpSessionBindingEvent event;

            event = new HttpSessionBindingEvent(this, name, oldValue);

            for (int i = 0; i < listeners.size(); i++) {
                HttpSessionAttributeListener listener;
                listener = (HttpSessionAttributeListener) listeners.get(i);

                listener.attributeRemoved(event);
            }
        }
    }

    /**
     * Return an enumeration of all the sessions' attribute names.
     * 
     * @return enumeration of the attribute names.
     */
    @Override
    public Enumeration<String> getAttributeNames() {
        synchronized (_values) {
            if (!_isValid)
                throw new IllegalStateException(
                        this + " can't call getAttributeNames() when session is no longer valid.");

            return Collections.enumeration(_values.keySet());
        }
    }

    /**
     * @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() {
        synchronized (_values) {
            if (!_isValid)
                throw new IllegalStateException(
                        this + " can't call getValueNames() when session is no longer valid.");

            if (_values == null)
                return new String[0];

            String[] s = new String[_values.size()];

            Enumeration<String> e = getAttributeNames();
            int count = 0;
            while (e.hasMoreElements())
                s[count++] = (String) e.nextElement();

            return s;
        }
    }

    //
    // lifecycle: creation
    //

    /**
     * Creates a new session.
     */
    void create(long now, boolean isCreate) {
        if (debug) {
            log.debug(this + " create session");
        }

        if (_isValid) {
            clearAllAttributes();
        }

        // TCK now cares about exact time
        now = System.currentTimeMillis();

        _isValid = true;
        _isNew = true;
        _creationTime = now;
    }

    //
    // invalidation, lru, timeout
    //

    /**
     * Invalidates the session, called by user code.
     * 
     */
    @Override
    public void invalidate() {
        if (debug)
            log.debug(this + " invalidate");

        clearAllAttributes();

        _isValid = false;

        _manager.removeSession(this);
    }

    /**
     * Cleans up the session.
     */
    void clearAllAttributes() {
        if (_values.size() == 0)
            return;

        // ClusterObject clusterObject = _clusterObject;

        ArrayList<String> names = new ArrayList<String>();
        ArrayList<Object> values = new ArrayList<Object>();

        synchronized (_values) {

            for (Map.Entry<String, Object> entry : _values.entrySet()) {
                names.add(entry.getKey());
                values.add(entry.getValue());
            }

            _values.clear();
        }

        // server/015a
        for (int i = 0; i < names.size(); i++) {
            String name = names.get(i);
            Object value = values.get(i);

            notifyValueUnbound(name, value);
        }
    }

    /**
     * Notify any value unbound listeners.
     */
    private void notifyValueUnbound(String name, Object oldValue) {
        if (oldValue == null)
            return;

        if (oldValue instanceof HttpSessionBindingListener) {
            HttpSessionBindingListener listener;
            listener = (HttpSessionBindingListener) oldValue;

            listener.valueUnbound(new HttpSessionBindingEvent(this, name, oldValue));
        }

        // Notify the attributes listeners
        ArrayList listeners = _manager.getAttributeListeners();
        if (listeners != null) {
            HttpSessionBindingEvent event;

            event = new HttpSessionBindingEvent(this, name, oldValue);

            for (int i = 0; i < listeners.size(); i++) {
                HttpSessionAttributeListener listener;
                listener = (HttpSessionAttributeListener) listeners.get(i);

                listener.attributeRemoved(event);
            }
        }
    }

    /**
     * Invalidates a session based on a timeout
     */
    void timeout() {
        clearAllAttributes();
    }

    /**
     * Callback when the session is removed from the session cache, generally because the session cache is full.
     */
    public void removeEvent() {

        if (debug)
            log.debug(this + " remove");

        long now = System.currentTimeMillis();

        // server/015k, server/10g2
        if (_accessTime + getMaxInactiveInterval() < now) {
            publishSessionDestroyed();
        }

    }

    /**
     * ?Session Destroyed
     */
    private void publishSessionDestroyed() {

        ArrayList<HttpSessionListener> listeners = _manager.getListeners();

        if (listeners != null) {
            HttpSessionEvent event = new HttpSessionEvent(this);

            for (int i = listeners.size() - 1; i >= 0; i--) {
                HttpSessionListener listener;
                listener = (HttpSessionListener) listeners.get(i);

                listener.sessionDestroyed(event);
            }
        }
    }

    @Override
    public String toString() {
        String contextPath = "";

        SessionManager manager = _manager;
        if (manager != null) {
            WebApp webApp = manager.getWebApp();

            if (webApp != null)
                contextPath = "," + webApp.getContextPath();
        }

        return getClass().getSimpleName() + "[" + getId() + contextPath + "]";
    }

}