You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by cr...@apache.org on 2001/05/04 07:07:09 UTC

cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core FastEngineMapper.java ContainerBase.java LocalStrings.properties StandardEngine.java StandardEngineValve.java

craigmcc    01/05/03 22:07:09

  Modified:    catalina/src/share/org/apache/catalina/core
                        ContainerBase.java LocalStrings.properties
                        StandardEngine.java StandardEngineValve.java
  Added:       catalina/src/share/org/apache/catalina/core
                        FastEngineMapper.java
  Log:
  Make it possible to dynamically select the Mapper implementation class to use
  for the StandardEngine implementation.  This is done by setting the
  "mapperClass" attribute of the <Engine> element.
  
  Add a new Mapper implementation for StandardEngine that is optimized for
  performance.  Among other things, it caches mappings for all define host names
  and aliases, and remembers each mapping to the default host (if any) after
  the first time.  No object creations occur during request processing.
  
  The default mapper is still the previous standard one.  If you wish to
  experiment, select the new implementation by the following in your
  server.xml file:
  
      <Engine ... mapperClass="org.apache.catalina.core.FastEngineMapper" .../>
  
  When we are satisfied that this class works correctly, it will become the
  default.
  
  Revision  Changes    Path
  1.11      +5 -7      jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ContainerBase.java
  
  Index: ContainerBase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ContainerBase.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- ContainerBase.java	2001/04/10 01:37:08	1.10
  +++ ContainerBase.java	2001/05/04 05:07:07	1.11
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ContainerBase.java,v 1.10 2001/04/10 01:37:08 craigmcc Exp $
  - * $Revision: 1.10 $
  - * $Date: 2001/04/10 01:37:08 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ContainerBase.java,v 1.11 2001/05/04 05:07:07 craigmcc Exp $
  + * $Revision: 1.11 $
  + * $Date: 2001/05/04 05:07:07 $
    *
    * ====================================================================
    *
  @@ -153,7 +153,7 @@
    * class comments of the implementation class.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.10 $ $Date: 2001/04/10 01:37:08 $
  + * @version $Revision: 1.11 $ $Date: 2001/05/04 05:07:07 $
    */
   
   public abstract class ContainerBase
  @@ -1031,6 +1031,7 @@
   	if (started)
   	    throw new LifecycleException
   		(sm.getString("containerBase.alreadyStarted", logName()));
  +	addDefaultMapper(this.mapperClass);
   	started = true;
   
   	// Start our subordinate components, if any
  @@ -1044,9 +1045,6 @@
   	    ((Lifecycle) realm).start();
   	if ((resources != null) && (resources instanceof Lifecycle))
   	    ((Lifecycle) resources).start();
  -
  -	// Add a default Mapper if none have been defined
  -	addDefaultMapper(this.mapperClass);
   
   	// Start our Mappers, if any
   	Mapper mappers[] = findMappers();
  
  
  
  1.32      +3 -185    jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/LocalStrings.properties
  
  Index: LocalStrings.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/LocalStrings.properties,v
  retrieving revision 1.31
  retrieving revision 1.32
  diff -u -r1.31 -r1.32
  --- LocalStrings.properties	2001/04/25 02:20:48	1.31
  +++ LocalStrings.properties	2001/05/04 05:07:07	1.32
  @@ -1,370 +1,188 @@
   applicationContext.attributeEvent=Exception thrown by attributes event listener
  -
   applicationContext.requestDispatcher.iae=Path {0} does not start with a "/" character
  -
   applicationDispatcher.allocateException=Allocate exception for servlet {0}
  -
   applicationDispatcher.deallocateException=Deallocate exception for servlet {0}
  -
   applicationDispatcher.forward.ise=Cannot forward after response has been committed
  -
   applicationDispatcher.forward.throw=Forwarded resource threw an exception
  -
   applicationDispatcher.include.throw=Included resource threw an exception
  -
   applicationDispatcher.isUnavailable=Servlet {0} is currently unavailable
  -
   applicationDispatcher.serviceException=Servlet.service() for servlet {0} threw exception
  -
   applicationRequest.badParent=Cannot locate parent Request implementation
  -
   applicationRequest.badRequest=Request is not a javax.servlet.ServletRequestWrapper
  -
   applicationResponse.badParent=Cannot locate parent Response implementation
  -
   applicationResponse.badResponse=Response is not a javax.servlet.ServletResponseWrapper
  -
   containerBase.addDefaultMapper=Exception configuring default mapper of class {0}
  -
   containerBase.alreadyStarted=Container {0} has already been started
  -
   containerBase.notConfigured=No basic Valve has been configured
  -
   containerBase.notStarted=Container {0} has not been started
  -
  +fastEngineMapper.alreadyStarted=FastEngineMapper {0} has already been started
  +fastEngineMapper.notStarted=FastEngineMapper {0} has not yet been started
   filterChain.filter=Filter execution threw an exception
  -
   filterChain.servlet=Servlet execution threw an exception
  -
   httpContextMapper.container=This container is not a StandardContext
  -
   httpEngineMapper.container=This container is not a StandardEngine
  -
   httpHostMapper.container=This container is not a StandardHost
  -
   interceptorValve.alreadyStarted=InterceptorValve has already been started
  -
   interceptorValve.notStarted=InterceptorValve has not yet been started
  -
   standardContext.alreadyStarted=Context has already been started
  -
   standardContext.applicationListener=Error configuring application listener of class {0}
  -
   standardContext.applicationSkipped=Skipped installing application listeners due to previous error(s)
  -
   standardContext.badRequest=Invalid request path ({0}).
  -
   standardContext.errorPage.error=Error page location {0} must start with a '/'
  -
   standardContext.errorPage.required=ErrorPage cannot be null
  -
   standardContext.errorPage.warning=WARNING: Error page location {0} must start with a '/' in Servlet 2.3
  -
   standardContext.filterMap.either=Filter mapping must specify either a <url-pattern> or a <servlet-name>
  -
   standardContext.filterMap.name=Filter mapping specifies an unknown filter name {0}
  -
   standardContext.filterMap.pattern=Invalid <url-pattern> {0} in filter mapping
  -
   standardContext.filterStart=Exception starting filter {0}
  -
   standardContext.filterStartFailed=Failed to start application Filters successfully
  -
   standardContext.isUnavailable=This application is not currently available
  -
   standardContext.listenerStart=Exception sending context initialized event to listener instance of class {0}
  -
   standardContext.listenerStartFailed=Failed to start application Listeners successfully
  -
   standardContext.listenerStop=Exception sending context destroyed event to listener instance of class {0}
  -
   standardContext.loginConfig.errorPage=Form error page {0} must start with a '/'
  -
   standardContext.loginConfig.errorWarning=WARNING: Form error page {0} must start with a '/' in Servlet 2.3
  -
   standardContext.loginConfig.loginPage=Form login page {0} must start with a '/'
  -
   standardContext.loginConfig.loginWarning=WARNING: Form login page {0} must start with a '/' in Servlet 2.3
  -
   standardContext.loginConfig.required=LoginConfig cannot be null
  -
   standardContext.mappingError=MAPPING configuration error for relative URI {0}
  -
   standardContext.notFound=The requested resource ({0}) is not available.
  -
   standardContext.notReloadable=Reloading is disabled on this Context
  -
   standardContext.notStarted=Context has not yet been started
  -
   standardContext.notWrapper=Child of a Context must be a Wrapper
  -
   standardContext.parameter.duplicate=Duplicate context initialization parameter {0}
  -
   standardContext.parameter.required=Both parameter name and parameter value are required
  -
   standardContext.reloadingCompleted=Reloading this Context is completed
  -
   standardContext.reloadingFailed=Reloading this Context failed due to previous errors
  -
   standardContext.reloadingStarted=Reloading this Context has started
  -
   standardContext.securityConstraint.pattern=Invalid <url-pattern> {0} in security constraint
  -
   standardContext.servletMap.name=Servlet mapping specifies an unknown servlet name {0}
  -
   standardContext.servletMap.pattern=Invalid <url-pattern> {0} in servlet mapping
  -
   standardContext.startFailed=Context startup failed due to previous errors
  -
   standardContext.startingLoader=Exception starting Loader
  -
   standardContext.startingManager=Exception starting Manager
  -
   standardContext.startingWrapper=Exception starting Wrapper for servlet {0}
  -
   standardContext.stoppingLoader=Exception stopping Loader
  -
   standardContext.stoppingManager=Exception stopping Manager
  -
   standardContext.stoppingWrapper=Exception stopping Wrapper for servlet {0}
  -
   standardContext.urlDecode=Cannot URL decode request path {0}
  -
   standardContext.urlPattern.patternWarning=WARNING: URL pattern {0} must start with a '/' in Servlet 2.3
  -
   standardContext.wrapper.error=JSP file {0} must start with a '/'
  -
   standardContext.wrapper.warning=WARNING: JSP file {0} must start with a '/' in Servlet 2.3
  -
   standardContext.invalidEnvEntryValue={0} environment entry has an invalid value for specified type
  -
   standardContext.invalidEnvEntryType={0} environment entry has an invalid type
  -
   standardContext.bindFailed=Bind naming operation failed : {0}
  -
   standardContext.namingInitFailed=Error initializing naming context for context {0}
  -
   standardEngine.alreadyStarted=Engine has already been started
  -
   standardEngine.mappingError=MAPPING configuration error for server name {0}
  -
  +standardEngine.noHost=No Host matches server name {0}
   standardEngine.notHost=Child of an Engine must be a Host
  -
   standardEngine.notParent=Engine cannot have a parent Container
  -
   standardEngine.notStarted=Engine has not yet been started
  -
   standardEngine.unfoundHost=Virtual host {0} not found
  -
   standardEngine.unknownHost=No server host specified in this request
  -
   standardHost.accessBase=Cannot access document base directory {0}
  -
   standardHost.alreadyStarted=Host has already been started
  -
   standardHost.appBase=Application base directory {0} does not exist
  -
   standardHost.installing=Installing web application at context path {0} from URL {1}
  -
   standardHost.installError=Error deploying application at context path {0}
  -
   standardHost.docBase=Document base directory {0} already exists
  -
   standardHost.mappingError=MAPPING configuration error for request URI {0}
  -
   standardHost.noContext=No Context configured to process this request
  -
   standardHost.noHost=No Host configured to process this request
  -
   standardHost.notContext=Child of a Host must be a Context
  -
   standardHost.notStarted=Host has not yet been started
  -
   standardHost.nullName=Host name is required
  -
   standardHost.pathFormat=Invalid context path: {0}
  -
   standardHost.pathMissing=Context path {0} is not currently in use
  -
   standardHost.pathRequired=Context path is required
  -
   standardHost.pathUsed=Context path {0} is already in use
  -
   standardHost.removing=Removing web application at context path {0}
  -
   standardHost.removeError=Error removing application at context path {0}
  -
   standardHost.start=Starting web application at context path {0}
  -
   standardHost.stop=Stopping web application at context path {0}
  -
   standardHost.unfoundContext=Cannot find context for request URI {0}
  -
   standardHost.warRequired=URL to web application archive is required
  -
   standardHost.warURL=Invalid URL for web application archive: {0}
  -
   standardPipeline.alreadyStarted=Pipeline has already been started
  -
   standardPipeline.notStarted=Pipeline has not been started
  -
   standardPipeline.noValve=No more Valves in the Pipeline processing this request
  -
   standardServer.addContainer.ise=No connectors available to associate this container with
  -
   standardServer.start.connectors=At least one connector is not associated with any container
  -
   standardServer.start.started=This server has already been started
  -
   standardServer.stop.notStarted=This server has not yet been started
  -
   standardService.start.name=Starting service {0}
  -
   standardService.start.started=This service has already been started
  -
   standardService.stop.name=Stopping service {0}
  -
   standardService.stop.notStarted=This service has not yet been started
  -
   standardWrapper.allocate=Error allocating a servlet instance
  -
   standardWrapper.allocateException=Allocate exception for servlet {0}
  -
   standardWrapper.containerServlet=Loading container servlet {0}
  -
   standardWrapper.createFilters=Create filters exception for servlet {0}
  -
   standardWrapper.deallocateException=Deallocate exception for servlet {0}
  -
   standardWrapper.destroyException=Servlet.destroy() for servlet {0} threw exception
  -
   standardWrapper.exception0=Tomcat Exception Report
  -
   standardWrapper.exception1=A Servlet Exception Has Occurred
  -
   standardWrapper.exception2=Exception Report:
  -
   standardWrapper.exception3=Root Cause:
  -
   standardWrapper.initException=Servlet.init() for servlet {0} threw exception
  -
   standardWrapper.instantiate=Error instantiating servlet class {0}
  -
   standardWrapper.isUnavailable=Servlet {0} is currently unavailable
  -
   standardWrapper.jasperLoader=Using Jasper classloader for servlet {0}
  -
   standardWrapper.jspFile.format=JSP file {0} does not start with a '/' character
  -
   standardWrapper.loadException=Servlet {0} threw load() exception
  -
   standardWrapper.missingClass=Wrapper cannot find servlet class {0} or a class it depends on
  -
   standardWrapper.missingLoader=Wrapper cannot find Loader for servlet {0}
  -
   standardWrapper.notChild=Wrapper container may not have child containers
  -
   standardWrapper.notClass=No servlet class has been specified for servlet {0}
  -
   standardWrapper.notContext=Parent container of a Wrapper must be a Context
  -
   standardWrapper.notServlet=Class {0} is not a Servlet
  -
   standardWrapper.releaseFilters=Release filters exception for servlet {0}
  -
   standardWrapper.serviceException=Servlet.service() for servlet {0} threw exception
  -
   standardWrapper.statusHeader=HTTP Status {0} - {1}
  -
   standardWrapper.statusTitle=Tomcat Error Report
  -
   standardWrapper.unavailable=Marking servlet {0} as unavailable
  -
   standardWrapper.unloadException=Servlet {0} threw unload() exception
  -
   standardWrapper.unloading=Cannot allocate servlet {0} because it is being unloaded
  -
   http.100=The client may continue ({0}).
  -
   http.101=The server is switching protocols according to the "Upgrade" header ({0}).
  -
   http.201=The request succeeded and a new resource ({0}) has been created on the server.
  -
   http.202=This request was accepted for processing, but has not been completed ({0}).
  -
   http.203=The meta information presented by the client did not originate from the server ({0}).
  -
   http.204=The request succeeded but there is no information to return ({0}).
  -
   http.205=The client should reset the document view which caused this request to be sent ({0}).
  -
   http.206=The server has fulfilled a partial GET request for this resource ({0}).
  -
   http.207=Multiple status values have been returned ({0}).
  -
   http.300=The requested resource ({0}) corresponds to any one of a set of representations, each with its own specific location.
  -
   http.301=The requested resource ({0}) has moved permanently to a new location.
  -
   http.302=The requested resource ({0}) has moved temporarily to a new location.
  -
   http.303=The response to this request can be found under a different URI ({0}).
  -
   http.304=The requested resource ({0}) is available and has not been modified.
  -
   http.305=The requested resource ({0}) must be accessed through the proxy given by the "Location" header.
  -
   http.400=The request sent by the client was syntactically incorrect ({0}).
  -
   http.401=This request requires HTTP authentication ({0}).
  -
   http.402=Payment is required for access to this resource ({0}).
  -
   http.403=Access to the specified resource ({0}) has been forbidden.
  -
   http.404=The requested resource ({0}) is not available.
  -
   http.405=The specified HTTP method is not allowed for the requested resource ({0}).
  -
   http.406=The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers ({0}).
  -
   http.407=The client must first authenticate itself with the proxy ({0}).
  -
   http.408=The client did not produce a request within the time that the server was prepared to wait ({0}).
  -
   http.409=The request could not be completed due to a conflict with the current state of the resource ({0}).
  -
   http.410=The requested resource ({0}) is no longer available, and no forwarding address is known.
  -
   http.411=This request cannot be handled without a defined content length ({0}).
  -
   http.412=A specified precondition has failed for this request ({0}).
  -
   http.413=The request entity is larger than the server is willing or able to process.
  -
   http.414=The server refused this request because the request URI was too long ({0}).
  -
   http.415=The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ({0}).
  -
   http.416=The requested byte range cannot be satisfied ({0}).
  -
   http.417=The expectation given in the "Expect" request header ({0}) could not be fulfilled.
  -
   http.422=The server understood the content type and syntax of the request but was unable to process the contained instructions ({0}).
  -
   http.423=The source or destination resource of a method is locked ({0}).
  -
   http.500=The server encountered an internal error ({0}) that prevented it from fulfilling this request.
  -
   http.501=The server does not support the functionality needed to fulfill this request ({0}).
  -
   http.502=This server received an invalid response from a server it consulted when acting as a proxy or gateway ({0}).
  -
   http.503=The requested service ({0}) is not currently available.
  -
   http.504=The server received a timeout from an upstream server while acting as a gateway or proxy ({0}).
  -
   http.505=The server does not support the requested HTTP protocol version ({0}).
  -
   http.507=The resource does not have sufficient space to record the state of the resource after execution of this method ({0}).
  -
  
  
  
  1.8       +31 -6     jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardEngine.java
  
  Index: StandardEngine.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardEngine.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- StandardEngine.java	2001/02/26 04:59:29	1.7
  +++ StandardEngine.java	2001/05/04 05:07:08	1.8
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardEngine.java,v 1.7 2001/02/26 04:59:29 remm Exp $
  - * $Revision: 1.7 $
  - * $Date: 2001/02/26 04:59:29 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardEngine.java,v 1.8 2001/05/04 05:07:08 craigmcc Exp $
  + * $Revision: 1.8 $
  + * $Date: 2001/05/04 05:07:08 $
    *
    * ====================================================================
    *
  @@ -85,7 +85,7 @@
    * fully qualified host name of that virtual host.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.7 $ $Date: 2001/02/26 04:59:29 $
  + * @version $Revision: 1.8 $ $Date: 2001/05/04 05:07:08 $
    */
   
   public class StandardEngine
  @@ -181,6 +181,31 @@
       }
   
   
  +    /**
  +     * Return the default Mapper class name.
  +     */
  +    public String getMapperClass() {
  +
  +        return (this.mapperClass);
  +
  +    }
  +
  +
  +    /**
  +     * Set the default Mapper class name.
  +     *
  +     * @param mapperClass The new default Mapper class name
  +     */
  +    public void setMapperClass(String mapperClass) {
  +
  +        String oldMapperClass = this.mapperClass;
  +        this.mapperClass = mapperClass;
  +        support.firePropertyChange("mapperClass",
  +                                   oldMapperClass, this.mapperClass);
  +
  +    }
  +
  +
       // --------------------------------------------------------- Public Methods
   
   
  @@ -268,14 +293,14 @@
       }
   
   
  -    // -------------------------------------------------------- Private Methods
  +    // ------------------------------------------------------ Protected Methods
   
   
       /**
        * Add a default Mapper implementation if none have been configured
        * explicitly.
        *
  -     * @param mapperClass Java class name of the default Mapper
  +     * @param mapperClass The default mapper class name to add
        */
       protected void addDefaultMapper(String mapperClass) {
   
  
  
  
  1.4       +6 -5      jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardEngineValve.java
  
  Index: StandardEngineValve.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardEngineValve.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- StandardEngineValve.java	2001/01/23 02:51:15	1.3
  +++ StandardEngineValve.java	2001/05/04 05:07:08	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardEngineValve.java,v 1.3 2001/01/23 02:51:15 craigmcc Exp $
  - * $Revision: 1.3 $
  - * $Date: 2001/01/23 02:51:15 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardEngineValve.java,v 1.4 2001/05/04 05:07:08 craigmcc Exp $
  + * $Revision: 1.4 $
  + * $Date: 2001/05/04 05:07:08 $
    *
    * ====================================================================
    *
  @@ -86,7 +86,7 @@
    * when processing HTTP requests.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.3 $ $Date: 2001/01/23 02:51:15 $
  + * @version $Revision: 1.4 $ $Date: 2001/05/04 05:07:08 $
    */
   
   final class StandardEngineValve
  @@ -154,7 +154,8 @@
   	if (host == null) {
   	    ((HttpServletResponse) response.getResponse()).sendError
   		(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
  -		 sm.getString("standardEngine.notHost"));
  +		 sm.getString("standardEngine.noHost",
  +                              request.getRequest().getServerName()));
   	    return;
   	}
   
  
  
  
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/FastEngineMapper.java
  
  Index: FastEngineMapper.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/FastEngineMapper.java,v 1.1 2001/05/04 05:07:07 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2001/05/04 05:07:07 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2001 The Apache Software Foundation.  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 the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 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 THE APACHE SOFTWARE FOUNDATION 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 the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  
  package org.apache.catalina.core;
  
  
  import java.beans.PropertyChangeEvent;
  import java.beans.PropertyChangeListener;
  import java.util.ArrayList;
  import java.util.Iterator;
  import org.apache.catalina.Container;
  import org.apache.catalina.ContainerEvent;
  import org.apache.catalina.ContainerListener;
  import org.apache.catalina.Engine;
  import org.apache.catalina.Host;
  import org.apache.catalina.Lifecycle;
  import org.apache.catalina.LifecycleEvent;
  import org.apache.catalina.LifecycleException;
  import org.apache.catalina.LifecycleListener;
  import org.apache.catalina.Mapper;
  import org.apache.catalina.Request;
  import org.apache.catalina.util.LifecycleSupport;
  import org.apache.catalina.util.StringManager;
  
  
  /**
   * Implementation of <code>Mapper</code> for an <code>Engine</code>,
   * designed to process HTTP requests.  This mapper selects an appropriate
   * <code>Host</code> based on the server name included in the request.
   * <p>
   * <b>IMPLEMENTATION NOTE</b>:  This Mapper only works with a
   * <code>StandardEngine</code>, because it relies on internal APIs.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2001/05/04 05:07:07 $
   */
  
  public final class FastEngineMapper
      implements ContainerListener, Lifecycle, Mapper, PropertyChangeListener {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * Cache of hostname -> Host mappings.  FIXME - use FastHashMap.
       */
      private java.util.HashMap cache = new java.util.HashMap();
  
  
      /**
       * The default host used for unknown host names.
       */
      private Host defaultHost = null;
  
  
      /**
       * The debugging detail level for this component.
       */
      private int debug = 0;
  
  
      /**
       * The Container with which this Mapper is associated.
       */
      private StandardEngine engine = null;
  
  
      /**
       * The lifecycle event support for this component.
       */
      private LifecycleSupport lifecycle = new LifecycleSupport(this);
  
  
      /**
       * The protocol with which this Mapper is associated.
       */
      private String protocol = null;
  
  
      /**
       * The string manager for this package.
       */
      private static final StringManager sm =
          StringManager.getManager(Constants.Package);
  
  
      /**
       * Has this component been started yet?
       */
      private boolean started = false;
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Return the Container with which this Mapper is associated.
       */
      public Container getContainer() {
  
          return (engine);
  
      }
  
  
      /**
       * Set the Container with which this Mapper is associated.
       *
       * @param container The newly associated Container
       *
       * @exception IllegalArgumentException if this Container is not
       *  acceptable to this Mapper
       */
      public void setContainer(Container container) {
  
          if (!(container instanceof StandardEngine))
              throw new IllegalArgumentException
                  (sm.getString("httpEngineMapper.container"));
          engine = (StandardEngine) container;
  
      }
  
  
      /**
       * Return the protocol for which this Mapper is responsible.
       */
      public String getProtocol() {
  
          return (this.protocol);
  
      }
  
  
      /**
       * Set the protocol for which this Mapper is responsible.
       *
       * @param protocol The newly associated protocol
       */
      public void setProtocol(String protocol) {
  
          this.protocol = protocol;
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Return the child Container that should be used to process this Request,
       * based upon its characteristics.  If no such child Container can be
       * identified, return <code>null</code> instead.
       *
       * @param request Request being processed
       * @param update Update the Request to reflect the mapping selection?
       */
      public Container map(Request request, boolean update) {
  
          debug = engine.getDebug();
  
          // Extract the requested server name
          String server = request.getRequest().getServerName();
          if (server == null) {
              server = engine.getDefaultHost();
              if (update)
                  request.setServerName(server);
          }
          if (server == null)
              return (null);
          if (debug >= 1)
              engine.log("Mapping server name '" + server + "'");
  
          // Find the specified host in our cache
          if (debug >= 2)
              engine.log(" Trying a cache match");
          Host host = (Host) cache.get(server);
  
          // Map to the default host if any
          if ((host == null) && (defaultHost != null)) {
              if (debug >= 2)
                  engine.log(" Mapping to default host");
              host = defaultHost;
              addAlias(server, host);
          }
  
          // Update the Request if requested, and return the selected Host
          ;       // No update to the Request is required
          return (host);
  
      }
  
  
      // ---------------------------------------------- ContainerListener Methods
  
  
      /**
       * Acknowledge the occurrence of the specified event.
       *
       * @param event ContainerEvent that has occurred
       */
      public void containerEvent(ContainerEvent event) {
  
          Container source = (Container) event.getSource();
          String type = event.getType();
          if (source == engine) {
              if (Container.ADD_CHILD_EVENT.equals(type))
                  addHost((Host) event.getData());
              else if (Container.REMOVE_CHILD_EVENT.equals(type))
                  removeHost((Host) event.getData());
          } else if (source instanceof Host) {
              if (Host.ADD_ALIAS_EVENT.equals(type))
                  addAlias((String) event.getData(), (Host) source);
              else if (Host.REMOVE_ALIAS_EVENT.equals(type))
                  removeAlias((String) event.getData());
          }
  
      }
  
  
      // ------------------------------------------------------ Lifecycle Methods
  
  
      /**
       * Add a lifecycle event listener to this component.
       *
       * @param listener The listener to add
       */
      public void addLifecycleListener(LifecycleListener listener) {
  
          lifecycle.addLifecycleListener(listener);
  
      }
  
  
      /**
       * Remove a lifecycle event listener from this component.
       *
       * @param listener The listener to remove
       */
      public void removeLifecycleListener(LifecycleListener listener) {
  
          lifecycle.removeLifecycleListener(listener);
  
      }
  
  
      /**
       * Prepare for active use of the public methods of this Component.
       *
       * @exception IllegalStateException if this component has already been
       *  started
       * @exception LifecycleException if this component detects a fatal error
       *  that prevents it from being started
       */
      public synchronized void start() throws LifecycleException {
  
          // Validate and update our current component state
          if (started)
              throw new LifecycleException
                  (sm.getString("fastEngineMapper.alreadyStarted",
                                engine.getName()));
          started = true;
  
          // Configure based on our associated Engine properties
          engine.addContainerListener(this);
          engine.addPropertyChangeListener(this);
          setDefaultHost(engine.getDefaultHost());
  
          // Cache mappings for our child hosts
          Container children[] = engine.findChildren();
          for (int i = 0; i < children.length; i++) {
              addHost((Host) children[i]);
          }
  
          // Notify our interested LifecycleListeners
          lifecycle.fireLifecycleEvent(START_EVENT, null);
  
      }
  
  
      /**
       * Gracefully shut down active use of the public methods of this Component.
       *
       * @exception IllegalStateException if this component has not been started
       * @exception LifecycleException if this component detects a fatal error
       *  that needs to be reported
       */
      public synchronized void stop() throws LifecycleException {
  
          // Validate and update our current component state
          if (!started)
              throw new LifecycleException
                  (sm.getString("fastEngineMapper.notStarted",
                                engine.getName()));
  
          // Notify our interested LifecycleListeners
          lifecycle.fireLifecycleEvent(STOP_EVENT, null);
          started = false;
  
          // Deconfigure based on our associated Engine properties
          engine.removePropertyChangeListener(this);
          setDefaultHost(null);
          engine.removeContainerListener(this);
  
          // Clear our mapping cache
          cache.clear();
  
      }
  
  
      // ----------------------------------------- PropertyChangeListener Methods
  
  
      /**
       * Process a property change event.
       */
      public void propertyChange(PropertyChangeEvent event) {
  
          Object source = event.getSource();
          if (source instanceof Engine) {
              if ("defaultHost".equals(event.getPropertyName()))
                  setDefaultHost((String) event.getNewValue());
          }
  
      }
  
  
      // -------------------------------------------------------- Private Methods
  
  
      /**
       * Add an alias for the specified host.
       *
       * @param alias New alias name
       * @param host Host to resolve to
       */
      private void addAlias(String alias, Host host) {
  
          if (debug >= 3)
              engine.log("Adding alias '" + alias + "' for host '" +
                         host.getName() + "'");
          cache.put(alias.toLowerCase(), host);
  
      }
  
  
      /**
       * Add a new child Host to our associated Engine.
       *
       * @param host Child host to add
       */
      private void addHost(Host host) {
  
          if (debug >= 3)
              engine.log("Adding host '" + host.getName() + "'");
  
          host.addContainerListener(this);
  
          // Register the host name
          addAlias(host.getName(), host);
  
          // Register all associated aliases
          String aliases[] = host.findAliases();
          for (int i = 0; i < aliases.length; i++)
              addAlias(aliases[i], host);
  
      }
  
  
      /**
       * Return the Host that matches the specified name (or alias), if any;
       * otherwise, return <code>null</code>.
       *
       * @param name Name or alias of the desired Host
       */
      private Host findHost(String name) {
  
          return ((Host) cache.get(name.toLowerCase()));
  
      }
  
  
      /**
       * Remove the specified alias from our cache.
       *
       * @param alias Alias to remove
       */
      private void removeAlias(String alias) {
  
          if (debug >= 3)
              engine.log("Removing alias '" + alias + "'");
          cache.remove(alias.toLowerCase());
  
      }
  
  
      /**
       * Remove an existing child Host from our associated Engine.
       *
       * @param host Host to be removed
       */
      private void removeHost(Host host) {
  
          if (debug >= 3)
              engine.log("Removing host '" + host.getName() + "'");
  
          host.removeContainerListener(this);
  
          // Identify all names mapped to this host
          ArrayList removes = new ArrayList();
          Iterator keys = cache.keySet().iterator();
          while (keys.hasNext()) {
              String key = (String) keys.next();
              if (host.equals((Host) cache.get(key)))
                  removes.add(key);
          }
  
          // Remove the associated names
          keys = removes.iterator();
          while (keys.hasNext()) {
              removeAlias((String) keys.next());
          }
  
      }
  
  
      /**
       * Set the default Host used for resolving unknown host names.
       *
       * @param name Name of the default host
       */
      private void setDefaultHost(String name) {
  
          if (debug >= 3)
              engine.log("Setting default host '" + name + "'");
  
          if (name == null)
              defaultHost = null;
          else
              defaultHost = (Host) engine.findChild(name);
  
      }
  
  
  }