/*  Copyright (c) 2000 by Oracle Corporation. All Rights Reserved. */
package oracle.portal.provider.v1.http;

import javax.servlet.http.*;
import java.util.*;
import oracle.portal.provider.v1.*;

/**
 *  ServletProviderSession is an implementation of the ProviderSession that
 *  uses an HttpSession as the underlying session store. 
 *
 *  A single ServletProviderSession object is created per HttpSession. The
 *  ServletProviderSession is simply a wrapper that delegates session storage
 *  to the HttpSession and provides a mechanism for retrieving the attached
 *  session.<p>
 * 
 *  Sessions, if used, must be established in Provider.initSession(). Sessions
 *  are maintained on a ProviderUser basis.  The ProviderUser interface is used
 *  to create and reacquire the session.  A convenience method for reacquiring the
 *  session is available to renderers in the PortletRenderRequest object.
 */
public final class ServletProviderSession
    implements ProviderSession, HttpSessionBindingListener
{

    public static final String SESSION_ID = "oracle.portal.provider.http.v1.ServletProviderSession";

    /**
     * object to synchronize creation of ServletProviderSession
     */
    private static Object sLock = new Object();
    
    private HttpSession mSession;
    private int mSessionTimeout;

    public static ServletProviderSession getAttachedSession(HttpServletRequest request) 
    {
        HttpSession httpSession = request.getSession(false);
        if (httpSession != null) 
        {
            try 
            {
                return (ServletProviderSession)httpSession.getValue(ServletProviderSession.SESSION_ID);
            } 
            catch (IllegalStateException ise) 
            {
                return null;
            }
        } 
        else 
        {
            return null;
        }
    }
    
    public static ServletProviderSession getAttachedSession(HttpServletRequest request,
                                                            boolean create,
                                                            int timeout) 
    {
        ServletProviderSession sps = getAttachedSession(request);
        if (sps != null)
            return sps;

        if (create)
        {
            // ServletProviderSession does not exist & create flag was true so
            // create a new one. Creation is synchronized so that there is only 
            // one ServletProviderRequest object created. Creation of more than
            // can result in the existing object being unbound from the session
            // and its internal state being cleared - even though it may be in 
            // use by another thread
            synchronized(sLock)
            {
                sps = getAttachedSession(request);
                if (sps == null)
                {
                    sps = new ServletProviderSession(request, timeout);
                    sps.putValue(SESSION_ID, sps);
                }
            } 
        }
        return sps;
    }

    /**
     * private constructor - only called from getAttachedSession
     */
    private ServletProviderSession(HttpServletRequest request, int timeout) 
    {
        mSession = request.getSession(true);
        mSessionTimeout = timeout;
    }

    /**
     *
     * Returns the time when this session was created, measured
     * in milliseconds since midnight January 1, 1970 GMT.
     *
     * @return				a <code>long</code> specifying
     * 					when this session was created,
     *					expressed in
     *					milliseconds since 1/1/1970 GMT
     *
     * @exception IllegalStateException	if this method is called on an
     *					invalidated session
     *
     */

    public long getCreationTime() throws IllegalStateException
    {
        if (mSession == null)
        {
            throw new IllegalStateException("Session has expired");
        }
        return mSession.getCreationTime();
    }




    /**
     *
     * Returns a string containing the unique identifier assigned 
     * to this session. The identifier is assigned
     * by the servlet container and is implementation dependent.
     * 
     * @return				a string specifying the identifier
     *					assigned to this session
     *
     * @exeption IllegalStateException	if this method is called on an
     *					invalidated session
     *
     */

    public String getId() throws IllegalStateException
    {
        if (mSession == null)
        {
            throw new IllegalStateException("Session has expired");
        }
        return mSession.getId();
    }
    
    
    

    /**
     *
     * Returns the last time the client sent a request associated with
     * this session, as the number of milliseconds since midnight
     * January 1, 1970 GMT. 
     *
     * <p>Actions that your application takes, such as getting or setting
     * a value associated with the session, do not affect the access
     * time.
     *
     * @return				a <code>long</code>
     *					representing the last time
     *					the client sent a request associated
     *					with this session, expressed in 
     *					milliseconds since 1/1/1970 GMT
     *
     * @exeption IllegalStateException	if this method is called on an
     *					invalidated session
     *
     */

    public long getLastAccessedTime()  throws IllegalStateException
    {
        if (mSession == null)
        {
            throw new IllegalStateException("Session has expired");
        }
        return mSession.getLastAccessedTime();
    }

   /**
    * Returns the maximum time interval, in seconds, that
    * the servlet engine will keep this session open between
    * client requests. You can set the maximum time interval
    * with the <code>setMaxInactiveInterval</code> method.
    *
    *
    *
    * @return	an integer specifying the number of
    *			seconds this session remains open
    *			between client requests
    *
    *
    *
    */

    public int getMaxInactiveInterval()
    {
        return mSessionTimeout;
    }

    
    /**
     *
     * Returns the object bound with the specified name in this session, or
     * <code>null</code> if no object is bound under the name.
     *
     * @param name		a string specifying the name of the object
     *
     * @return			the object with the specified name
     *
     * @exception IllegalStateException	if this method is called on an
     *					invalidated session
     *
     */

    public Object getAttribute(String name) throws IllegalStateException {
        return getValue(name);
    }
    
    

    
    /**
     *
     * @deprecated 	As of Version 2.2, this method is
     * 			replaced by {@link #getAttribute}.
     *
     * @param name		a string specifying the name of the object
     *
     * @return			the object with the specified name
     *
     * @exception IllegalStateException	if this method is called on an
     *					invalidated session
     *
     */
  
    public Object getValue(String name) throws IllegalStateException
    {
        if (mSession == null)
        {
            throw new IllegalStateException("Session has not been created or has expired");
        }
        return mSession.getValue(name);
    }
    
    
    

    /**
     *
     * Returns an <code>Enumeration</code> of <code>String</code> objects
     * containing the names of all the objects bound to this session.
     *
     * @return			an <code>Enumeration</code> of 
     *				<code>String</code> objects specifying the
     *				names of all the objects bound to
     *				this session
     *
     * @exception IllegalStateException	if this method is called on an
     *					invalidated session
     *
     */
    
    public Enumeration getAttributeNames() throws IllegalStateException {
        String[] s = getValueNames();
        if (s == null || s.length == 0) return null;

        Vector v = new Vector(s.length);
        for (int i = 0; i < s.length; i++) {
            v.addElement(s[i]);
        }
        return v.elements();
    }
    
    
    

    /**
     *
     * @deprecated 	As of Version 2.2, this method is
     * 			replaced by {@link #getAttributeNames}
     *
     * @return				an array of <code>String</code>
     *					objects specifying the
     *					names of all the objects bound to
     *					this session
     *
     * @exception IllegalStateException	if this method is called on an
     *					invalidated session
     *
     */
    
    public String[] getValueNames() throws IllegalStateException
    {
        if (mSession == null)
        {
            throw new IllegalStateException("Session has expired");
        }
        return mSession.getValueNames();
    }
    

    

    /**
     * Binds an object to this session, using the name specified.
     * If an object of the same name is already bound to the session,
     * the object is replaced.
     *
     * <p>After this method executes, and if the object
     * implements <code>HttpSessionBindingListener</code>,
     * the container calls
     * <code>HttpSessionBindingListener.valueBound</code>.
     *
     * @param name			the name to which the object is bound;
     *					cannot be null
     *
     * @param value			the object to be bound; cannot be null
     *
     * @exception IllegalStateException	if this method is called on an
     *					invalidated session
     *
     */

    public void setAttribute(String name, Object value) throws IllegalStateException 
    {
        putValue(name, value);
    }
    



    
    /**
     *
     * @deprecated 	As of Version 2.2, this method is
     * 			replaced by {@link #setAttribute}
     *
     * @param name			the name to which the object is bound;
     *					cannot be null
     *
     * @param value			the object to be bound; cannot be null
     *
     * @exception IllegalStateException	if this method is called on an
     *					invalidated session
     *
     */

    public void putValue(String name, Object value) throws IllegalStateException
    {
        if (mSession == null)
        {
            throw new IllegalStateException("Session has expired");
        }
        mSession.putValue(name, value);
    }





    /**
     *
     * Removes the object bound with the specified name from
     * this session. If the session does not have an object
     * bound with the specified name, this method does nothing.
     *
     * <p>After this method executes, and if the object
     * implements <code>HttpSessionBindingListener</code>,
     * the container calls
     * <code>HttpSessionBindingListener.valueUnbound</code>.
     * 
     * 
     *
     * @param name				the name of the object to
     *						remove from this session
     *
     * @exception IllegalStateException	if this method is called on an
     *					invalidated session
     */

    public void removeAttribute(String name) throws IllegalStateException {
        removeValue(name);
    }





    /**
     *
     * @deprecated 	As of Version 2.2, this method is
     * 			replaced by {@link #setAttribute}
     *
     * @param name				the name of the object to
     *						remove from this session
     *
     * @exception IllegalStateException	if this method is called on an
     *					invalidated session
     */

    public void removeValue(String name) throws IllegalStateException
    {
        if (mSession == null)
        {
            throw new IllegalStateException("Session has expired");
        }
        mSession.removeValue(name);
    }




    /**
     *
     * Invalidates this session and unbinds any objects bound
     * to it.
     *
     * @exception IllegalStateException	if this method is called on an
     *					already invalidated session
     *
     */

    public void invalidate() throws IllegalStateException
    {
        if (mSession == null)
        {
            throw new IllegalStateException("Session has expired");
        }
        mSession.invalidate();
    }
    
    

    
    /**
     *
     * Returns <code>true</code> if the client does not yet know about the
     * session or if the client chooses not to join the session.  For 
     * example, if the server used only cookie-based sessions, and
     * the client had disabled the use of cookies, then a session would
     * be new on each request.
     *
     * @return 				<code>true</code> if the 
     *					server has created a session,
     *					but the client has not yet joined
     *
     * @exception IllegalStateException	if this method is called on an
     *					already invalidated session
     *
     */

    public boolean isNew() throws IllegalStateException
    {
        if (mSession == null)
        {
            throw new IllegalStateException("Session has expired");
        }
        return mSession.isNew();
    }


    public void valueBound(HttpSessionBindingEvent event)
    {
        // Do nothing -- we already now our session
        return;
    }

    /**
     *  The ServletProviderSession object has been removed from the session. This
     *  means the HttpSession has expired (or someone has added another object to 
     *  the HttpSession using the same key). In either case, this object must now
     *  release it's reference to the session so it can be garbage collected. 
     * 
     *  subsequent calls to methods that access the session will throw an 
     *  IllegalStateException.
     */
    public void valueUnbound(HttpSessionBindingEvent event)
    {
        // object does not keep a session reference anymore
        mSession = null;
    }
}

 