head	1.8;
access;
symbols;
locks; strict;
comment	@# @;


1.8
date	2001.08.08.18.47.32;	author dlr;	state Exp;
branches;
next	1.7;

1.7
date	2001.08.06.21.29.10;	author dlr;	state Exp;
branches;
next	1.6;

1.6
date	2001.07.23.20.13.03;	author dlr;	state Exp;
branches;
next	1.5;

1.5
date	2001.07.18.23.47.30;	author dlr;	state Exp;
branches;
next	1.4;

1.4
date	2001.07.18.10.05.15;	author dlr;	state Exp;
branches;
next	1.3;

1.3
date	2001.05.23.02.41.08;	author dlr;	state Exp;
branches;
next	1.2;

1.2
date	2001.05.22.00.09.28;	author dlr;	state Exp;
branches;
next	1.1;

1.1
date	2001.05.21.23.02.05;	author dlr;	state Exp;
branches;
next	;


desc
@@


1.8
log
@minor cleanup
@
text
@/* ================================================================
 * Copyright (c) 2000 CollabNet.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * 3. The end-user documentation included with the redistribution, if
 * any, must include the following acknowlegement: "This product includes
 * software developed by CollabNet (http://www.CollabNet/)."
 * Alternately, this acknowlegement may appear in the software itself, if
 * and wherever such third-party acknowlegements normally appear.
 * 
 * 4. The hosted project names must not be used to endorse or promote
 * products derived from this software without prior written
 * permission. For written permission, please contact info@@collab.net.
 * 
 * 5. Products derived from this software may not use the "Tigris" name
 * nor may "Tigris" appear in their names without prior written
 * permission of CollabNet.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL COLLAB.NET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ====================================================================
 * 
 * This software consists of voluntary contributions made by many
 * individuals on behalf of CollabNet.
 */

package org.tigris.helm.tool;

import java.io.*;
import java.util.*;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;

import org.apache.turbine.util.Log;

import org.apache.velocity.context.Context;

import org.tigris.helm.om.User;
import org.tigris.helm.tool.FormCache;
import org.tigris.helm.security.BaseHelmServlet;
import org.tigris.helm.security.RedirectException;

/**
 * Manages information cached in the session.
 *
 * @@author <a href="mailto:davidp@@collab.net">David C. Pellegrini</a>
 * @@author <a href="mailto:dlr@@collab.net">Daniel Rall</a>
 *
 * Copyright (c) 1999 dataweb systems, inc.
 * Copyright (c) 1999-2001 CollabNet, Inc.
 */
public class SessionManager implements Serializable
{
    private static final boolean DEBUG = false;

    /**
     * Do we need to display the welcome message?
     */
    private Boolean needToWelcome = Boolean.TRUE;

    /**
     * The stack of cancel-to target pages.
     */
    private Stack cancelTargets = new Stack();

    /**
     * The session object this manages data for.
     */
    private HttpSession session = null;

    /**
     * Whether the user associated with this session is logged in.
     */
    private Boolean isLoggedIn = Boolean.FALSE;

    /**
     * The user's email.
     */
    private String email = null;

    /**
     * The name of the servlet from whence we started a detour through
     * another servlet or sequence of servlets.  Thus, this is the name of
     * the servlet to resume once the detour is finished. 
     */
    private String detourTarget;

    /**
     * The collection of full contexts for redirects, including cancel-to.
     */
    private Hashtable redirectContexts = new Hashtable();

    /**
     * Creates a new instance.
     *
     * @@param session A variable of type HttpSession
     */
    public SessionManager(HttpSession session)
    {
        this.session = session;
    }

    /**
     * Initializes a user session.  Useful upon successful login.
     *
     * @@param user The user to initialize this session for.
     */
    public void init(User user)
    {
        setLoggedIn(true);
        setUserID(user.getID());
        setLoginID(user.getLoginName());
        setEmail(user.getEmail());
        setUserName(user.getRealName());
    }

    /**
     * Resets the instance variables to initial state.  Useful after logout.
     */
    public void reset()
    {
        if (DEBUG) Log.debug("resetting session: " + session);
        setLoggedIn(false);
        setLoginID(null);
        setUserID(null);
        setUserName(null);
        setEmail(null);
        needToWelcome(true);
        resetCancel();
    }

    /**
     * Returns the current session.
     *
     * @@return The managed session.
     */
    public HttpSession getSession()
    {
        return session;
    }

    /**
     * Returns the session ID.
     *
     * @@return The ID of the managed session.
     */
    public String getSessionID()
    {
        return session.getId();
    }

    /**
     * Returns the session creation time.
     *
     * @@return The session creation time.
     */
    public String getCreationTime()
    {
        return new java.util.Date(session.getCreationTime()).toString();
    }

    /**
     * Returns the session last access time.
     *
     * @@return The session last access time.
     */
    public String getLastAccessedTime()
    {
        return new java.util.Date(session.getLastAccessedTime()).toString();
    }

    /**
     * Sets whether logged in.
     *
     * @@param isLoggedIn Whether logged in.
     */
    public void setLoggedIn(boolean isLoggedIn)
    {
        this.isLoggedIn = (isLoggedIn ? Boolean.TRUE : Boolean.FALSE);
    }

    /**
     * @@deprecated Use setLoggedIn(boolean) instead.
     */
    public void isLoggedIn(boolean isLoggedIn)
    {
        setLoggedIn(isLoggedIn);
    }

    /**
     * Gets whether logged in.
     *
     * @@return Whether logged in.
     */
    public Boolean isLoggedIn()
    {
        return isLoggedIn;
    }

    /**
     * The user's loginID.
     */
    private String loginID = null;

    /**
     * Sets the loginID.
     *
     * @@param loginID The user's loginID.
     */
    public void setLoginID(String loginID)
    {
        this.loginID = loginID;
    }

    /**
     * Returns the loginID.
     *
     * @@return The user's loginID.
     */
    public String getLoginID()
    {
        return loginID;
    }

    /**
     * The user's userID.
     */
    private String userID = null;

    /**
     * Sets the userID.
     *
     * @@param userID The user's database key.
     */
    public void setUserID(String userID)
    {
        this.userID = userID;
    }

    /**
     * Returns the user's database key.
     *
     * @@return The user's database key.
     */
    public String getUserID()
    {
        return userID;
    }

    /**
     * Returns the user's database key as an <code>Integer</code>.
     *
     * @@return The user's database key.
     */
    public Integer getIntegerUserID()
    {
        return Integer.valueOf(userID);
    }

    /**
     * Returns user's database key as an <code>int</code>.
     *
     * @@return The user's database key.
     */
    public int getIntUserID()
    {
        return Integer.parseInt(userID);
    }

    /**
     * The user's name.
     */
    private String userName = null;

    /**
     * Sets the user's name.
     *
     * @@param userName The user's name.
     */
    public void setUserName(String userName)
    {
        this.userName = userName;
    }

    /**
     * Gets the user's name.
     * @@return The user's name.
     */
    public String getUserName()
    {
        return userName;
    }

    /**
     * Sets the user's email.
     * @@param email The user's email.
     */
    public void setEmail(String email)
    {
        this.email = email;
    }

    /**
     * Returns the user's email.
     *
     * @@return The user's email.
     */
    public String getEmail()
    {
        return email;
    }

    /**
     *  Sets the needToWelcome
     * @@param	needToWelcome  A variable of type boolean
     */
    public void needToWelcome(boolean needToWelcome)
    {
        this.needToWelcome = new Boolean(needToWelcome);
    }

    /**
     *  Returns the needToWelcome
     * @@return	A variable of type Boolean 
     */
    public Boolean needToWelcome()
    {
        return needToWelcome;
    }

    /**
     *  Reset the cancelTargets and redirectContexts to new, empty instances.
     */
    public void resetCancel()
    {
        cancelTargets = new Stack();
        resetRedirectContext();
    }

    /**
     *  Redirect to the cancel page.
     *
     * @@param	context  A variable of type Context
     * @@return	A variable of type String 
     * @@exception	RedirectException
     */
    public String redirectToCancel(Context context)
        throws RedirectException
    {
        if ((cancelTargets == null) || (cancelTargets.empty()))
            return null;

        String cancelTo = null;

        if (DEBUG) Log.debug("redirectToCancel: " + cancelTargets.toString());
        cancelTo = (String)cancelTargets.pop();
        Context savedContext = removeRedirectContext(cancelTo);

        // Check if the current servlet is the cancel-to target, and pop
        // the stack again if so.
        if (cancelTo.equals((String)context.get("servletName")))
        {
            if (cancelTargets.empty())
            {
                cancelTo = null;
                savedContext = null;
            }
            else
            {
                cancelTo = (String) cancelTargets.pop();
                savedContext = removeRedirectContext(cancelTo);
            }
        }

        if (savedContext != null)
        {
            String action = (String) savedContext.get
                (BaseHelmServlet.SAVED_ACTION_KEY);
            context.put("action", action);
            if (DEBUG) Log.debug(">> savedContext action=" + action);
            //context.defaultFormData(savedContext.getFormData());
            context.put(BaseHelmServlet.SAVED_CONTEXT_KEY,
                        savedContext);
            Log.error("saved context: "+savedContext);
            FormCache form = ContextAPI.getFormCache(context);
            FormCache oldForm = ContextAPI.getFormCache(savedContext);
            form.override(oldForm);
        }

        if (DEBUG) Log.debug("redirectToCancel: cancel to: " + cancelTo +
                             " with action: " + context.get("action"));
        return cancelTo;
    }

    /**
     *  Sets the target page of a cancel to the specified page.
     *  If the page is already on the stack, pop the stack until it is the
     *  top-most element.
     *
     * @@param	cancelToPage    the name of the target page for a cancel
     * @@param	context    the Context
     * @@param	action  A variable of type String
     */
    public void setAsCancel(String cancelToPage, Context context,
            String action)
    {
        if (DEBUG) Log.debug("setAsCancel: adding " + cancelToPage +
            " with action: " + context.get("action"));

        // Since we no longer use the Servlet API's deprecated
        // getServlet() method, we're reusing this context -- and
        // whatever was in its action field will get clobbered.  So
        // save whatever the action used to be ...  note that this
        // means multiple internal setAsCancel() calls w/in a single
        // request won't work as expected.
        context.put(BaseHelmServlet.SAVED_ACTION_KEY, action);

        if (cancelTargets == null)
        {
            resetCancel();
        }

        int numPops = cancelTargets.search(cancelToPage);
        if (numPops == -1)
        {
            // Not currently on the stack, so add it.
            cancelTargets.push(cancelToPage);
        }
        else
        {
            if (DEBUG) Log.debug("setAsCancel: already on stack");
            // Currently on stack, so pop stack until it is topmost.
            // Remove any saved contexts for popped servlets.
            String servletName;
            for (int i = 1; i < numPops; i++)
            {
                servletName = (String) cancelTargets.pop();
                removeRedirectContext(servletName);
                if (DEBUG) Log.debug("setAsCancel: popped " + servletName);
            }
        }

        // Save the cancel-to page's context.
        context.put("cancelAction", action);
        setRedirectContext(context);

        if (DEBUG) Log.debug("setAsCancel: " + cancelTargets.toString());
    }

    /**
     *  Sets the target page of a cancel to the specified page with the
     *  current action.
     *
     * @@param	cancelToPage    the name of the target page for a cancel
     * @@param	context    the Context
     */
    public void setAsCancel(String cancelToPage, Context context)
    {
        setAsCancel(cancelToPage, context, "none");
    }

    /**
     *  Removes the specified page as a target of a cancel.
     *  If the page is not on the stack, do nothing; otherwise pop the stack
     *  until it is removed.
     *
     * @@param	cancelToPage    the name of the page to remove
     * @@param	context    the Context
     */
    public void removeAsCancel(String cancelToPage, Context context)
    {
        if (DEBUG) Log.debug("removeAsCancel: " + cancelToPage);

        if ((cancelTargets == null) || (cancelTargets.empty()))
            return;

        int numPops = cancelTargets.search(cancelToPage);

        if (numPops == cancelTargets.size())
        {
            // Rather than popping the whole stack, just create a new one.
            if (DEBUG) Log.debug("setAsCancel: popping whole stack");
            resetCancel();
        }
        else if (numPops != -1)
        {
            // The cancel-to page is on the stack, so pop it and any 
            // intervening pages, along with their saved contexts.
            String servletName;
            for (int i = 1; i <= numPops; i++)
            {
                servletName = (String) cancelTargets.pop();
                removeRedirectContext(servletName);
                if (DEBUG) Log.debug("setAsCancel: popped " + servletName);
            }
        }
        if (DEBUG) Log.debug("removeAsCancel: " + cancelTargets.toString());
    }

    /**
     *  Sets the detourTarget
     * @@param	detourTarget  A variable of type String
     */
    public void detourTarget(String detourTarget)
    {
        this.detourTarget = detourTarget;
    }

    /**
     *  Returns the detourTarget
     * @@return	A variable of type String 
     */
    public String detourTarget()
    {
        return detourTarget;
    }

    /**
     *  Resets the detourTarget
     */
    public void detourTargetReset()
    {
        this.detourTarget = null;
    }

    /**
     *  Redirect to the detour page.
     *
     * @@param	context  A variable of type Context
     * @@return	A variable of type String 
     * @@exception	RedirectException
     */
    public String redirectToDetour(Context context)
        throws RedirectException
    {
        Context savedContext = null;

        String detourTo = detourTarget();
        detourTargetReset();

        // If there is no detour target, bail out right now.
        if (detourTo == null)
            return detourTo;

        if (cancelTargets != null && !cancelTargets.empty())
        {
            if (DEBUG)
                Log.debug("redirectToDetour: " + cancelTargets.toString());
            int numPops = cancelTargets.search(detourTo);

            if (numPops != -1)
            {
                // The cancel-to page is on the stack, so pop any intervening
                // pages, along with their saved contexts.
                String servletName;
                for (int i = 1; i <= numPops; i++)
                {
                    servletName = (String) cancelTargets.pop();
                    savedContext = removeRedirectContext(servletName);
                    if (DEBUG) Log.debug("setAsCancel: popped " + servletName);
                }

                if (savedContext != null)
                {
                    String action = (String)savedContext.get
                        (BaseHelmServlet.SAVED_ACTION_KEY);
                    context.put("action", action);
                    if (DEBUG) Log.debug(">> savedContext action=" + action);
                    //context.defaultFormData(savedContext.getFormData());
                    context.put(BaseHelmServlet.SAVED_CONTEXT_KEY,
                                savedContext);
                    if (DEBUG) Log.debug("saved context: "+savedContext);
                    FormCache form = ContextAPI.getFormCache(context);
                    FormCache oldForm = ContextAPI.getFormCache(savedContext);
                    form.override(oldForm);
                }
            }
            else
            {
                detourTo = null;
            }

            if (DEBUG) Log.debug("redirectToDetour: cancel to: " + detourTo +
                " with action: " + context.get("action"));
        }
        else
        {
            if (DEBUG) Log.debug("redirectToDetour: stack is empty");
            detourTo = null;
        }
        return detourTo;
    }

    /**
     *  Sets the specified page as the origin of a detour.  At some future
     *  point the user will return to this page with its original action.
     *  If the page is already on the stack, pop the stack until it is the
     *  top-most element.
     *
     * @@param	cancelToPage    the name of the target page prior to a detour.
     * @@param	context    the Context
     */
    public void setAsDetour(String cancelToPage, Context context)
    {
        if (DEBUG) Log.debug("setAsDetour: adding " + cancelToPage +
            " with action: " + context.get("action"));

        detourTarget(cancelToPage);
        setAsCancel(cancelToPage, context, (String)context.get("action"));
    }

    /**
     * Dump the <code>redirectContexts</code> Hashtable to the log if
     * <code>DEBUG</code> is set.
     */
    private final void dumpRedirectContexts()
    {
        if (DEBUG)
        {
            String key;
            Enumeration keys = redirectContexts.keys();
            while (keys.hasMoreElements())
            {
                key = (String) keys.nextElement();
                Log.debug(">>> key: " + key + " value: " +
                          redirectContexts.get(key));
            }
        }
    }

    /**
     *  Sets the redirectContext
     * @@param	redirectContext  A variable of type Context
     */
    public void setRedirectContext(Context redirectContext)
    {
        if (DEBUG) Log.debug("Saving a context for " +
            redirectContext.get("servletName"));
        this.redirectContexts.put(redirectContext.get("servletName"),
            redirectContext);
        dumpRedirectContexts();
    }

    /**
     *  Returns the Context
     * @@param	servletName  A variable of type String
     * @@return	A variable of type Context 
     */
    public Context getRedirectContext(String servletName)
    {
        if (DEBUG) Log.debug("Retrieving a context for " + servletName);
        dumpRedirectContexts();
        return (Context)(redirectContexts.get(servletName));
    }

    /**
     *  Removes and returns the Context
     * @@param	servletName  A variable of type String
     * @@return	A variable of type Context 
     */
    public Context removeRedirectContext(String servletName)
    {
        if (DEBUG) Log.debug("Removing a context for " + servletName);
        dumpRedirectContexts();
        return (Context) redirectContexts.remove(servletName);
    }

    /**
     *  Resets the redirectContext
     */
    public void resetRedirectContext()
    {
        redirectContexts = new Hashtable();
    }
}
@


1.7
log
@Added an init() method to the SessionManager class; made use of it in two places.
@
text
@d368 1
a368 1
    public String redirectToCancel (Context context)
d425 1
a425 1
    public void setAsCancel (String cancelToPage, Context context,
d478 1
a478 1
    public void setAsCancel (String cancelToPage, Context context)
d491 1
a491 1
    public void removeAsCancel (String cancelToPage, Context context)
d554 1
a554 1
    public String redirectToDetour (Context context)
d624 1
a624 1
    public void setAsDetour (String cancelToPage, Context context)
d682 1
a682 2
    public Context
    removeRedirectContext(String servletName)
d686 1
a686 1
        return (Context)(redirectContexts.remove(servletName));
@


1.6
log
@Removed Joist reference.
@
text
@d59 1
a120 1
        if (DEBUG) Log.debug("Creating a SessionManager for: " + session);
d125 14
d144 1
a144 1
        isLoggedIn(false);
d198 8
d208 1
a208 1
        this.isLoggedIn = (isLoggedIn ? Boolean.TRUE : Boolean.FALSE);
@


1.5
log
@Removed Joist dependancies.
@
text
@d409 6
a414 5
        // Since we no longer use getServlet in joist, we're reusing
        // this context -- and whatever was in its action field will
        // get clobbered.  So save whatever the action used to be ...
        // note that this means multiple internal setAsCancel calls
        // w/in a single request won't work as expected.
@


1.4
log
@Ported Joist Redirect*Exception to Helm.
@
text
@a58 1
import org.joist.util.FormTool;
d60 1
a60 1
import org.joist.security.UnsecureServlet;
d377 1
a377 1
                (UnsecureServlet.SAVED_ACTION_KEY);
d381 1
a381 1
            context.put(UnsecureServlet.SAVED_CONTEXT_KEY,
d414 1
a414 1
        context.put(UnsecureServlet.SAVED_ACTION_KEY, action);
d564 1
a564 1
                        (UnsecureServlet.SAVED_ACTION_KEY);
d568 1
a568 1
                    context.put(UnsecureServlet.SAVED_CONTEXT_KEY,
@


1.3
log
@Import Helm FormCache (moved in from Joist).
@
text
@d62 1
a62 1
import org.joist.security.RedirectException;
@


1.2
log
@Made use of new ContextAPI.getFormCache() method.
@
text
@d60 1
a60 1
import org.joist.util.FormCache;
@


1.1
log
@Helm-specific session manager (to nurse along our SessionManager dependancy until we can finally get rid of reference to it in templates).
@
text
@d377 2
a378 2
            String action = (String)savedContext.get(
                    UnsecureServlet.SAVED_ACTION_KEY);
d381 2
a382 4
            try
            {
                //context.defaultFormData(savedContext.getFormData());
                context.put(UnsecureServlet.SAVED_CONTEXT_KEY,
d384 4
a387 9
                Log.error("saved context: "+savedContext);
                FormCache form = (FormCache)context.getTool("Form");
                FormCache oldForm =(FormCache)savedContext.getTool("Form");
                form.override(oldForm);
            }
            catch (ContextException e)
            {
                Log.error(e);
            }
d568 2
a569 3
                    try {
                        //context.defaultFormData(savedContext.getFormData());
                        context.put(UnsecureServlet.SAVED_CONTEXT_KEY,
d571 4
a574 9
                        if (DEBUG) Log.debug("saved context: "+savedContext);
                        FormCache form = (FormCache)context.getTool("Form");
                        FormCache oldForm =
                            (FormCache)savedContext.getTool("Form");
                        form.override(oldForm);
                    }
                    catch (ContextException e) {
                        Log.error(e);
                    }
@

