head	1.66;
access;
symbols
	TIGRIS_1_1_0RC2:1.2.2.1.2.1
	TIGRIS_1_1_0RC1:1.2.2.1
	TIGRIS_1_1:1.2.2.1.0.2
	TIGRIS_1_0_8:1.2.2.1
	TIGRIS_1_0_8RC3:1.2.2.1
	TIGRIS_1_0_8RC2:1.2.2.1
	TIGRIS_1_0_8RC1:1.2.2.1
	TIGRIS_1_0_7:1.2.2.1
	TIGRIS_1_0_7RC3:1.2.2.1
	TIGRIS_1_0_7RC2:1.2.2.1
	TIGRIS_1_0_7RC1:1.2.2.1
	TIGRIS_1_0_6:1.2.2.1
	TIGRIS_1_0_6RC5:1.2.2.1
	TIGRIS_1_0_6RC4:1.2.2.1
	TIGRIS_1_0_6RC3:1.2.2.1
	TIGRIS_1_0_6RC2:1.2.2.1
	TIGRIS_1_0_6RC1:1.2.2.1
	TIGRIS_1_0_5:1.2.2.1
	TIGRIS_1_0_5RC6:1.2.2.1
	TIGRIS_1_0_5RC5:1.2.2.1
	TIGRIS_1_0_5RC4:1.2.2.1
	TIGRIS_1_0_5RC3:1.2.2.1
	TIGRIS_1_0_5RC2:1.2.2.1
	TIGRIS_1_0_5RC1:1.2.2.1
	TIGRIS_1_0_4:1.2.2.1
	TIGRIS_1_0_3:1.2.2.1
	TIGRIS_1_0:1.2.0.2;
locks; strict;
comment	@# @;


1.66
date	2001.08.30.17.57.12;	author leonardr;	state Exp;
branches;
next	1.65;

1.65
date	2001.08.29.00.43.19;	author dlr;	state Exp;
branches;
next	1.64;

1.64
date	2001.08.28.22.39.35;	author dlr;	state Exp;
branches;
next	1.63;

1.63
date	2001.08.28.21.48.49;	author dlr;	state Exp;
branches;
next	1.62;

1.62
date	2001.08.28.21.48.01;	author dlr;	state Exp;
branches;
next	1.61;

1.61
date	2001.08.28.18.12.23;	author leonardr;	state Exp;
branches;
next	1.60;

1.60
date	2001.08.28.17.45.18;	author leonardr;	state Exp;
branches;
next	1.59;

1.59
date	2001.08.28.17.13.34;	author leonardr;	state Exp;
branches;
next	1.58;

1.58
date	2001.08.28.01.36.38;	author leonardr;	state Exp;
branches;
next	1.57;

1.57
date	2001.08.28.01.09.34;	author leonardr;	state Exp;
branches;
next	1.56;

1.56
date	2001.08.28.00.56.13;	author leonardr;	state Exp;
branches;
next	1.55;

1.55
date	2001.08.27.23.18.26;	author leonardr;	state Exp;
branches;
next	1.54;

1.54
date	2001.08.16.00.45.18;	author dlr;	state Exp;
branches;
next	1.53;

1.53
date	2001.08.11.18.05.30;	author dlr;	state Exp;
branches;
next	1.52;

1.52
date	2001.08.11.09.08.08;	author dlr;	state Exp;
branches;
next	1.51;

1.51
date	2001.08.08.19.29.09;	author leonardr;	state Exp;
branches;
next	1.50;

1.50
date	2001.08.08.18.32.49;	author leonardr;	state Exp;
branches;
next	1.49;

1.49
date	2001.07.24.00.02.28;	author leonardr;	state Exp;
branches;
next	1.48;

1.48
date	2001.07.23.20.04.37;	author dlr;	state Exp;
branches;
next	1.47;

1.47
date	2001.07.23.20.02.53;	author dlr;	state Exp;
branches;
next	1.46;

1.46
date	2001.07.19.20.13.18;	author dlr;	state Exp;
branches;
next	1.45;

1.45
date	2001.07.19.19.54.05;	author dlr;	state Exp;
branches;
next	1.44;

1.44
date	2001.07.19.19.08.43;	author dlr;	state Exp;
branches;
next	1.43;

1.43
date	2001.07.19.18.42.22;	author dlr;	state Exp;
branches;
next	1.42;

1.42
date	2001.07.18.23.20.43;	author leonardr;	state Exp;
branches;
next	1.41;

1.41
date	2001.07.18.16.04.11;	author leonardr;	state Exp;
branches;
next	1.40;

1.40
date	2001.07.18.10.05.15;	author dlr;	state Exp;
branches;
next	1.39;

1.39
date	2001.07.17.23.20.23;	author leonardr;	state Exp;
branches;
next	1.38;

1.38
date	2001.07.17.20.54.06;	author leonardr;	state Exp;
branches;
next	1.37;

1.37
date	2001.07.17.20.22.46;	author leonardr;	state Exp;
branches;
next	1.36;

1.36
date	2001.07.17.17.55.45;	author leonardr;	state Exp;
branches;
next	1.35;

1.35
date	2001.07.17.16.00.43;	author leonardr;	state Exp;
branches;
next	1.34;

1.34
date	2001.07.16.23.22.09;	author leonardr;	state Exp;
branches;
next	1.33;

1.33
date	2001.07.16.22.36.27;	author leonardr;	state Exp;
branches;
next	1.32;

1.32
date	2001.07.13.21.56.41;	author leonardr;	state Exp;
branches;
next	1.31;

1.31
date	2001.07.13.21.47.11;	author leonardr;	state Exp;
branches;
next	1.30;

1.30
date	2001.07.13.19.47.34;	author leonardr;	state Exp;
branches;
next	1.29;

1.29
date	2001.07.12.20.10.49;	author leonardr;	state Exp;
branches;
next	1.28;

1.28
date	2001.07.12.00.50.17;	author leonardr;	state Exp;
branches;
next	1.27;

1.27
date	2001.07.11.23.13.30;	author leonardr;	state Exp;
branches;
next	1.26;

1.26
date	2001.07.09.15.21.16;	author leonardr;	state Exp;
branches;
next	1.25;

1.25
date	2001.07.03.23.21.51;	author ms;	state Exp;
branches;
next	1.24;

1.24
date	2001.06.07.19.06.51;	author elicia;	state Exp;
branches;
next	1.23;

1.23
date	2001.06.07.03.07.20;	author elicia;	state Exp;
branches;
next	1.22;

1.22
date	2001.06.07.00.24.25;	author dlr;	state Exp;
branches;
next	1.21;

1.21
date	2001.06.04.01.33.57;	author dlr;	state Exp;
branches;
next	1.20;

1.20
date	2001.05.30.21.51.16;	author dlr;	state Exp;
branches;
next	1.19;

1.19
date	2001.05.25.20.46.47;	author dlr;	state Exp;
branches;
next	1.18;

1.18
date	2001.05.25.00.04.46;	author dlr;	state Exp;
branches;
next	1.17;

1.17
date	2001.05.24.23.42.07;	author dlr;	state Exp;
branches;
next	1.16;

1.16
date	2001.05.24.23.00.39;	author dlr;	state Exp;
branches;
next	1.15;

1.15
date	2001.05.24.22.59.05;	author dlr;	state Exp;
branches;
next	1.14;

1.14
date	2001.05.24.22.53.36;	author dlr;	state Exp;
branches;
next	1.13;

1.13
date	2001.05.24.22.40.52;	author dlr;	state Exp;
branches;
next	1.12;

1.12
date	2001.05.24.22.39.51;	author dlr;	state Exp;
branches;
next	1.11;

1.11
date	2001.05.24.21.06.43;	author dlr;	state Exp;
branches;
next	1.10;

1.10
date	2001.05.24.18.49.38;	author dlr;	state Exp;
branches;
next	1.9;

1.9
date	2001.05.24.18.37.28;	author dlr;	state Exp;
branches;
next	1.8;

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

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

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

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

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

1.3
date	2001.05.04.18.34.30;	author leonardr;	state Exp;
branches;
next	1.2;

1.2
date	2001.04.17.07.49.23;	author dlr;	state Exp;
branches
	1.2.2.1;
next	1.1;

1.1
date	2001.04.17.00.19.40;	author leonardr;	state Exp;
branches;
next	;

1.2.2.1
date	2001.04.25.23.48.39;	author dlr;	state Exp;
branches
	1.2.2.1.2.1;
next	;

1.2.2.1.2.1
date	2001.08.09.02.19.22;	author jrobbins;	state Exp;
branches;
next	;


desc
@@


1.66
log
@Servlet configuration is now part of component configuration. ComponentTools and ComponentTool provide an interface to component configuration and will be used in templates to process component-specific template fragments.
@
text
@/* ================================================================
 * Copyright (c) 2001 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.collab.net/)."
 * 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 COLLABNET 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.security;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.util.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import javax.servlet.*;
import javax.servlet.http.*;

import org.apache.commons.collections.ExtendedProperties;
import org.apache.commons.util.exception.NestableException;
import org.apache.commons.util.StringUtils;

import org.apache.log4j.Category;

import org.apache.turbine.RunData;
import org.apache.turbine.services.rundata.RunDataService;
import org.apache.turbine.services.rundata.TurbineRunDataService;
import org.apache.turbine.Turbine;
import org.apache.turbine.util.TurbineConfig;

import org.apache.fulcrum.TurbineServices;
import org.apache.fulcrum.ServiceManager;

import org.apache.fulcrum.velocity.TurbineVelocity;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.HttpServletResponseWrap;
import org.apache.velocity.context.Context;

import org.tigris.helm.AlreadyExists;
import org.tigris.helm.DoesNotExist;
import org.tigris.helm.om.*;
import org.tigris.helm.domain.*;
import org.tigris.helm.component.ComponentTools;
import org.tigris.helm.tool.ContextAPI;
import org.tigris.helm.tool.FormCache;
import org.tigris.helm.tool.HelmProperties;
import org.tigris.helm.tool.MemorySentinel;
import org.tigris.helm.tool.ServletHelp;
import org.tigris.helm.tool.SessionManager;
import org.tigris.helm.tool.VelocityEventCartridge;
import org.tigris.helm.tool.WebStats;
import org.tigris.helm.tool.paginate.PeerBackedList;
import org.tigris.helm.util.FileUtil;
import org.tigris.helm.util.PropertiesUtil;
import org.apache.turbine.util.Log;
import org.tigris.helm.util.URL;

/**
 * A basic Helm layer originally based on Joist's UnsecureServlet.
 *
 * @@author <a href="mailto:leonardr@@collab.net">Leonard Richardson</a>
 * @@author <a href="mailto:dlr@@collab.net">Daniel Rall</a>
 * @@author <a href="mailto:davidp@@collab.net">David Pellegrini</a>
 * @@version $Id: BaseHelmServlet.java,v 1.65 2001/08/29 00:43:19 dlr Exp $
 *
 * Copyright (c) 2001 CollabNet, Inc.
 */
public abstract class BaseHelmServlet extends HttpServlet
{
    /**
     * Turn debug log output on/off
     */
    private static final boolean DEBUG = false;

    /**
     * Used to when internal redirects require making an old context
     * available.
     */
    public static final String SAVED_CONTEXT_KEY = "JOIST_REDIRECTED_CONTEXT";

    /**
     * Used when internal redirects are; this is a (somewhat limited)
     * way to provide the old action to the new context.  The limit is
     * that the current implementation doesn't allow multiple redirects
     * w/in a single HTTP requests.
     */
    public static final String SAVED_ACTION_KEY = "JOIST_REDIRECTED_ACTION";

    /**
     * The context key used for the per-screen user message.
     */
    protected static final String MESSAGE_KEY = "Message";

    /**
     * The action CGI/context key.
     */
    protected static final String ACTION_KEY = "action";

    /**
     * The alterante action CGI/context key.
     */
    protected static final String BUTTON_KEY = "Button";

    /**
     * Context key for the current broadcast message
     */
    public static final String BROADCAST_MESSAGE_KEY = "broadcastMessage";

    /**
     * A constant for the empty {@@link java.lang.String} object sometimes
     * supplied to the context by <code>processField</code>.
     */
    private static final String EMPTY_STRING = "";

    /**
     * The properties key to the default servlet zone mount point.
     */
    private static final String DEF_MNT_PT = "servletZone.mountPoint.default";

    /**
     * Read in a servlet-specific properties file and populate this
     * variable.  We may want to set up app-wide properties, which
     * would be the default for the servlet-specific properties.
     * This is the portion of the TurbineResources.properties file
     * given over to properties for this servlet.
     */
    protected Properties myProperties;

    /**
     * The servlet-specific default template name.
     */
    protected String masterTemplateName = null;

    /**
     * Flag indicating whether operating in a production environment.
     * If set to false, specifies server development mode, as opposed to
     * completed, tested, and ready to release to the world mode.
     */
    protected boolean inProductionEnvironment = false;

    /**
     * The HTTP port.
     */
    protected final String HTTP_PORT = URL.DEFAULT_HTTP_PORT.toString();

    /**
     * Hit counter for servlets.
     */
    private static WebStats webStats = null;

    /**
     * Key to pull webStats on/off property.
     */
    private final static String GATHER_WEB_STATS_KEY = "webStats.gather";

    /** Whether to do webstats.
     */
    private static boolean boolWebStats = false;

    /**
     * Cache for Servlet instances.
     */
    private static Hashtable servletCache = new Hashtable();

    /**
     * The context key for a string consisting of a protocol and server name.
     */
    private static final String HTTP_AND_SERVER_KEY = "httpAndServer";

    /**
     * The context key for a string consisting of the current protocol
     * and the domain name.
     */
    private static final String SCHEME_AND_DOMAIN_KEY = "schemeAndDomain";

    /**
     * Whether <a href="http://java.apache.org/turbine/">Turbine</a> has been
     * initialized.
     */
    private static boolean turbineInitialized = false;

    /**
     * Performs tasks common to all servlets, such as recording the
     * page hit, servlet specific processing, and populating the
     * template with values.
     *
     * @@param context The Context to populate.
     * @@return        The name of the template for formatting the
     *                Context data.
     *
     * @@exception NestableException Any runtime error.  
     */
    public String handle (Context context, HttpServletResponse res)
        throws NestableException
    {
        String templateName;
        Template template = null;

        long startTime = 0;
        if (DEBUG) 
        {
            startTime = new Date().getTime();
        }

        // Record the hit.
        if (webStats != null) 
        {
            webStats.addHit();
        }

        // Retrieve or set up the session manager as necessary.
        SessionManager sMgr = getSessionManager(context);

        try
        {
            // Do servlet-specific processing ...
            try
            {
                // Process the request; this is where the real work is done.
                // Put data into the context and return a template name.
                //
                // NOTE: If the call to processRequest returns a null template
                // name, let this be a signal that the servlet called w/ 
                // processRequest handled the request completly taking care of
                // writing the response; there is no more work to be done on 
                // the response.
                templateName = null;
                try 
                {
                    if (DEBUG) 
                    {
                        Log.debug("About to process request for " +
                                  getServletName());
                    }
                    templateName = processRequest(context);
                    if (DEBUG) 
                    {
                        Log.debug("Completed processing request for " +
                                  getServletName());
                    }
                }
                catch (NestableException e)
                {
                    //The servlet threw an exception; display
                    //its message (if in production environment)
                    //or its stack trace (if not) as a fatal error.
                    Log.error(e);
                    String message = e.getMessage();
                    if (!(e instanceof DoesNotExist 
                          || e instanceof AlreadyExists) 
                        && "false".equals(myProperties.getProperty
                                          ("inProductionEnvironment")))
                    {
                        message = "<pre>" + StringUtils.stackTrace(e) 
                            + "</pre>";
                    }
                    ContextAPI.addFatalError(context, message);
                    redirectToError(context, "");
                }

                if (templateName != null)
                {
                    // Process the template.
                    TurbineVelocity.handleRequest(context, templateName, 
                                                  res.getOutputStream());
                }
            }
            catch (RedirectURLException e)
            {
                // Nothing more to be done.
            }
            catch (RedirectException e)
            {
                // Get the name of the servlet to which to redirect.
                ServletContext servletContext = getServletContext();
                String shortServletName = e.getMessage();
                String servletName = shortServletName;
                context.put("redirectException", e);

                if ("ErrorPage".equals(getServletName())
                    && "ErrorPage".equals(servletName))
                {
                    throw new Error("Endless ErrorPage redirect detected!");
                }

                // if we've got interesting info, show it
                String dump = e.dump();
                if (dump != null && !dump.equals(servletName)) 
                {
                    Log.debug("RedirectException dump: " + dump);
                }

                // get the full class name from the conf/servlets file
                servletName = myProperties.getProperty
                    ("servlet." + servletName + ".code");
                
                if (DEBUG) 
                {
                    Log.debug ("Redirect servletName: " + servletName );
                }

                // could not find the servlet in the conf/servlets file
                if (!StringUtils.isValid(servletName))
                {
                    throw new NestableException
                        ("Could not find the servlet class in the " +
                         "conf/servlets file");
                }

                // Get the instance of the servlet by its name.
                BaseHelmServlet redirect = null;
                try
                {
                    // check the cache first
                    if (servletCache.containsKey(servletName))
                    {
                        redirect = 
                            (BaseHelmServlet) servletCache.get(servletName);
                    }
                    else
                    {
                        // create an instance of the servlet
                        redirect = (BaseHelmServlet)
                            Class.forName(servletName).newInstance();
                        redirect.init(getServletConfig());
                        servletCache.put(servletName, redirect);
                    }
                }
                catch (Exception se)
                {
                    throw new NestableException(se);
                }

                // Have the redirect-to servlet handle the "request".
                if (DEBUG)
                {
                    Log.debug("Redirect class name: " +
                              redirect.getClass().getName());
                }

                templateName = redirect.handle(context, res);
            }
        }
        catch (Exception e)
        {
            // Catch-all for otherwise unhandled exceptions.
            if (DEBUG)
            {
                Log.debug("BaseHelmServlet: Unhandled exception in the " + 
                          "handle() method: " + e.getMessage());
            }
            Log.error(e);
            ContextAPI.addFatalError(context, e.getMessage());
            throw new NestableException(e);
        }

        if (DEBUG) 
        {
            long endTime = new Date().getTime();
            long elapsed = endTime - startTime;
            Log.debug("Request processed in " + elapsed + " milliseconds.");
        }

        return null;
    }

    /**
     * This is the old-style init method, it just calls init(), after
     * handing the ServletConfig object to the superclass
     *
     * @@exception ServletException Servlet failed to initialize.
     */
    public final synchronized void init(ServletConfig sc)
        throws ServletException 
    {
        super.init(sc);
        init();
    }

    /**
     * This method is called by the servlet runner--do not call it.
     *
     * @@exception ServletException Servlet failed to initialize.
     */
    public final synchronized void init()
        throws ServletException 
    {
        start();
    }

    /**
     * Process an incoming GET request: Builds a Context up and then 
     * passes it to the handle() method. You can overide this if you want,
     * though for most purposes you are expected to overide handle() 
     * instead.
     * <p>
     * @@param req The request we got.
     * @@param res The response we are generating.
     *
     * @@exception ServletException We can't get our configuration.
     * @@exception IOException      We can't read/write to the streams we got.
     */
    protected void doGet(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException
    { 
        doRequest(req, res);
    }

    /**
     * Behaves exactly like doGet() except that it reads data from POST
     * before doing exactly the same thing. This means that you can use 
     * GET and POST interchangeably with WebMacro. You can overide this if
     * you want, though for most purposes you are expected to overide 
     * handle() instead.
     * <p>
     * @@param req The request we got.
     * @@param res The response we are generating.
     *
     * @@exception ServletException We can't get our configuration.
     * @@exception IOException      We can't read/write to the streams we got.
     */
    protected void doPost(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException
    { 
        doRequest(req, res);
    }

    private void doRequest(HttpServletRequest req, HttpServletResponse res)
    {
        try
        {
            TurbineRunDataService rds = (TurbineRunDataService) TurbineServices
                .getInstance().getService(RunDataService.SERVICE_NAME);
            RunData data = rds.getRunData(req, res, getServletConfig());
            //Log.debug("TurbineRunDataService returned " + data);
            Context context = new VelocityContext();
            ContextAPI.putData(context, data);

            String templateName = handle(context, res);
            if (templateName != null)
            {
                TurbineVelocity.handleRequest(context, templateName,
                                              res.getOutputStream());
            }
        }
        catch (Exception e)
        {
            Log.warn("Your handler was unable to successfully process the " +
                     "request", e);
        }
    }

    /**
     * Does whatever processing is necessary to fill the Context instance
     * with objects to be used to fill in the template.  The value in the
     * Context keyed by the String "action" will always be filled by this
     * method.  The values corresponding to the CGI keys "action" and "Button"
     * are checked (in that order, with a default of "none"), and resulting
     * value is stuffed into the Context and keyed by "action".
     * This method can also decide to use another template entirely.
     * In addition, it caches the session info and handles redirects.
     * <p>
     * Subclasses should both override and invoke this method.
     *
     * @@param    context   the Context partially populated by WMServlet
     * @@return     the name of the Template for formatting the Context data
     * @@exception    HandlerException
     * @@exception    RedirectException
     */
    protected String processRequest(Context context)
        throws NestableException, RedirectException
    {
        RunData runData = ContextAPI.getRunData(context);
        HttpServletRequest request = runData.getRequest();
        HttpServletResponse response = runData.getResponse();
        SessionManager sMgr = getSessionManager(context);

        // Set the default Content-Type: text/html
        response.setContentType("text/html");

        // Cache some session info in the context.
        context.put("res", new HttpServletResponseWrap(response));
        context.put("isLoggedIn", sMgr.isLoggedIn());
        String servletName = getServletName();
        context.put("servletName", servletName);
        String displayName = myProperties.getProperty("displayName");
        context.put("displayName", displayName);
        String shortDisplayName = myProperties.getProperty("shortDisplayName");
        if (shortDisplayName == null)
        {
            shortDisplayName = displayName;
        }
        context.put("shortDisplayName", shortDisplayName);
        if (DEBUG) Log.debug(">> Starting servlet: " + servletName);
        context.put("myProperties", myProperties);
        if (DEBUG) Log.debug(">> BRANDSITE: " +
                             myProperties.getProperty("BRANDSITE"));
        context.put("joistFileUtil", new FileUtil());

        //Adding the TIGRIS_VERSIOn, TIGRIS_BUILD_NUMBER and the instance
        //into the context
        context.put("tigrisVersion",
                    myProperties.getProperty("TIGRIS_VERSION"));
        context.put("tigrisBuildNumber",
                    myProperties.getProperty("TIGRIS_BUILD_NUMBER"));
        context.put("tigrisBuildInstance",
                    myProperties.getProperty("tigrisBuildInstance"));
        context.put("hostname",myProperties.getProperty("hostname"));
        
        // Check whether we need to redirect based on protocol (scheme).
        String currentScheme = request.getScheme();

        // check for a global forceServletScheme before using the
        // servlet's individual scheme
        String servletScheme = myProperties.getProperty("forceServletScheme");
        if (servletScheme == null) {
            servletScheme = myProperties.getProperty("servletScheme");
        }

        //REM: if (DEBUG) Log.debug("[ ] current scheme: " + currentScheme +
        //REM:     "\tport: " + currentPort);
        if (DEBUG) Log.debug("[ ] servlet scheme: " + servletScheme);
        if (!servletScheme.equals(currentScheme) && inProductionEnvironment)
        {
            // Redirect with servlet scheme.
            redirectForScheme(context, servletScheme, servletName);
        }

        // Stash the form action in the context if it's not there already.
        String action = (String) context.get(ACTION_KEY);
        if (action == null)
        {
            action = getAction(context);
            context.put(ACTION_KEY, (action == null ? "none" : action));
        }
        if (DEBUG) Log.debug(">> action=" + action);

        // Retrieve the existing context if this is a redirect
        String redirect = (String) context.get("redirect");
        if (redirect != null && redirect.equals("SSL"))
        {
            // Remove the SSL redirect from the form data.
            if (DEBUG) Log.debug("Removing SSL redirect from formData");
            FormCache formCache = ContextAPI.getFormCache(context);
            formCache.remove("redirect");

            Context original = sMgr.removeRedirectContext(servletName);
            if (original != null)
            {
                action = (String)original.get(SAVED_ACTION_KEY);
                context.put(ACTION_KEY, action);

                if (DEBUG) Log.debug(">> original action=" + action);
                //context.defaultFormData(original.getFormData());
                context.put(SAVED_CONTEXT_KEY, original);
                if (DEBUG) Log.debug("original context: "+original);
                FormCache form = ContextAPI.getFormCache(context);
                FormCache oldForm = ContextAPI.getFormCache(original);
                form.override(oldForm);
            }
            else
            {
                if (DEBUG) Log.debug("After SSL redirect, no context saved");
                redirectToCancel(context);
            }
        }

        // Get the servlet-specific sub-template that plugs into the
        // standard template, and put it into the context.  In a production
        // environment, bypass the standard template and get the raw
        // application servlet specific template.

        // TODO: Retire SERVLET_TEMPLATE_ROOT from use.
        String servletTemplateRoot =
            myProperties.getProperty("SERVLET_TEMPLATE_ROOT");
        context.put("SERVLET_TEMPLATE_ROOT", servletTemplateRoot);

        // TODO: Retire BRAND_TEMPLATE_ROOT from use.
        String brandTemplateRoot =
            myProperties.getProperty("BRAND_TEMPLATE_ROOT");
        context.put("BRAND_TEMPLATE_ROOT", brandTemplateRoot);

        String documentRoot = myProperties.getProperty("documentRoot");
        context.put("documentRoot", documentRoot);
        
        String servletTemplate = myProperties.getProperty("template");
        if (servletTemplate == null)
        {
            Log.debug("No template specified, building one.");
            String component = myProperties.getProperty("component");
            Log.debug("Component: " + component);
            String componentDirectory = (String)ComponentTools.singleton
                .getTool(component).getDirectory();
            String templatePackage = myProperties.getProperty("package");
            servletTemplate = componentDirectory + File.separatorChar 
                + templatePackage + File.separatorChar + servletName + ".vm";
        }

        //if (DEBUG) Log.debug("servlet template: " + servletTemplate);
        Log.debug("servlet template: " + servletTemplate);
        context.put("servletTemplate", servletTemplate);

        context.put("myProperties", myProperties);
        context.put("BRANDSITE", myProperties.getProperty("BRANDSITE"));
        String httpAndServer =
            URL.httpAndServer(ContextAPI.getRequest(context)).toString();
        context.put(HTTP_AND_SERVER_KEY, httpAndServer);
        context.put(SCHEME_AND_DOMAIN_KEY,
                    URL.schemeAndDomain(ContextAPI.getRequest(context)));

        // Put following into context specifically for a webmacro test whether
        // to show search or not but they maybe of general utility.
        if ( haveValue( request.getPathInfo() ) )
            context.put( "PATH_INFO", request.getPathInfo( ) );
        if ( haveValue( request.getServletPath() ) )
            context.put( "SCRIPT_NAME", request.getServletPath( ) );
        if ( haveValue( request.getQueryString() ) )
            context.put( "QUERY_STRING", request.getQueryString( ) );
 
        // HELP: Yipes!  Why are we relying on a form variable?
        String vhost = ContextAPI.getParameter(context, "project");

        // If no virtual host is set, attempt to guess it from the host name.
        if (!StringUtils.isValid(vhost))
        {
            // Guess at whether we're running vhosted.
            int dot = httpAndServer.indexOf('.', 7);
            vhost = (dot == -1 ?
                     httpAndServer.substring(7) :
                     httpAndServer.substring(7, dot));
        }

        context.put("vhost", vhost);

        // Handle the "Cancel" action right away
        if (action != null && action.equals("Cancel"))
        {
            redirectToCancel(context);
        }

        // Remove the current servlet as the cancel-to target.
        removeAsCancel(context);

        populateWithBroadcastMessage(context);

        // Format date to YYYY-MM-DD.
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        context.put("todayDate", df.format(new java.util.Date()));

        // setup velocity exception handler
        VelocityEventCartridge vCart = new VelocityEventCartridge();
        context = vCart.init(context);
        
        // Use the default template to start with. Another template could
        // be substituted before we're done.

        return masterTemplateName;
    }

    /**
     * Populates the context with the current broadcast message.
     */
    protected void populateWithBroadcastMessage(Context context)
        throws NestableException
    {
        try
        {
            Message message = MessagePeer.getBroadcastMessage();
            String broadcast = null;
            if (message != null)
            {
                broadcast = message.getMessageText();
            }
            context.put(BROADCAST_MESSAGE_KEY,
                        broadcast == null ? EMPTY_STRING : broadcast);
        }
        catch (Exception e)
        {
            throw new NestableException(e);
        }
    }

    /**
     *  Redirect to use a different scheme, such as http or https.
     *
     * @@param    context    A Context partially populated by WMServlet
     * @@param    newScheme    the scheme to use
     * @@param    servletName  The name of the servlet to redirect to
     * @@exception    HandlerException
     * @@exception    RedirectURLException
     */
    protected void redirectForScheme (Context context, String newScheme, 
                                      String servletName)
        throws NestableException, RedirectURLException
    {
        if (DEBUG) Log.debug("redirectForScheme: to " + servletName);
        try
        {
            HttpServletResponse response =
                ContextAPI.getRunData(context).getResponse();
            HttpServletRequest request = ContextAPI.getRequest(context);

            // Save the old context for the return request.
            SessionManager sMgr = getSessionManager(context);
            sMgr.setRedirectContext(context);

            // Construct a "redirect" URL
            String serverName = request.getServerName();

            // if we are in development only, don't use HTTPS
            if (newScheme.equals("https") && !inProductionEnvironment)
                newScheme = "http";

            String port = "";
            String uri = request.getRequestURI();
            String queryString = "?redirect=SSL";
            int mountPointEnd = uri.lastIndexOf('/') + 1;
            String mountPoint = (mountPointEnd > 1 ?
                                 uri.substring(0, mountPointEnd) :
                                 HelmProperties.getProperty(DEF_MNT_PT));
            String newURL = newScheme + "://" + serverName + port + mountPoint
                + servletName + queryString;
            newURL = response.encodeRedirectUrl(newURL);
            if (DEBUG) Log.debug("redirectForScheme w/ id: " + newURL);
            response.sendRedirect(newURL);
            throw new RedirectURLException();
        }
        catch (IOException e)
        {
            if (DEBUG) Log.debug("redirectForScheme: " + e.getMessage());
            throw new NestableException(e);
        }
    }


    /**
     * Redirect to the site home page.  Construct the home page URL from
     * properties specified in <code>zone.properties</code>.  If the port
     * number is not port 80, include it in the URL.
     *
     * @@param context The Context partially populated by WMServlet.
     *
     * @@exception HandlerException
     * @@exception RedirectURLException
     */
    protected void redirectToHomePage (Context context)
        throws NestableException, RedirectURLException
    {
        try
        {
            // Build the new URL from properties, leaving off port 80.
            StringBuffer newURL = new StringBuffer("http://");
            newURL.append(HelmProperties.getProperty("hostname"));
            String port = HelmProperties.getProperty("http_port");
            if (!port.equals("80")) newURL.append(':').append(port);
            newURL.append(HelmProperties.getProperty("HomePage"));
            if (DEBUG) Log.debug("redirectToHomePage: " + newURL);

            // Redirect
            HttpServletResponse response =
                ContextAPI.getRunData(context).getResponse();
            response.sendRedirect
                (response.encodeRedirectUrl(newURL.toString()));
            throw new RedirectURLException();
        }
        catch (IOException e)
        {
            if (DEBUG) Log.debug("redirectToHomePage: " + e.getMessage());
            throw new NestableException(e);
        }
    }


    /**
     * Redirect to the specified URL.  Does <i>not</i> make the provided
     * context available in the next URL/servlet.
     *
     * @@param context   The Context partially populated by WMServlet.
     * @@param targetURL The URL to redirect to.
     *
     * @@exception HandlerException
     * @@exception RedirectURLException
     */
    protected void redirectToURL (Context context, String targetURL)
        throws RedirectURLException, RedirectException
    {
        if (DEBUG) Log.debug("redirectToURL: " + targetURL);
        HttpServletResponse response =
            ContextAPI.getRunData(context).getResponse();
        try
        {
            response.sendRedirect(response.encodeRedirectUrl(targetURL));
        }
        catch (IOException e)
        {
            redirectToError(context, e.getMessage());
        }

        // Exception thrown to stop processing and jump to the end of handle().
        // This is essentially being used as a goto.
        throw new RedirectURLException(targetURL);
    }


    /**
     * Redirect to another page.  <i>Does</i> preserve context data.
     *
     * @@param targetURL The URL to redirect to.
     *
     * @@exception HandlerException
     * @@exception RedirectException
     */
    protected void redirectTo (String targetPage)
        throws RedirectException
    {
        if (DEBUG) Log.debug("redirectTo: " + targetPage);
        throw new RedirectServletException(targetPage);
    }


    /**
     * Redirect to the UnauthorizedAccess page.
     *
     * @@exception RedirectException
     */
    protected void redirectToUnauthorized ()
        throws RedirectException
    {
        throw new RedirectServletException("UnauthorizedAccess");
    }


    /**
     * Redirect to the Error page.
     *
     * @@param context The Context partially populated by WMServlet.
     * @@param message The text message to display as an error message.
     *
     * @@exception RedirectException
     */
    protected void redirectToError (Context context, String message)
        throws RedirectException
    {
        if (DEBUG) Log.debug("Redirecting to error screen: " + message);

        //NOTE: This check may no longer be neccessary, since it
        //happens in process(). However, redirectToError 
        if ("ErrorPage".equals(message))
        {
            throw new Error("Endless ErrorPage redirect detected!");
        }
        else
        {
            context.put(MESSAGE_KEY, message);
            throw new RedirectServletException("ErrorPage");
        }
    }


    /**
     * Redirect to the cancel page.
     *
     * @@param context The Context partially populated by WMServlet.
     *
     * @@exception HandlerException
     * @@exception RedirectException
     */
    protected void redirectToCancel (Context context)
        throws NestableException, RedirectException
    {
        String cancelPage =
            getSessionManager(context).redirectToCancel(context);

        if (cancelPage != null)
        {
            if (DEBUG) Log.debug("redirectToCancel: " + cancelPage);
            redirectTo(cancelPage);
        }
        else
        {
            if (DEBUG) Log.debug("redirectToCancel: setting action=none");
            context.put(ACTION_KEY, "none");

            if (((Boolean) context.get("isLoggedIn")).booleanValue())
                redirectTo(myProperties.getProperty("startServletName"));
            else
                redirectToHomePage(context);
        }
    }


    /**
     * Sets the target page of a cancel to the specified page.
     *
     * @@param context The Context partially populated by WMServlet.
     */
    protected void setAsCancel (Context context)
    {
        String cancelToPage = (String)context.get("servletName");
        getSessionManager(context).setAsCancel(cancelToPage, context);
    }


    /**
     *  Sets the target page of a cancel to the specified page and action.
     *
     * @@param context      The Context partially populated by WMServlet.
     * @@param cancelAction The action to perform when canceling to here.
     */
    protected void setAsCancel (Context context, String cancelAction)
    {
        String cancelToPage = (String)context.get("servletName");
        getSessionManager(context).setAsCancel(cancelToPage, context,
                                               cancelAction);
    }


    /**
     * Sets the target page of a cancel to the specified page and current
     * action.
     *
     * @@param context The Context partially populated by WMServlet.
     */
    protected void setAsCancelWithAction (Context context)
    {
        String cancelToPage = (String)context.get("servletName");
        String cancelAction = (String)context.get(ACTION_KEY);
        getSessionManager(context).setAsCancel(cancelToPage, context,
                                               cancelAction);
    }


    /**
     * Redirect to the detoured page.
     *
     * @@param    context    the Context partially populated by WMServlet
     * @@exception    HandlerException
     * @@exception    RedirectException
     */
    protected void redirectToDetour (Context context)
        throws NestableException, RedirectException
    {
        SessionManager sMgr = getSessionManager(context);
        String detourPage = sMgr.redirectToDetour(context);

        if (detourPage != null)
        {
            if (DEBUG) Log.debug("redirectToDetour: " + detourPage);
            redirectTo(detourPage);
        }
        else
        {
            if (DEBUG) Log.debug("redirectToDetour: setting action=none; " +
                                 "isLoggedIn: " + context.get("isLoggedIn"));
            context.put(ACTION_KEY, "none");

            if (((Boolean) context.get("isLoggedIn")).booleanValue())
                redirectTo(myProperties.getProperty("startServletName"));
            else
                redirectToHomePage(context);
        }
    }


    /**
     *  Sets the target page of a detour to the specified page.
     *
     * @@param    context    the Context partially populated by WMServlet
     */
    protected void setAsDetour (Context context)
    {
        String cancelToPage = (String)context.get("servletName");
        getSessionManager(context).setAsDetour(cancelToPage, context);
    }

    /**
     *  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 context The context to pull cached data from.
     */
    protected void removeAsCancel (Context context)
    {
        String servletName = (String) context.get("servletName");
        getSessionManager(context).removeAsCancel(servletName, context);
    }

    /**
     * Gets the action specified by the last button pushed.  Since
     * {@@link #processRequest} adds any action garnered from CGI inputs to
     * the context, we look there first.
     *
     * @@param context The context to grab the action from.
     * @@return The action.
     */
    protected final String getAction (Context context)
    {
        String action = (String) context.get(ACTION_KEY);
        if (action == null)
        {
            action = ContextAPI.getParameter(context, ACTION_KEY);
            if (action == null)
            {
                action = ContextAPI.getParameter(context, BUTTON_KEY);
            }
        } 

        //Don't perform any action if there are errors.
        if (!ContextAPI.isValidUserInput(context, Boolean.FALSE))
        {
            action = "none";
        }
        return action;
    }

    /**
     *  Returns the SessionManager for this session, automatically adding it 
     *  to the provided WebContext.
     *
     * @@param  ctx The template context.
     * @@return     The manager for this session.
     */
    protected SessionManager getSessionManager(Context ctx)
    {
        HttpSession session = ContextAPI.getRunData(ctx).getSession();
        SessionManager sMgr =
            (SessionManager) session.getValue("SessionManager");
        if (sMgr == null)
        {
            sMgr = new SessionManager(session);
            session.putValue("SessionManager", sMgr);
        }
        return sMgr;
    }

    /**
     *  Performs any initialization when the servlet is loaded.
     *  First, gets the default template name and the properties file name
     *  from the init args, then loads the properties file.
     *
     * @@exception ServletException
     */
    public void start()
        throws ServletException
    {
        // Set up myProperties to supply values with the precedence:
        // - servlet properties
        // - site properties
        // - zone properties
        // - System properties
        // TODO: Merge zone properties into TR.props.

        // Start by reading the initialization parameters into a Properties
        // object.  Make the System properties supply defaults.

        Properties initParameters = new Properties(System.getProperties());
        ServletConfig config = getServletConfig();
        if (config == null)
        {
            throw new ServletException("ServletConfig is null");
        }

        Enumeration parameterNames = config.getInitParameterNames();
        String paramName;
        while (parameterNames.hasMoreElements())
        {
            paramName = (String)parameterNames.nextElement();
            initParameters.put(paramName, config.getInitParameter(paramName));
        }

        // Get the name of the site properties file from the zone properties,
        // then open the file and load the properties.  Make the zone
        // properties supply defaults.
        Properties siteProperties = new Properties(initParameters);
        String sitePropertiesFile =
            initParameters.getProperty("siteProperties");

        if (sitePropertiesFile != null)
        {
            try
            {
                PropertiesUtil.readProperties(sitePropertiesFile, 
                                              siteProperties);
            }
            catch (IOException e)
            {
                throw new ServletException(e.getMessage());
            }
        }

        // Make the properties built up thus far globally accessible.
        HelmProperties.getInstance().init(siteProperties);

        // Initialize all Turbine Services configured in its properties file.
        if (!turbineInitialized)
        {
            synchronized (BaseHelmServlet.class)
            {
                if (!turbineInitialized)
                {
                    initTurbine(config);
                    turbineInitialized = true;
                }
            }
        }

        //Get servlet-specific properties.
        myProperties = new Properties(siteProperties);
        Properties p = ComponentTools.singleton.findServletProperties
            (getServletName());
        if (p != null)
        {
            for (Iterator i = p.keySet().iterator(); i.hasNext();)
            {
                Log.debug("Found property: " + (String)i.next());
            }
            myProperties.putAll(p);
        }
        else
        {
            Log.warn("Couldn't find any properties for " + getServletName());
        }

        //Get information about the current version of the application.
        String versionProperties = siteProperties.getProperty("VERSION_INFO");
        if (versionProperties != null)
        {
            try
            {
                PropertiesUtil.readProperties(versionProperties, myProperties);
            }
            catch (IOException e)
            {
                throw new ServletException(e.getMessage());
            }
        }

        // Make sure that a default scheme is set if not specified otherwise.
        if (!myProperties.containsKey("servletScheme"))
            myProperties.put("servletScheme", "http");

        // Determine if we are running in a production environment
        String prodEnvFlag =
            myProperties.getProperty("inProductionEnvironment", "false");
        inProductionEnvironment =
            prodEnvFlag.equalsIgnoreCase("true")? true : false;
        if (DEBUG) Log.debug("In Production Environment: " + prodEnvFlag);

        // Get the name of the template to use from the configuration
        masterTemplateName = myProperties.getProperty("templateName");
        if (DEBUG) Log.debug("master template: " + masterTemplateName);

        // Initialize the stats object if we're to run web stats.
        if( webStats == null && boolWebStats )
        {
            String logTraffic =
                myProperties.getProperty("logTraffic", "false");
            if (logTraffic.equals("true"))
            {
                String trafficLog = myProperties.getProperty("trafficLog");
                String intervalArg =
                    myProperties.getProperty("trafficInterval", "10");
                int interval = Integer.parseInt(intervalArg);
                String batchArg =
                    myProperties.getProperty("trafficBatchSize", "6");
                int batch = Integer.parseInt(batchArg);
                String histArg =
                    myProperties.getProperty("trafficHistorySize", "360");
                int hist = Integer.parseInt(histArg);

                try
                {
                    webStats = WebStats.getInstance(interval, batch, hist,
                                                    trafficLog);
                }
                catch (IOException e)
                {
                    Log.error(e);
                    if (DEBUG) Log.debug("Unable to access web traffic log: " +
                                         trafficLog);
                    throw new ServletException(e.getMessage());
                }
            }
        }
   
        // Get instance of MemorySentinel running in current Heap.  It writes 
        // memory total and free to webmacro log.  It's singleton, so only
        // ever one instance per heap.
        //
        // Not a tragedy if we MemorySentinel fails to run but the fact that
        // it failed is worthy of mention.
        try 
        {
            MemorySentinel.getInstance();
        }
        catch (Exception e)
        {
            Log.warn("Failed starting memory sentinel: " + e);
        }

        // Initialize the boolean that says whether or not to run web stats.
        boolWebStats = new Boolean
            (myProperties.getProperty(GATHER_WEB_STATS_KEY)).booleanValue();

        if (DEBUG)
            Log.debug("WebStats " + (boolWebStats ? "on." : "off."));
    }

    /**
     * Initializes <a href="http://java.apache.org/turbine/">Turbine</a> and 
     * all its configured services, supplying a web application root of the
     * install location of Tigris (i.e. the <code>$SANDBOX</code> directory).
     * This shouldn't be called until <code>HelmProperties</code> has been
     * initialized.
     *
     * @@param config The servlet configuration.
     */
    private void initTurbine(ServletConfig config)
    {
        String webAppRoot = config.getInitParameter("SANDBOX");
        String trProps = config.getInitParameter("TURBINE_RESOURCES");
        String initInfo = "Turbine with a properties file of " + trProps +
            " and a web app root of " + webAppRoot;
        try
        {
            TurbineConfig cfg = new TurbineConfig(webAppRoot, trProps);
            cfg.init();
        }
        catch (Exception e)
        {
            // If Turine fails to initialize, no logging will be available.
            String msg = "Failed to initialize " + initInfo + ": " +
                e.getMessage();
            // Write directly to stderr to preserve the full stack trace.
            System.err.println(msg);
            e.printStackTrace();
            throw new Error(msg);
        }
        Log.debug("BaseHelmServlet initialized " + initInfo);
    }

    /**
     * Returns the name of this servlet, as specified by its 
     * <code>servletName</code> property, or if not set, then by its super 
     * class' implementation.
     *
     * @@return The name of this servlet.
     */
    public String getServletName()
    {
        String name = myProperties.getProperty("servletName");
        if (!StringUtils.isValid(name))
        {
            String myClass = getClass().getName();
            name = myClass.substring(myClass.lastIndexOf('.') + 1);

            // TODO: Use this enhanced implementation when moving to a
            // modern Servlet API (i.e. 2.2).
            /*
            if (!StringUtils.isValid(name))
            {
                name = super.getServletName();
            }
            */

            if (StringUtils.isValid(name))
            {
                myProperties.put("servletName", name);
            }
        }
        return name;
    }

    /**
     * Checks whether their is a user inputted value in the provided string.
     *
     * @@param value The string to check.
     * @@return      Whether there is a value.
     */
    protected static final boolean haveValue (String value)
    {
        return (value != null && value.trim().length() > 0);
    }

    /**
     * This is used to allow subclasses to access information which will
     * be in either the current context, or the saved context (if a
     * redirect was done).
     */
    protected Object contextGet(Context context, String key)
    {
        Object object = context.get(key);
        if (object != null)
            return object;

        Object savedContext = context.get(SAVED_CONTEXT_KEY);
        if (savedContext != null && savedContext instanceof Context)
            object = ((Context)savedContext).get(key);

        return object;
    }

    /**
     * This is for symetry w/ contextGet -- and in case we decided to
     * change the implementation.  Save a value to the context, ensuring
     * that it will be available on the next request.
     */
    protected void contextPut(Context context, String key, Object value)
    {
        context.put(key, value);
    }

    /**
     * Returns a partial URL string consisting of a protocol and server name.
     *
     * @@param ctx The context to get the data from.
     * @@return    String consisting of a protocol and server name.
     */
    protected final String getHttpAndServer (Context ctx)
    {
        return (String)ctx.get(HTTP_AND_SERVER_KEY);
    }    
}
@


1.65
log
@tfahrner requests that $shortDisplayName defaults to $displayName if
not configured in the properties file.
@
text
@d87 1
d108 1
a108 1
 * @@version $Id: BaseHelmServlet.java,v 1.64 2001/08/28 22:39:35 dlr Exp $
d629 13
d643 2
a644 7
        // servletDirectory - application base package
        // servletTemplate  - application-specific package snippet + file
        // TODO: This is legacy, these properties need to be combined into
        // one at some point.
        String servletTemplate = myProperties.getProperty("servletDirectory") +
            File.separatorChar + myProperties.getProperty("servletTemplate");
        if (DEBUG) Log.debug("servlet template: " + servletTemplate);
d1154 11
a1164 6
        String servletName = getServletName();

        TurbineServices s = (TurbineServices)TurbineServices.getInstance();
        ExtendedProperties subset = s.getConfiguration().subset
            ("servlets." + servletName);
        if (subset != null)
d1166 1
a1166 1
            myProperties.putAll(subset.getProperties("properties"));
@


1.64
log
@* Made use of StringUtils.

* Refactored getServletName() to derive servlet name from class name
if servlet name is unknown (moved code from start() instance method).
@
text
@d107 1
a107 1
 * @@version $Id: BaseHelmServlet.java,v 1.63 2001/08/28 21:48:49 dlr Exp $
d534 1
a534 1
            shortDisplayName = "";
@


1.63
log
@Added TODO note.
@
text
@d107 1
a107 1
 * @@version $Id: BaseHelmServlet.java,v 1.62 2001/08/28 21:48:01 dlr Exp $
a269 1
                //
d346 1
a346 1
                if (servletName == null || servletName.length() == 0)
d1131 1
a1131 1
        synchronized (BaseHelmServlet.class)
d1133 1
a1133 1
            if (!turbineInitialized)
d1135 5
a1139 2
                initTurbine(config);
                turbineInitialized = true;
d1145 1
a1145 3
        String myClass = getClass().getName();
        String servletName = myClass.substring(myClass.lastIndexOf('.')+1);
        myProperties.put("servletName", servletName);
d1283 19
a1301 8
        // TODO: Use this enhanced implementation when moving to a modern 
        // Servlet API (i.e. 2.2).
        /*
          if (name == null || name.trim().equals(""))
          {
          name = super.getServletName();
          }
        */
@


1.62
log
@Corrected compile-time errors.
@
text
@d107 1
a107 1
 * @@version $Id: BaseHelmServlet.java,v 1.61 2001/08/28 18:12:23 leonardr Exp $
d1084 5
a1088 5
        // 1. servlet properties
        // 2. application properties (future)
        // 3. site properties
        // 4. zone properties
        // 5. System properties
@


1.61
log
@Moved code out into a utility class.
@
text
@d107 1
a107 1
 * @@version $Id: BaseHelmServlet.java,v 1.60 2001/08/28 17:45:18 leonardr Exp $
d1124 1
a1124 1
                throw new ServletException(e);
d1165 1
a1165 1
                throw new ServletException(e);
@


1.60
log
@More methods migrated to ContextAPI.
@
text
@d97 1
d107 1
a107 1
 * @@version $Id: BaseHelmServlet.java,v 1.59 2001/08/28 17:13:34 leonardr Exp $
a1073 51
     * Reads a properties file into a Properties object.
     *
     * @@param propertiesFile The name of the file with properties.
     * @@param theProperties  The Properties object into which to load file.
     *
     * @@exception ServletException I/O problem reading properties.
     */
    protected void readProperties(String propertiesFile,
                                  Properties theProperties)
        throws ServletException
    {
        try
        {
            // Load the properties from the specified file.
            if (propertiesFile.charAt(0) == '/')
            {
                theProperties.load(new BufferedInputStream
                    (new FileInputStream(propertiesFile)));
            }
            else
            {
                // The leading "/" tells Class.getResourceAsStream
                // not to munge the name.
                theProperties.load(new BufferedInputStream
                    (getClass().getResourceAsStream("/" + propertiesFile)));
            }
        }
        catch (IOException e)
        {
            String msg = "Unable to read properties file: " + propertiesFile +
                ": " + e.getMessage();
            System.err.println(msg);
            e.printStackTrace();
            throw new ServletException(msg);
        }

        if (DEBUG)
        {
            System.out.println("Properties File: " + propertiesFile);
            for (Enumeration e=theProperties.propertyNames(); 
                 e.hasMoreElements(); )
            {
                String propName = (String) e.nextElement();
                String propValue =
                    (String) theProperties.getProperty(propName);
                System.out.println(propName + " => " + propValue);
            }
        }
    }

    /**
d1117 9
a1125 1
            readProperties(sitePropertiesFile, siteProperties);
d1159 8
a1166 1
            readProperties(versionProperties, myProperties);
@


1.59
log
@Completed migration of more methods to ContextAPI.
@
text
@d106 1
a106 1
 * @@version $Id: BaseHelmServlet.java,v 1.58 2001/08/28 01:36:38 leonardr Exp $
a1377 16

    /**
     * {@@link org.tigris.helm.tool.ContextAPI} macro.
     */
    protected final String getParameter(Context ctx, String name)
    {
        return ContextAPI.getParameter(ctx, name);
    }

    /**
     * {@@link org.tigris.helm.tool.ContextAPI} macro.
     */
    protected final String[] getParameterValues(Context ctx, String name)
    {
        return ContextAPI.getParameterValues(ctx, name);
    }
@


1.58
log
@A bit more cleanup.
@
text
@d106 1
a106 1
 * @@version $Id: BaseHelmServlet.java,v 1.57 2001/08/28 01:09:34 leonardr Exp $
a1392 17
    }


    /**
     * {@@link org.tigris.helm.tool.ContextAPI} macro.
     */
    protected final HttpServletRequest getRequest(Context context)
    {
        return ContextAPI.getRequest(context);
    }

    /**
     * {@@link org.tigris.helm.tool.ContextAPI} macro.
     */
    protected final HttpServletResponse getResponse(Context context)
    {
        return ContextAPI.getResponse(context);
@


1.57
log
@Got rid of the deprecated methods which were taking up 25% of the space in BaseHelmServlet.
@
text
@d106 1
a106 1
 * @@version $Id: BaseHelmServlet.java,v 1.56 2001/08/28 00:56:13 leonardr Exp $
d225 7
a231 4
     * Does connection management and other tasks common to all servlets.
     * This function performs actions such as recording the page hit,
     * servlet specific processing, and populating the template with
     * actual values.
d233 1
a233 5
     * @@param context The Context partially populated by WMServlet.
     * @@return        The name of the template for formatting the {@@link
     *                org.webmacro.servlet.WebContext} data.
     *
     * @@exception HandlerException Any runtime error.
d248 4
a251 1
        if (webStats != null) webStats.addHit();
a255 1
        // Do all of the servlet processing ...
d273 5
a277 2
                    if (DEBUG) Log.debug("About to process request for " +
                                         getServletName());
d279 5
a283 2
                    if (DEBUG) Log.debug("Completed processing request for " +
                                         getServletName());
d287 3
d297 2
a298 1
                        message = "<pre>" + StringUtils.stackTrace(e) + "</pre>";
d307 1
a307 2
                    // TODO: Handle character encoding.
                    TurbineVelocity.handleRequest(context, templateName,
d319 2
a320 2
                String servletName = e.getMessage();
                String shortServletName = servletName;
d331 2
a332 1
                if (dump != null && !dump.equals(servletName)) {
d337 2
a338 6
                servletName = myProperties.getProperty("servlet." +
                                                       servletName + ".code");
                assertServerRedirectOkay
                    ((servletName != null),
                     "Unable to locate full name for servlet",
                     shortServletName);
d340 4
a343 1
                if (DEBUG) Log.debug ("Redirect servletName: " + servletName );
d374 1
a374 1
                    throw new NestableException(e);
a410 18
     * The server-side redirect methods are misused so much that we need this
     * assertion to check them during processing.
     */
    private final void assertServerRedirectOkay(boolean condition,
                                                String preamble,
                                                String shortServletName)
        throws Exception
    {
        if (!condition)
        {
            String msg = preamble + ' ' + shortServletName + ": Be sure to " +
                "pass servlet names without any additional concatenated  " +
                "information when using server side redirect methods";
            throw new Exception(msg);
        }
    }

    /**
a470 32
    /**
     * {@@link org.tigris.helm.tool.ContextAPI} macro.
     */
    protected final HttpServletRequest getRequest(Context ctx)
    {
        return ContextAPI.getRequest(ctx);
    }

    /**
     * {@@link org.tigris.helm.tool.ContextAPI} macro.
     */
    protected final HttpServletResponse getResponse(Context ctx)
    {
        return ContextAPI.getResponse(ctx);
    }

    /**
     * {@@link org.tigris.helm.tool.ContextAPI} macro.
     */
    protected final String getParameter(Context ctx, String name)
    {
        return ContextAPI.getParameter(ctx, name);
    }

    /**
     * {@@link org.tigris.helm.tool.ContextAPI} macro.
     */
    protected final String[] getParameterValues(Context ctx, String name)
    {
        return ContextAPI.getParameterValues(ctx, name);
    }

d641 1
a641 1
            URL.httpAndServer(getRequest(context)).toString();
d644 1
a644 1
                    URL.schemeAndDomain(getRequest(context)));
d656 1
a656 1
        String vhost = getParameter(context, "project");
d736 1
a736 1
            HttpServletRequest request = getRequest(context);
d1037 1
a1037 1
            action = getParameter(context, ACTION_KEY);
d1040 1
a1040 1
                action = getParameter(context, BUTTON_KEY);
d1378 33
@


1.56
log
@Moved code out of BaseHelmServlet and into other classes which suit it better.
@
text
@d106 1
a106 1
 * @@version $Id: BaseHelmServlet.java,v 1.55 2001/08/27 23:18:26 leonardr Exp $
d113 5
a146 5
     * Turn debug log output on/off
     */
    private static final boolean DEBUG = false;

    /**
d386 1
a386 1
            appendToError(context, e.getMessage());
a1416 185
    }
    
    /////////////////////////////////////////////////
    // Deprecated methods.
    /////////////////////////////////////////////////

    /**
     * Retrieves HTML form checkbox data, both adding the data to the
     * context as an object and returning it as a primitive.
     *
     * @@deprecated Use ContextAPI instead.
     * @@param ctx The context of user interaction.
     * @@param key The key to the desired field.
     * @@return    The whether the checkbox was checked.
     */
    protected final boolean processCheckbox (Context ctx, String key)
    {
        String value = getParameter(ctx, key);
        boolean bool = haveValue(value);
        addBooleanToContext(ctx, key, bool);
        if (DEBUG) Log.debug("Processing checkbox: " + key + '=' + value);
        return bool;
    }


    /**
     * Adds a boolean value to the context.
     *
     * @@deprecated Use ContextAPI instead.
     * @@param ctx  The context to add to.
     * @@param key  The key name of the value in the context.
     * @@param bool The boolean primitive whose object equivalent to add.
     */
    protected final void addBooleanToContext (Context ctx, String key, 
                                              boolean bool)
    {
        ctx.put(key, (bool ? Boolean.TRUE : Boolean.FALSE));
    }


    /**
     * Requires that a value is provided, adding it to the list of missing 
     * fields if it is not there.  This method is convenient to call in 
     * conjunction with the processField() variants which do not take a list 
     * of missing fields.
     *
     * @@deprecated Use ContextAPI instead.
     * @@param value         The value to check.
     * @@param description   The description to use to describe a missing value.
     * @@param missingFields The list of missing fields to add to.
     */
    protected void requireValue (String value, String description, 
                                 List missingFields)
    {
        if (!haveValue(value))
        {
            if (missingFields != null)
            {
                missingFields.add(description);
            }
        }
    }

    /**
     * @@see org.tigris.helm.security.HelmServlet#processField
     * @@deprecated Use ContextAPI instead.
     */
    protected final String processField (Context context, String key)
    {
        return processField(context, key, (String)null);
    }

    /**
     * @@see #processField
     * @@deprecated Use ContextAPI instead.
     */
    protected final String processField (Context context, 
                                         String key, String defaultValue)
    {
        return processField(context, key, defaultValue, null, null, true);
    }

    /**
     * @@see #processField
     * @@deprecated Use ContextAPI instead.
     */
    protected final String processField (Context context, String key,
                                         HttpSession session)
    {
        return processField(context, key, session);
    }

    /**
     * Attempts to get <code>defaultValue</code> from the 
     * <code>HttpSession</code> object, keyed by <code>key</code>.
     *
     * @@see #processField
     * @@deprecated Use ContextAPI instead.
     */
    protected final String processRequiredField 
        (Context context, String key, HttpSession session)
    {
        return processField(context, key, (String)session.getValue(key), 
                            null, null, true);
    }    

    /**
     * @@see #processField
     * @@deprecated Use ContextAPI instead.
     */
    protected final String processRequiredField 
        (Context context, String key, String description)
    {
        return processField(context, key, null, description, null, true);
    }

    /**
     * Retrieves HTML form and/or CGI query string data, both adding the data 
     * to the context and returning it.  If the form field contains no data, 
     * the provided <code>description</code> is noted in the 
     * <code>missingFields</code> list (if provided).
     * @@deprecated Use ContextAPI instead.
     */
    protected String processField (Context context, String key, 
                                   String defaultValue, String description)
    {
        return processField(context, key, defaultValue, description, null, 
                            true);
    }

    /**
     * @@see #processField
     * @@deprecated Use ContextAPI instead.
     */
    protected final String processField (Context context, 
                                         String key, String description, 
                                         List missingFields)
    {
        return processField(context, key, (String)null, description,
                            missingFields, true);
    }

    /**
     * Attempts to get <code>defaultValue</code> from the 
     * <code>HttpSession</code> object, keyed by <code>key</code>.
     *
     * @@deprecated Use ContextAPI instead.
     * @@see #processField
     */
    protected final String processField (Context context, String key,
                                         HttpSession session,
                                         String description,
                                         List missingFields)
    {
        return processField(context, key, (String)session.getValue(key), 
                            description, missingFields, true);
    }    

    /**
     * Retrieves HTML form and/or CGI query string data, both adding the data 
     * to the context and returning it.  If the form field contains no data, 
     * the provided <code>description</code> is noted in the 
     * <code>missingFields</code> list (if provided).
     * @@deprecated Use ContextAPI instead.
     */
    protected String processField (Context context, String key, 
                                   String defaultValue, String description, 
                                   List missingFields)
    {
        return processField(context, key, defaultValue, description,
                            missingFields, true);
    }

    /**
     * Attempts to get <code>defaultValue</code> from the 
     * <code>HttpSession</code> object, keyed by <code>key</code>.
     *
     * @@deprecated Use ContextAPI instead.
     * @@see #processField
     */
    protected final String processRequiredField 
        (Context context, String key, HttpSession session, String description)
    {
        return processField(context, key, (String)session.getValue(key), 
                            description, null, true);
a1417 257

    /**
     * Retrieves HTML form and/or CGI query string data, both adding the data 
     * to the context and returning it.  If the form field contains no data, 
     * the provided <code>description</code> is noted in the 
     * <code>missingFields</code> list (if provided). Will also trim
     * leading and trailing spaces on demand.
     * <p>
     * The name of this method is, unfortunately, ambiguous (because it does 
     * so many things).  It may not be a cohesive, but it sure is useful!
     *
     * @@deprecated Use ContextAPI instead.
     * @@param context       The Context to add the param to.
     * @@param key           The name of the form field and context key.
     * @@param defaultValue  The default value to use if there is nothing in 
     *                      the form (if <code>null</code>, defaults to the
     *                      empty string).
     * @@param description   The description to put into the 
     *                      <code>missingFields</code> list if the the form 
     *                      field has no value (or <code>null</code>).
     * @@param missingFields The list of missing fields (or <code>null</code> 
     *                      if you do not care if the field is missing).
     * @@param cleanup       Whether or not to clean up the data before 
     *                      processing it.
     * @@return The form value retrieved.
     */
    protected String processField (Context context, String key, 
                                   String defaultValue, String description, 
                                   List missingFields, boolean cleanup)
    {
        String value = getParameter(context, key);
        if (!haveValue(value))
        {
            if (missingFields != null)
            {
                missingFields.add(description);
            }
            value = (defaultValue != null ? defaultValue : EMPTY_STRING);
        }
        if (cleanup)
        {
            value = value.trim();
        }
        context.put(key, value);
        if (DEBUG) Log.debug("Processing field: " + key + '=' + value);
        return value;
    }

    /**
     * Process a field without modifying its data in any way.
     * @@deprecated Use ContextAPI instead.
     */
    protected final String processFieldRaw
        (Context context, String key)
    {
        return processFieldRaw(context, key, null);
    }
    
    /**
     * Process a field without modifying its data in any way.
     * @@deprecated Use ContextAPI instead.
     */
    protected final String processFieldRaw
        (Context context, String key, String defaultValue)
    {
        return processField(context, key, defaultValue, (String)null,
                            null, false);
    }
    
    /**
     * Process a field without modifying its data in any way.
     * @@deprecated Use ContextAPI instead.
     */
    protected final String processFieldRaw
        (Context context, String key, String description, List missingFields)
    {
        return processField(context, key, (String)null, description,
                            missingFields, false);
    } 

    /**
     * Checks whether the user inputs are valid.  Examines 
     * <code>missingFields</code> and <code>validationErrors</code> for listed 
     * fields.
     *
     * @@deprecated Use ContextAPI instead.
     * @@param missingFields    The missing fields.
     * @@param validationErrors The field validaiton errors.
     * @@return                 The validity of the user input.
     */
    protected final boolean isValidUserInput (List missingFields, 
                                              List validationErrors)
    {
        return ( (missingFields == null || missingFields.isEmpty()) && 
                 (validationErrors == null || validationErrors.isEmpty()) );
    }

    /**
     * Reports missing fields and data validation errors.  Examines 
     * <code>missingFields</code> and <code>validationErrors</code> for listed 
     * fields.
     *
     * @@deprecated This happens automatically.
     * @@param context          The Context to report errors in.
     * @@param missingFields    The missing fields.
     * @@param validationErrors The field validaiton errors.
     */
    protected final void reportInvalidUserInput (Context context, 
                                                 List missingFields, 
                                                 List validationErrors)
    {
        if (missingFields != null && !missingFields.isEmpty())
        {
            appendToMessage(context, "Required information missing", 
                            missingFields);
        }
        if (validationErrors != null && !validationErrors.isEmpty())
        {
            appendToMessage(context, "Invalid information entered", 
                            validationErrors);
        }
    }

    /**
     * Adds an error about missing a required input.
     * @@deprecated This is handled automatically.
     */
    protected final void alertToMissingInput(Context context, 
                                             String missingInput)
    {
        appendToError(context, "You are missing the following required input: "
                      + missingInput);        
    }

    /**
     * @@see #appendToError
     * @@deprecated Use ContextAPI.addError() instead.
     */
    protected final void appendToError (Context context, String text)
    {
        appendToError(context, text, (List)null);
    }

    /**
     * Appends the specified text and list of elements to the user error
     * message.
     *
     * @@deprecated Use ContextAPI.addError() instead.
     * @@param context The <code>WebContext</code> to use.
     * @@param text    The message text, or if list is not <code>null</code> 
     *                the text to use as a heading when building the message.
     * @@param list    The list of elements to add after the heading text, or 
     *                <code>null</code> if the text is the entire message.
     */
    protected void appendToError (Context context, String text, List list)
    {
        Object msg = context.get(MESSAGE_KEY);
        if (msg == null)
        {
            text = "Sorry, an error has occurred:<p>" + text + "</p>";
        }
        appendToMessage(context, text, list);
    }

    /**
     * @@see #appendToMessage
     * @@deprecated Use ContextAPI.addMessage() instead.
     */
    protected final void appendToMessage (Context context, String text)
    {
        appendToMessage(context, text, (List)null);
    }

    /**
     * Appends the specified text and list of elements to the general purpose
     * user message.
     *
     * @@deprecated Use ContextAPI.addMessage() instead.
     * @@param context The <code>WebContext</code> to use.
     * @@param text    The message text, or if list is not <code>null</code> 
     *                the text to use as a heading when building the message.
     * @@param list    The list of elements to add after the heading text, or 
     *                <code>null</code> if the text is the entire message.
     */
    protected void appendToMessage (Context context, String text, List list)
    {
        // Get any existing message.
        StringBuffer buf = null;
        Object msg = context.get(MESSAGE_KEY);
        if (msg == null)
        {
            buf = new StringBuffer();
        }
        else if (msg instanceof StringBuffer)
        {
            buf = (StringBuffer)msg;
        }
        else
        {
            buf = new StringBuffer(msg.toString());
        }

        // Append to the text and any list elements.
        buf.append(text);
        if (list != null)
        {
            int nbrElements = list.size();
            if (nbrElements > 0)
            {
                buf.append("<ul>");
                for (int i = 0; i < nbrElements; i++)
                {
                    buf.append("<li>").append((String)list.get(i));
                    buf.append("</li>");
                }
                buf.append("</ul>");
            }
        }
        else
        {
            buf.append("<br>");
        }

        // Add the new message to the context.
        context.put(MESSAGE_KEY, buf);
    }

    /**
     * @@deprecated use ContextAPI instead.
     */
    public static List searchParamsForPrefix(Context context, String prefix)
        throws NestableException
    {
        return searchParamsForPrefix(context, prefix);
    }

    /**
     * @@deprecated use ContextAPI instead.
     */
    public static List searchParamsForPrefixIncludeValue
        (Context context, String prefix)
        throws NestableException
    {
        return ContextAPI.searchParamsForPrefixIncludeValue(context, prefix);
    }

    /**
     * @@deprecated use ContextAPI instead.
     */
    public static List searchParamsForPrefixAndTokenize
        (Context context, String prefix, int tokens, boolean appendValue)
        throws NestableException
    {
        return ContextAPI.searchParamsForPrefixAndTokenize
            (context, prefix, tokens, appendValue);
    }   

@


1.55
log
@Moved servlet-specific properties out of a million tiny files and into TurbineResources.properties.
@
text
@d106 1
a106 1
 * @@version $Id: BaseHelmServlet.java,v 1.54 2001/08/16 00:45:18 dlr Exp $
d287 1
a287 1
                        message = "<pre>" + stackTraceToString(e) + "</pre>";
a1380 22
     * Returns the output of printStackTrace as a String.
     *
     * @@param e A Throwable.
     * @@return A String.
     */
    public static final String stackTraceToString(Throwable e)
    {
        String asString = null;
        try
        {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw,true));
            asString = sw.toString();
        }
        catch (Exception f)
        {
            // Do nothing.
        }
        return asString;
    }

    /**
a1417 110

    /**
     * Search the form parameters for parameters that begin with a certain
     * prefix. Return the list of parameter values provided for that prefix.
     *
     * For instance, calling searchParamsForPrefix(context, "Add")
     * when "Add 4" and "Add 7" are form parameters will return a List
     * containing the Strings "4" and "7".
     */
    public List searchParamsForPrefix(Context context, String prefix)
        throws NestableException
    {
        return searchParamsForPrefixAndTokenize(context, prefix, 1, false);
    }

    /**
     * Search the form parameters for parameters that begin with a certain
     * prefix. Return the list of parameter values provided for that prefix.
     *
     * For instance, calling searchParamsForPrefix(context, "Add"),
     * when "Add 4" and "Add 7" are form parameters mapping to "a" and
     * "b", will return a list containing the String arrays {"4" "a"}
     * and {"7" "b"}.  
     */
    public List searchParamsForPrefixIncludeValue
        (Context context, String prefix)
        throws NestableException
    {
        return searchParamsForPrefixAndTokenize(context, prefix, 1, true);
    }

    /**
     * Search the form parameters for parameters that begin with a
     * certain prefix. Return the list of string arrays containing the
     * tokenized parameter values provided for that prefix.
     *
     * <p>Examples<br>
     * Assume the following parameters:
     * <li>"Add 4 7" => "a"
     * <li>"Add 10 4" => "b"
     *
     * <p>sPFPAT(context, "Add", 1, false) returns a List containing
     * the Strings "4 7" and "10 4".
     *
     * <p>sPFPAT(context, "Add", 2, false) returns a List containing
     * the String arrays {"4" "7"} and {"10" "4"}.
     *
     * <p>sPFPAT(context, "Add", 3, false) throws an exception
     * because there are not enough tokens in "Add 4 7".
     *
     * <p>sPFPAT(context, "Add", 2, true) returns a List containing
     * the String arrays {"4" "7" "a"} and {"10" "4" "b"}
     *
     * <p>sPFPAT(context, "Add", 1, true) returns a List containing
     * the String arrays {"4 7" "a"} and {"10 4" "b"}
     *
     * <p>sPFPAT(context, "Remove", 3, false) returns an empty List,
     * since there are no parameter values beginning with "Remove".
     */
    public List searchParamsForPrefixAndTokenize
        (Context context, String prefix, int tokens, boolean appendValue)
        throws NestableException
    {
        List values = new ArrayList();
        Enumeration paramNames = getRequest(context).getParameterNames();
        while (paramNames.hasMoreElements())
        {
            String paramName = (String) paramNames.nextElement();
            if (paramName.startsWith(prefix))
            {
                StringTokenizer tok = new StringTokenizer (paramName);
                tok.nextToken();
                int size = tokens;
                if (appendValue)
                {
                    size++;
                }
                String[] theseValues = new String[size];
                for (int i = 0; i < tokens; i++)
                {
                    try
                    {                    
                        theseValues[i] = tok.nextToken();
                    }
                    catch (NoSuchElementException e)
                    {
                        throw new NestableException
                            ("Attempt to tokenize \"" + paramName + "\" " 
                             + (tokens+1) 
                             + " times failed: not enough tokens.");
                    }
                    if (appendValue)
                    {
                        String value = processField(context, paramName, 
                                                    (String)null);
                        theseValues[theseValues.length-1] = value;
                    }
                }
                if (theseValues.length == 1) 
                {
                    values.add(theseValues[0]);
                }
                else
                {
                    values.add(theseValues);
                }
            }
        }    
        return values;
    }   
d1829 31
@


1.54
log
@Used Commons Collections ExtendedProperties instead of Velocity's deprecated Configuration class.
@
text
@d61 1
d106 1
a106 1
 * @@version $Id: BaseHelmServlet.java,v 1.53 2001/08/11 18:05:30 dlr Exp $
d144 1
a144 1
    private static final boolean DEBUG = true;
d166 2
a167 2
     * This is found in the <Servletname>.properties file, stored in
     * the same directory as the servlet source code.
a331 18

                // get the properties file for the servlet
                String propertiesFile = myProperties
                    .getProperty("servlet." + servletName + ".initArgs");
                assertServerRedirectOkay
                    ((propertiesFile != null),
                     "Unable to locate initArgs for servlet",
                     shortServletName);
                int offset = propertiesFile.indexOf("propertiesFile=");
                if (offset < 0) {
                    propertiesFile = null;
                }
                else {
                    propertiesFile = propertiesFile.substring
                        (offset + "propertiesFile=".length());
                    
                    // TODO: Check for an additional name=value pairs.
                }
a357 2
                        redirect.setServletName(shortServletName);
                        redirect.setPropertiesFile(propertiesFile);
d1223 1
a1223 3
        // Get the name of the servlet properties file from the zone
        // properties, then open the file and load the properties.  Make the
        // site properties supply defaults.
d1225 3
a1227 5
        String propertiesFile = siteProperties.getProperty("propertiesFile");
        if (propertiesFileOverride != null) 
            propertiesFile = propertiesFileOverride;

        if (DEBUG) Log.debug(">> propertiesFile is " + propertiesFile);
d1229 4
a1232 1
        if (propertiesFile != null)
d1234 1
a1234 1
            readProperties(propertiesFile, myProperties);
d1237 1
a1237 2
        //Get the name of the version.properties file so that the version
        //info and build number can be put into the context
a1356 1
        if (nameOverride != null) return nameOverride;
a1368 15
    private String nameOverride = null;

    private void setServletName(String name)
    {
        if (DEBUG) Log.debug("setServletName to " + name);
        this.nameOverride = name;
    }

    private String propertiesFileOverride = null;

    private void setPropertiesFile(String file)
    {
        this.propertiesFileOverride = file;
    }

d1550 2
a1551 1

d1553 1
@


1.53
log
@Removed variable which turned out to be unused (preserved the previous
implementation for now).
@
text
@a80 1
import org.apache.velocity.runtime.configuration.Configuration;
d105 1
a105 1
 * @@version $Id: BaseHelmServlet.java,v 1.52 2001/08/11 09:08:08 dlr Exp $
@


1.52
log
@Upgrading to Turbine 3.0-dev, Fulcrum 1.0, and Torque 1.0.
@
text
@d106 1
a106 1
 * @@version $Id: BaseHelmServlet.java,v 1.51 2001/08/08 19:29:09 leonardr Exp $
a1349 1
        String trPropsPath = webAppRoot + File.separatorChar + trProps;
@


1.51
log
@Took out test exception throw.
@
text
@d61 9
a69 4
import org.apache.turbine.util.Log;
import org.apache.turbine.util.RunData;
import org.apache.turbine.util.RunDataFactory;
import org.apache.turbine.util.StringUtils;
d71 5
a75 2
import org.apache.turbine.util.TurbineException;
import org.apache.turbine.services.velocity.TurbineVelocity;
d78 1
d81 1
d97 1
d106 1
a106 1
 * @@version $Id: BaseHelmServlet.java,v 1.50 2001/08/08 18:32:49 leonardr Exp $
d237 1
a237 1
        throws TurbineException
d278 1
a278 1
                catch (TurbineException e)
d356 1
a356 1
                    throw new TurbineException
d384 1
a384 1
                    throw new TurbineException(e);
d407 1
a407 1
            throw new TurbineException(e);
a501 8
    protected final RunData getRunData(Context ctx)
    {
        return ContextAPI.getRunData(ctx);
    }

    /**
     * {@@link org.tigris.helm.tool.ContextAPI} macro.
     */
d535 6
a540 5
            RunData data = RunDataFactory.getRunData(req, res,
                                                     getServletConfig());
            //Log.debug("RunDataFactory returned " + data);
            Context context = TurbineVelocity.getContext(data);
            ContextAPI.putFormCache(context);
d574 1
a574 1
        throws TurbineException, RedirectException
d576 1
a576 1
        RunData runData = getRunData(context);
d759 1
a759 1
        throws TurbineException
d774 1
a774 1
            throw new TurbineException(e);
d789 1
a789 1
        throws TurbineException, RedirectURLException
d794 2
a795 1
            HttpServletResponse response = getRunData(context).getResponse();
d826 1
a826 1
            throw new TurbineException(e);
d842 1
a842 1
        throws TurbineException, RedirectURLException
d855 2
a856 1
            HttpServletResponse response = getRunData(context).getResponse();
d864 1
a864 1
            throw new TurbineException(e);
d883 2
a884 1
        HttpServletResponse response = getRunData(context).getResponse();
d964 1
a964 1
        throws TurbineException, RedirectException
d1036 1
a1036 1
        throws TurbineException, RedirectException
d1121 1
a1121 1
        HttpSession session = getRunData(ctx).getSession();
d1350 1
d1489 1
a1489 1
        throws TurbineException
d1505 1
a1505 1
        throws TurbineException
d1540 1
a1540 1
        throws TurbineException
d1565 1
a1565 1
                        throw new TurbineException
@


1.50
log
@Always trap an endless redirect to ErrorPage, not just when
redirectToError is called.
@
text
@d95 1
a95 1
 * @@version $Id: BaseHelmServlet.java,v 1.49 2001/07/24 00:02:28 leonardr Exp $
a281 4
                if (true)
                {
                    throw new RedirectException("ErrorPage");
                }
d935 1
a935 1
        //happens in process().
@


1.49
log
@The final pieces of the error handling revolution.
@
text
@d95 1
a95 1
 * @@version $Id: BaseHelmServlet.java,v 1.48 2001/07/23 20:04:37 dlr Exp $
d282 4
d306 6
d386 1
d395 1
a395 1
                Log.debug("BaseHelmServlet: Unhandled exception in the " +
d937 4
a940 1
        if (message != null && message.equals("ErrorPage"))
d942 1
a942 1
            throw new Error("Endless redirectToError detected!");
@


1.48
log
@Removed Joist reference.
@
text
@d95 1
a95 1
 * @@version $Id: BaseHelmServlet.java,v 1.47 2001/07/23 20:02:53 dlr Exp $
a1320 100
     * Adds an error about missing a required input.
     */
    protected final void alertToMissingInput(Context context, 
                                             String missingInput)
    {
        appendToError(context, "You are missing the following required input: "
                      + missingInput);        
    }

    /**
     * @@see #appendToError
     *
     */
    protected final void appendToError (Context context, String text)
    {
        appendToError(context, text, (List)null);
    }

    /**
     * Appends the specified text and list of elements to the user error
     * message.
     *
     * @@param context The <code>WebContext</code> to use.
     * @@param text    The message text, or if list is not <code>null</code> 
     *                the text to use as a heading when building the message.
     * @@param list    The list of elements to add after the heading text, or 
     *                <code>null</code> if the text is the entire message.
     */
    protected void appendToError (Context context, String text, List list)
    {
        Object msg = context.get(MESSAGE_KEY);
        if (msg == null)
        {
            text = "Sorry, an error has occurred:<p>" + text + "</p>";
        }
        appendToMessage(context, text, list);
    }

    /**
     * @@see #appendToMessage
     */
    protected final void appendToMessage (Context context, String text)
    {
        appendToMessage(context, text, (List)null);
    }

    /**
     * Appends the specified text and list of elements to the general purpose
     * user message.
     *
     * @@param context The <code>WebContext</code> to use.
     * @@param text    The message text, or if list is not <code>null</code> 
     *                the text to use as a heading when building the message.
     * @@param list    The list of elements to add after the heading text, or 
     *                <code>null</code> if the text is the entire message.
     */
    protected void appendToMessage (Context context, String text, List list)
    {
        // Get any existing message.
        StringBuffer buf = null;
        Object msg = context.get(MESSAGE_KEY);
        if (msg == null)
        {
            buf = new StringBuffer();
        }
        else if (msg instanceof StringBuffer)
        {
            buf = (StringBuffer)msg;
        }
        else
        {
            buf = new StringBuffer(msg.toString());
        }

        // Append to the text and any list elements.
        buf.append(text);
        if (list != null)
        {
            int nbrElements = list.size();
            if (nbrElements > 0)
            {
                buf.append("<ul>");
                for (int i = 0; i < nbrElements; i++)
                {
                    buf.append("<li>").append((String)list.get(i));
                    buf.append("</li>");
                }
                buf.append("</ul>");
            }
        }
        else
        {
            buf.append("<br>");
        }

        // Add the new message to the context.
        context.put(MESSAGE_KEY, buf);
    }

    /**
d1875 104
@


1.47
log
@Leverage StringUtils.
@
text
@d95 1
a95 1
 * @@version $Id: BaseHelmServlet.java,v 1.46 2001/07/19 20:13:18 dlr Exp $
d1299 1
a1299 2
        // ever one instance per heap. Reads properties from
        // 30joist.zone.properties.
@


1.46
log
@Removed Joist references.
@
text
@d64 1
d95 1
a95 1
 * @@version $Id: BaseHelmServlet.java,v 1.45 2001/07/19 19:54:05 dlr Exp $
d708 1
a708 1
        if (vhost == null || vhost.length() == 0)
@


1.45
log
@Removed Joist references.
@
text
@a71 3
import org.joist.util.FileUtil;
import org.joist.security.WebStats;

d79 1
d83 1
d85 1
d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.44 2001/07/19 19:08:43 dlr Exp $
d152 1
a152 1
     * variable.  We may want to set up joist-wide properties, which
d1305 1
a1305 1
            org.joist.util.MemorySentinel.getInstance();
@


1.44
log
@Updated to use Helm URL class (just ported from Joist).
@
text
@a71 1
import org.tigris.helm.tool.HelmProperties;
a72 2
import org.tigris.helm.tool.FormCache;
import org.tigris.helm.util.URL;
d80 2
d84 1
d86 1
a86 1
import org.tigris.helm.tool.VelocityEventCartridge;
d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.43 2001/07/19 18:42:22 dlr Exp $
@


1.43
log
@Updated in light of the port of Joist JoistProperties class to Helm (as class HelmProperties).
@
text
@d75 1
a75 1
import org.joist.util.URL;
d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.42 2001/07/18 23:20:43 leonardr Exp $
@


1.42
log
@Got rid of never-used methods.
@
text
@d72 1
a72 1
import org.joist.util.JoistProperties;
d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.41 2001/07/18 16:04:11 leonardr Exp $
d802 1
a802 1
                                 JoistProperties.getProperty(DEF_MNT_PT));
d835 2
a836 2
            newURL.append(JoistProperties.getProperty("hostname"));
            String port = JoistProperties.getProperty("http_port");
d838 1
a838 1
            newURL.append(JoistProperties.getProperty("HomePage"));
d1213 1
a1213 1
        JoistProperties.getInstance().init(siteProperties);
d1424 1
a1424 1
     * This shouldn't be called until <code>JoistProperties</code> has been
@


1.41
log
@Tweaked the error handling system to make it work like it did before. Bizarrely, there appears to be a built-in Velocimacro called errorList which does exactly the same thing as the errorList I wrote.
@
text
@d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.40 2001/07/18 10:05:15 dlr Exp $
d332 1
a332 1

d702 1
a702 1

a1094 63
     *  Gets the named object ID currently in the context or, if not found,
     *  the most recently referenced ID of that type from the session.  If the
     *  object ID is found in the context, the value is stored in the session
     *  as the most recent ID of that type.
     *
     * @@param    context    the Context partially populated by WMServlet
     * @@param    objectType    the name of the type of object
     * @@return     a String representation of the object ID
     * @@exception    HandlerException
     */
    protected String getObjectID (Context context, String objectType)
        throws TurbineException
    {
        boolean putIntoContext = true;

        // Look in the context first.
        String objectID = getParameter(context, objectType);
        if (objectID == null)
        {
            objectID = (String) context.get(objectType);
            putIntoContext = (objectID == null);
        }

        // Save the value into the context for use downstream
        if (putIntoContext && objectID != null)
            context.put(objectType, objectID);

        return objectID;
    }


    /**
     *  Gets the named object's title or name currently in the context or, if
     *  not found, the most recently used name of that type from the session.
     *  If the object's name is found in the context, the value is stored in
     *  the session as the most recent name of that type.
     *
     * @@param    context    the Context partially populated by WMServlet
     * @@param    objectType    the name of the type of object
     * @@return     a String with the name or title
     * @@exception    HandlerException
     */
    protected String getObjectName (Context context, String objectType)
        throws TurbineException
    {
        boolean putIntoContext = true;

        // Look in the context first.
        String objectName = getParameter(context, objectType);
        if (objectName == null)
        {
            objectName = (String) context.get(objectType);
            putIntoContext = (objectName == null);
        }

        // Save the value into the context for use downstream
        if (putIntoContext)
            context.put(objectType, objectName);

        return objectName;
    }

    /**
d1332 1
@


1.40
log
@Ported Joist Redirect*Exception to Helm.
@
text
@d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.39 2001/07/17 23:20:23 leonardr Exp $
d1086 1
a1086 2
        //Don't perform any action if there are errors which are not
        //missing fields.
@


1.39
log
@Added flag so that you can signal when missing fields are important errors and when they're not.
@
text
@d76 1
a76 1
import org.joist.security.*;
d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.38 2001/07/17 20:54:06 leonardr Exp $
a1155 15
    }


    /**
     *  Determines whether the user has the required access permission.
     *  For unsecured servlets, access is always permitted.
     *
     * @@param    permissionName    the name of the required permission
     * @@param    userPermissions    the set of permissions for the user
     * @@return     always returns true
     */
    protected boolean accessAllowed (String permissionName,
                                     PermissionSet userPermissions)
    {
        return true;
@


1.38
log
@Cleanup for port to new error handling system.
@
text
@d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.37 2001/07/17 20:22:46 leonardr Exp $
d132 1
a132 1
    private static final boolean DEBUG = false;
d1086 3
a1088 2
        //Don't perform any action if there are errors.
        if (!ContextAPI.isValidUserInput(context))
@


1.37
log
@Ported servlet to new error-handling mechanism.
@
text
@d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.36 2001/07/17 17:55:45 leonardr Exp $
d1639 111
a1749 1
    // Methods which will soon be deprecated.
d1755 1
d1773 1
d1791 1
d1810 1
d1819 1
d1829 1
d1842 1
d1853 1
d1866 1
d1877 1
d1891 1
d1908 1
d1922 1
d1942 1
d1981 1
d1991 1
d2002 1
d2016 1
d2033 1
a2052 110

    /**
     * Search the form parameters for parameters that begin with a certain
     * prefix. Return the list of parameter values provided for that prefix.
     *
     * For instance, calling searchParamsForPrefix(context, "Add")
     * when "Add 4" and "Add 7" are form parameters will return a List
     * containing the Strings "4" and "7".
     */
    public List searchParamsForPrefix(Context context, String prefix)
        throws TurbineException
    {
        return searchParamsForPrefixAndTokenize(context, prefix, 1, false);
    }

    /**
     * Search the form parameters for parameters that begin with a certain
     * prefix. Return the list of parameter values provided for that prefix.
     *
     * For instance, calling searchParamsForPrefix(context, "Add"),
     * when "Add 4" and "Add 7" are form parameters mapping to "a" and
     * "b", will return a list containing the String arrays {"4" "a"}
     * and {"7" "b"}.  
     */
    public List searchParamsForPrefixIncludeValue
        (Context context, String prefix)
        throws TurbineException
    {
        return searchParamsForPrefixAndTokenize(context, prefix, 1, true);
    }

    /**
     * Search the form parameters for parameters that begin with a
     * certain prefix. Return the list of string arrays containing the
     * tokenized parameter values provided for that prefix.
     *
     * <p>Examples<br>
     * Assume the following parameters:
     * <li>"Add 4 7" => "a"
     * <li>"Add 10 4" => "b"
     *
     * <p>sPFPAT(context, "Add", 1, false) returns a List containing
     * the Strings "4 7" and "10 4".
     *
     * <p>sPFPAT(context, "Add", 2, false) returns a List containing
     * the String arrays {"4" "7"} and {"10" "4"}.
     *
     * <p>sPFPAT(context, "Add", 3, false) throws an exception
     * because there are not enough tokens in "Add 4 7".
     *
     * <p>sPFPAT(context, "Add", 2, true) returns a List containing
     * the String arrays {"4" "7" "a"} and {"10" "4" "b"}
     *
     * <p>sPFPAT(context, "Add", 1, true) returns a List containing
     * the String arrays {"4 7" "a"} and {"10 4" "b"}
     *
     * <p>sPFPAT(context, "Remove", 3, false) returns an empty List,
     * since there are no parameter values beginning with "Remove".
     */
    public List searchParamsForPrefixAndTokenize
        (Context context, String prefix, int tokens, boolean appendValue)
        throws TurbineException
    {
        List values = new ArrayList();
        Enumeration paramNames = getRequest(context).getParameterNames();
        while (paramNames.hasMoreElements())
        {
            String paramName = (String) paramNames.nextElement();
            if (paramName.startsWith(prefix))
            {
                StringTokenizer tok = new StringTokenizer (paramName);
                tok.nextToken();
                int size = tokens;
                if (appendValue)
                {
                    size++;
                }
                String[] theseValues = new String[size];
                for (int i = 0; i < tokens; i++)
                {
                    try
                    {                    
                        theseValues[i] = tok.nextToken();
                    }
                    catch (NoSuchElementException e)
                    {
                        throw new TurbineException
                            ("Attempt to tokenize \"" + paramName + "\" " 
                             + (tokens+1) 
                             + " times failed: not enough tokens.");
                    }
                    if (appendValue)
                    {
                        String value = processField(context, paramName, 
                                                    (String)null);
                        theseValues[theseValues.length-1] = value;
                    }
                }
                if (theseValues.length == 1) 
                {
                    values.add(theseValues[0]);
                }
                else
                {
                    values.add(theseValues);
                }
            }
        }    
        return values;
    }   
@


1.36
log
@Porting of domain package to new error handling API.
@
text
@d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.35 2001/07/17 16:00:43 leonardr Exp $
d1089 1
a1089 1
            action = null;
@


1.35
log
@Ported servlets over to the new error handling system.
@
text
@d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.34 2001/07/16 23:22:09 leonardr Exp $
d1639 1
a1639 12
    /**
     * Adds a boolean value to the context.
     *
     * @@param ctx  The context to add to.
     * @@param key  The key name of the value in the context.
     * @@param bool The boolean primitive whose object equivalent to add.
     */
    protected final void addBooleanToContext (Context ctx, String key, 
                                              boolean bool)
    {
        ctx.put(key, (bool ? Boolean.TRUE : Boolean.FALSE));
    }
d1658 15
a1693 2

    // Methods which will soon be deprecated.
@


1.34
log
@More changes to and first use of new error-handling system.
@
text
@d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.33 2001/07/16 22:36:27 leonardr Exp $
d1085 6
d1922 110
a2031 1
    
@


1.33
log
@First stab at error handling architecture.
@
text
@d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.32 2001/07/13 21:56:41 leonardr Exp $
d275 1
a275 4
                        StringWriter sw = new StringWriter();
                        e.printStackTrace(new PrintWriter(sw, true));
                        message = "<pre>" 
                            + sw.getBuffer().append("</pre>").toString();
d277 2
a278 2

                    redirectToError(context, message);
d1580 1
a1580 1
        String foo = null;
d1583 3
a1585 4
            // And show the Error Screen.
            ByteArrayOutputStream ostr = new ByteArrayOutputStream();
            e.printStackTrace( new PrintWriter(ostr,true) );
            foo = ostr.toString();
d1591 1
a1591 1
        return foo;
a1684 41
    /**
     * Checks whether the user inputs are valid.  Examines 
     * <code>missingFields</code> and <code>validationErrors</code> for listed 
     * fields.
     *
     * @@param missingFields    The missing fields.
     * @@param validationErrors The field validaiton errors.
     * @@return                 The validity of the user input.
     */
    protected final boolean isValidUserInput (List missingFields, 
                                              List validationErrors)
    {
        return ( (missingFields == null || missingFields.isEmpty()) && 
                 (validationErrors == null || validationErrors.isEmpty()) );
    }

    /**
     * Reports missing fields and data validation errors.  Examines 
     * <code>missingFields</code> and <code>validationErrors</code> for listed 
     * fields.
     *
     * @@param context          The Context to report errors in.
     * @@param missingFields    The missing fields.
     * @@param validationErrors The field validaiton errors.
     */
    protected final void reportInvalidUserInput (Context context, 
                                                 List missingFields, 
                                                 List validationErrors)
    {
        if (missingFields != null && !missingFields.isEmpty())
        {
            appendToMessage(context, "Required information missing", 
                            missingFields);
        }
        if (validationErrors != null && !validationErrors.isEmpty())
        {
            appendToMessage(context, "Invalid information entered", 
                            validationErrors);
        }
    }

d1875 41
@


1.32
log
@Don't print the stacktraces of DoesNotExist or AlreadyExists exceptions, since those are sufficiently self-explanatory.
@
text
@d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.31 2001/07/13 21:47:11 leonardr Exp $
d1638 95
d1744 10
a1753 2
                                         String key, String description, 
                                         List missingFields)
d1755 1
a1755 2
        return processField(context, key, (String)null, description,
                            missingFields, true);
d1759 3
d1764 24
a1787 2
    protected final String processField (Context context, 
                                         String key, String defaultValue)
d1789 2
a1790 1
        return processField(context, key, defaultValue, null, null, true);
d1796 3
a1798 2
    protected final String processField (Context context, String key,
                                         HttpSession session)
d1800 2
a1801 1
        return processField(context, key, session, null, null);
a1814 1
        Log.debug("Session value for " + key + ": " + (String)session.getValue(key));
d1834 13
a1891 1

d1895 1
a1895 1
    protected final String processFieldRaw 
d1900 1
a1900 1

d1904 1
a1904 1
    protected final String processFieldRaw 
d1907 1
a1907 1
        return processField(context, key, defaultValue, (String)null, 
d1910 1
a1910 1

d1914 1
a1914 1
    protected final String processFieldRaw 
d1917 1
a1917 1
        return processField(context, key, (String)null, description, 
d1919 2
a1920 94
    }

    /**
     * Adds a boolean value to the context.
     *
     * @@param ctx  The context to add to.
     * @@param key  The key name of the value in the context.
     * @@param bool The boolean primitive whose object equivalent to add.
     */
    protected final void addBooleanToContext (Context ctx, String key, 
                                              boolean bool)
    {
        ctx.put(key, (bool ? Boolean.TRUE : Boolean.FALSE));
    }

    /**
     * Retrieves HTML form checkbox data, both adding the data to the
     * context as an object and returning it as a primitive.
     *
     * @@param ctx The context of user interaction.
     * @@param key The key to the desired field.
     * @@return    The whether the checkbox was checked.
     */
    protected final boolean processCheckbox (Context ctx, String key)
    {
        String value = getParameter(ctx, key);
        boolean bool = haveValue(value);
        addBooleanToContext(ctx, key, bool);
        if (DEBUG) Log.debug("Processing checkbox: " + key + '=' + value);
        return bool;
    }

    /**
     * Requires that a value is provided, adding it to the list of missing 
     * fields if it is not there.  This method is convenient to call in 
     * conjunction with the processField() variants which do not take a list 
     * of missing fields.
     *
     * @@param value         The value to check.
     * @@param description   The description to use to describe a missing value.
     * @@param missingFields The list of missing fields to add to.
     */
    protected void requireValue (String value, String description, 
                                 List missingFields)
    {
        if (!haveValue(value))
        {
            if (missingFields != null)
            {
                missingFields.add(description);
            }
        }
    }

    /**
     * Checks whether the user inputs are valid.  Examines 
     * <code>missingFields</code> and <code>validationErrors</code> for listed 
     * fields.
     *
     * @@param missingFields    The missing fields.
     * @@param validationErrors The field validaiton errors.
     * @@return                 The validity of the user input.
     */
    protected final boolean isValidUserInput (List missingFields, 
                                              List validationErrors)
    {
        return ( (missingFields == null || missingFields.isEmpty()) && 
                 (validationErrors == null || validationErrors.isEmpty()) );
    }

    /**
     * Reports missing fields and data validation errors.  Examines 
     * <code>missingFields</code> and <code>validationErrors</code> for listed 
     * fields.
     *
     * @@param context          The Context to report errors in.
     * @@param missingFields    The missing fields.
     * @@param validationErrors The field validaiton errors.
     */
    protected final void reportInvalidUserInput (Context context, 
                                                 List missingFields, 
                                                 List validationErrors)
    {
        if (missingFields != null && !missingFields.isEmpty())
        {
            appendToMessage(context, "Required information missing", 
                            missingFields);
        }
        if (validationErrors != null && !validationErrors.isEmpty())
        {
            appendToMessage(context, "Invalid information entered", 
                            validationErrors);
        }
    }
@


1.31
log
@Print stack traces along with errors instead of just the (often unhelpful) messages. Sticks with the messages, however unhelpful, in production environments.
@
text
@d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.30 2001/07/13 19:47:34 leonardr Exp $
d270 4
a273 5
                    Log.debug("!!!!!!!!!!!!!!!!!!");
                    Log.debug(myProperties.getProperty
                              ("inProductionEnvironment"));
                    if ("false".equals(myProperties.getProperty
                                       ("inProductionEnvironment")))
@


1.30
log
@Minor new functionality avaliable to servlets to automatically check for the presence of 'current' values for business objects.
@
text
@d53 1
d78 1
d94 1
a94 1
 * @@version $Id: BaseHelmServlet.java,v 1.29 2001/07/12 20:10:49 leonardr Exp $
a267 1
                    // wouldn't it be nice to see the stack trace somewhere?
d269 14
a282 1
                    redirectToError(context, e.getMessage());
@


1.29
log
@shortDisplayName should always be something that can be displayed.
@
text
@d92 1
a92 1
 * @@version $Id: BaseHelmServlet.java,v 1.28 2001/07/12 00:50:17 leonardr Exp $
d1380 10
@


1.28
log
@Fixed ticket bug and got rid of the need to store ticket in session.
@
text
@d92 1
a92 1
 * @@version $Id: BaseHelmServlet.java,v 1.27 2001/07/11 23:13:30 leonardr Exp $
d570 4
@


1.27
log
@Trim leading and trailing spaces in form fields, except when obtaining passwords.
@
text
@d92 1
a92 1
 * @@version $Id: BaseHelmServlet.java,v 1.26 2001/07/09 15:21:16 leonardr Exp $
d1658 1
@


1.26
log
@Always give broadcastMessage a value, even if it's just the empty string.
@
text
@d92 1
a92 1
 * @@version $Id: BaseHelmServlet.java,v 1.25 2001/07/03 23:21:51 ms Exp $
d1626 1
a1626 1
                            missingFields);
d1635 1
a1635 1
        return processField(context, key, defaultValue, null, null);
d1659 1
a1659 1
                            description, missingFields);
d1667 15
d1696 2
d1702 1
a1702 1
                                   List missingFields)
d1713 4
d1720 30
@


1.25
log
@added VelocityEventCartridge to handle exceptions thrown in templates that stop rendering of pages. Need to more intelligently handle them but otherwise the page would jsut stop rendering. Coupled to BaseHelmServlet. Minor change in StartPage.vm that saves a full iteration over the projects in the context
@
text
@d92 1
a92 1
 * @@version $Id: BaseHelmServlet.java,v 1.24 2001/06/07 19:06:51 elicia Exp $
d738 1
d741 1
a741 3
                String broadcast = message.getMessageText();
                context.put(BROADCAST_MESSAGE_KEY,
                            broadcast == null ? EMPTY_STRING : broadcast);
d743 2
@


1.24
log
@changed "shortName" to "shortDisplayName" for the context variable that the bread crumbs navigation on the Project_Nav. For example, for any of the ProjectDocuments page (Add, Edit, List) the shortDisplayName will be "Documents".
@
text
@d84 1
d92 1
a92 1
 * @@version $Id: BaseHelmServlet.java,v 1.23 2001/06/07 03:07:20 elicia Exp $
d719 4
@


1.23
log
@added shortName property to the context
@
text
@d91 1
a91 1
 * @@version $Id: BaseHelmServlet.java,v 1.22 2001/06/07 00:24:25 dlr Exp $
d568 2
a569 2
        String shortName = myProperties.getProperty("shortName");
        context.put("shortName", shortName);
@


1.22
log
@Removed errant references to UnsecureServlet (part of Joist, which we
are moving away from in favor of Turbine).
@
text
@d91 1
a91 1
 * @@version $Id: BaseHelmServlet.java,v 1.21 2001/06/04 01:33:57 dlr Exp $
d568 2
@


1.21
log
@Added a comment regarding the dubious nature of the Joist-legacy
server-only redirect.
@
text
@d91 1
a91 1
 * @@version $Id: BaseHelmServlet.java,v 1.20 2001/05/30 21:51:16 dlr Exp $
d372 1
a372 1
                Log.debug("UnsecureServlet: Unhandled exception in the " +
d1266 1
a1266 1
        synchronized (UnsecureServlet.class)
d1489 1
a1489 1
        Log.debug("UnsecureServlet initialized " + initInfo);
@


1.20
log
@Use Velocity's public HttpServletResponse implementation to side-step
retardo introspection issues.  Geir indicates that he's got something
cooking for the next release that will obviate the needs for such
machinations.
@
text
@d91 1
a91 1
 * @@version $Id: BaseHelmServlet.java,v 1.19 2001/05/25 20:46:47 dlr Exp $
d856 3
d1393 1
a1393 1
            text = "Sorry, an error has occurred:<p>" + text;
@


1.19
log
@Renamed some properties.
@
text
@d68 1
d91 1
a91 1
 * @@version $Id: BaseHelmServlet.java,v 1.18 2001/05/25 00:04:46 dlr Exp $
d562 1
a562 1
        context.put("res", response);
@


1.18
log
@Turned off debug.
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.17 2001/05/24 23:42:07 dlr Exp $
d142 1
a142 1
     * The properties key to the default mount point.
d144 1
a144 2
    private static final String DEF_MNT_PT =
        "org.joist.security.UnsecureServlet.mountPoint.default";
d180 1
a180 2
    private final static String WEBSTATS_BOOL =
        "org.joist.security.UnsecureServlet.webStats.on";
d1360 1
a1360 1
            (myProperties.getProperty(WEBSTATS_BOOL)).booleanValue();
@


1.17
log
@* Added a tad of doc to ACTION_KEY.

* Added BUTTON_KEY constant.

* Reworked addition of the user action to the context.

* Refactored getAction(Context) to try both harder and more
intelligently to get the action.
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.16 2001/05/24 23:00:39 dlr Exp $
d128 1
a128 1
    private static final boolean DEBUG = true;
@


1.16
log
@The templateDirectory context variable is already concatenated onto
the servletTemplate context variable, and is not used in any core Helm
templates.
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.15 2001/05/24 22:59:05 dlr Exp $
d116 1
a116 1
     * The action context key.
d121 5
d605 1
a605 1
        String action = (String)context.get(ACTION_KEY);
d608 1
a608 1
            action = (String)context.get("Button");
a1028 1

d1034 1
a1034 1
     * @@param    context    the Context partially populated by WMServlet
a1041 1

d1043 3
a1045 1
     * Gets the action specified by the last button pushed.
d1047 2
a1048 2
     * @@param context The context to grab the action from
     * @@return a String containing the action
d1052 1
a1052 1
        String action = getParameter(context, ACTION_KEY);
d1055 5
a1059 1
            action = (String) context.get(ACTION_KEY);
@


1.15
log
@Nobody liked BRANDNAME anyway... (Assuming legacy.)
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.14 2001/05/24 22:53:36 dlr Exp $
a651 5

        String templateDirectory =
            myProperties.getProperty("servletDirectory");

        context.put("servletDirectory", templateDirectory);
@


1.14
log
@Don't add a null broadcast message to the context (Velocity complains
via its log file).
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.13 2001/05/24 22:40:52 dlr Exp $
a641 3

        String brandName = myProperties.getProperty("BRANDNAME");
        context.put("BRANDNAME", brandName);
@


1.13
log
@Further clarified properties comment.
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.12 2001/05/24 22:39:51 dlr Exp $
d123 1
a123 1
    private static final boolean DEBUG = false;
d735 6
a740 2
            context.put(BROADCAST_MESSAGE_KEY,
                        message == null ? "" : message.getMessageText());
@


1.12
log
@Log the entire template path and use less memory.
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.11 2001/05/24 21:06:43 dlr Exp $
d664 2
a665 2
        // servletDirectory - Base application package.
        // servletTemplate  - Application-specific package + file
@


1.11
log
@Still need to take the per-servlet servletDirectory property into
consideration (but it should be combined w/ servletTemplate).
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.10 2001/05/24 18:49:38 dlr Exp $
d668 2
a669 2
        String servletTemplate = myProperties.getProperty("servletTemplate");
        String servletDirectory = myProperties.getProperty("servletDirectory");
d671 1
a671 2
        context.put("servletTemplate",
                    servletDirectory + File.separatorChar + servletTemplate);
@


1.10
log
@Don't add $SANDBOX to the context (removed in the templates, and as
per the comments).
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.9 2001/05/24 18:37:28 dlr Exp $
d664 4
d669 1
d671 2
a672 1
        context.put("servletTemplate", servletTemplate);
@


1.9
log
@Munging of the template path is no longer necessary, as multiple
template paths are configured for Velocity via the
TurbineResources.properties file.
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.8 2001/05/24 17:06:37 dlr Exp $
a641 4

        //REM: davidp thinks $SANDBOX is no longer needed
        String sandbox = myProperties.getProperty("SANDBOX");
        context.put("SANDBOX", sandbox);
@


1.8
log
@DEBUG should be false.  Ooops.
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.7 2001/05/24 17:06:07 dlr Exp $
d650 1
a653 2
        // The above assignment could be over-ridden in non-cooked operation.
        // See the else clause below ...
d655 1
d669 2
a670 29
        if (DEBUG) Log.debug("servlet template: "+servletTemplate);

        StringBuffer fullTemplate = new StringBuffer();

        String useCookedTemplates =
            myProperties.getProperty("useCookedTemplates");
        if ("true".equalsIgnoreCase(useCookedTemplates))
        {
            // When using cooked templates, specify the full path to the cooked
            // version of the servlet-specific template.  This must be relative
            // to the TemplatePath specified in WebMacro.properties.
            // Ex: .../site/templates/org/helm/admin/ProjectList.vm
            fullTemplate.append(servletTemplateRoot).append(File.separatorChar);
            fullTemplate.append(templateDirectory).append(File.separatorChar);
            fullTemplate.append(servletTemplate);
        }
        else
        {
            // When using uncooked templates, specify the top-level template
            // into which the servlet-specific template will be #parse'd
            // relative to TemplatePath in Webmacro.properties.
            // Ex: .../data/helm/htdocs/look/www/Standard.vm
            fullTemplate.append(brandTemplateRoot).append(File.separatorChar);
            fullTemplate.append(masterTemplateName);
        }

        context.put("servletTemplate", 
                    templateDirectory + File.separatorChar + servletTemplate);
        if (DEBUG) Log.debug("template: " + fullTemplate.toString());
d722 1
a722 1
        return fullTemplate.toString();
d1303 1
a1303 1
        if (DEBUG) Log.debug("Default template name: " + masterTemplateName);
@


1.7
log
@Corrected comment format.
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.6 2001/05/23 22:39:23 dlr Exp $
d123 1
a123 1
    private static final boolean DEBUG = true;
@


1.6
log
@Changed examples to use Velocity template extensions.
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.5 2001/05/23 02:40:36 dlr Exp $
d123 1
a123 1
    private static final boolean DEBUG = false;
d173 2
a174 1
    /** Key to pull webStats on/off property
@


1.5
log
@Adding FormCache to context.
@
text
@d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.4 2001/05/23 01:50:20 dlr Exp $
d679 1
a679 1
            // Ex: .../site/templates/org/helm/admin/ProjectList.wm
d689 1
a689 1
            // Ex: .../data/helm/htdocs/look/www/Standard.wm
@


1.4
log
@Ported Helm from WebMacro to Velocity.
@
text
@d72 1
a72 1
import org.joist.util.FormCache;
d90 1
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.3 2001/05/04 18:34:30 leonardr Exp $
a230 2
        // TODO: Add FormCache to context here.

d512 2
@


1.3
log
@Handle a null message better.
@
text
@d48 6
a53 1
import java.sql.*;
d55 2
a59 1
import org.apache.turbine.util.db.Criteria;
d61 5
d67 2
a68 1
import org.webmacro.servlet.*;
d70 4
a74 1
import org.joist.session.*;
d79 1
d81 1
d85 1
a85 1
 * A basic Helm layer which overlays some UnsecureServlet methods.
d88 3
a90 1
 * @@version $Id: BaseHelmServlet.java,v 1.2 2001/04/17 07:49:23 dlr Exp $
d94 1
a94 1
public abstract class BaseHelmServlet extends UnsecureServlet
d96 27
d126 626
d754 2
a755 3
    protected void populateWithBroadcastMessage(Connection connection, 
                                                WebContext context)
        throws HandlerException
d765 1036
a1800 1
            throw new HandlerException(e.getMessage());
@


1.2
log
@Broke long line.
@
text
@d71 1
a71 1
 * @@version $Id: BaseHelmServlet.java,v 1.1 2001/04/17 00:19:40 leonardr Exp $
d88 1
d90 1
a90 1
                        MessagePeer.getBroadcastMessage().getMessageText());
@


1.2.2.1
log
@Back ported Joist servlets which have been merged into Helm in the HEAD.
@
text
@d71 1
a71 1
 * @@version $Id: BaseHelmServlet.java,v 1.2 2001/04/17 07:49:23 dlr Exp $
d77 19
@


1.2.2.1.2.1
log
@making HelmProperties work
@
text
@a64 1
import org.tigris.helm.tool.HelmProperties;
d71 1
a71 1
 * @@version $Id: BaseHelmServlet.java,v 1.2.2.1 2001/04/25 23:48:39 dlr Exp $
a76 45


    public void start()
        throws ServletException
    {
        // Start by reading the initialization parameters into a Properties
        // object.  Make the System properties supply defaults.
        try {
            super.start();

        Properties initParameters = new Properties(System.getProperties());
        ServletConfig config = getServletConfig();
        if (config == null)
        {
            throw new ServletException("ServletConfig is null");
        }

        Enumeration parameterNames = config.getInitParameterNames();
        String paramName;
        while (parameterNames.hasMoreElements())
        {
            paramName = (String)parameterNames.nextElement();
            initParameters.put(paramName, config.getInitParameter(paramName));
        }

        // Get the name of the site properties file from the zone properties,
        // then open the file and load the properties.  Make the zone
        // properties supply defaults.
        Properties siteProperties = new Properties(initParameters);
        String sitePropertiesFile =
            initParameters.getProperty("siteProperties");

        if (sitePropertiesFile != null)
        {
            readProperties(sitePropertiesFile, siteProperties);
        }

        // Make the properties built up thus far globally accessible.
        HelmProperties.getInstance().init(siteProperties);

        }
        catch (Exception e) {
            Log.error(e);
        }
    }
@


1.1
log
@Moved from Message, the last of the Joist tables, to HELM_MESSAGE. A few minor problems with Joist servlets remain.
@
text
@d71 1
a71 1
 * @@version $Id: HelmServlet.java,v 1.92 2001/04/16 19:52:42 dlr Exp $
d88 2
a89 1
            context.put(BROADCAST_MESSAGE_KEY, MessagePeer.getBroadcastMessage().getMessageText());
@

