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

DO NOT REPLY [Bug 5181] - HttpConnector [8080] No processor available, rejecting this connection

DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=5181>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=5181

HttpConnector [8080] No processor available, rejecting this connection

dirk.herrmann@bb-data.de changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Severity|Critical                    |Normal
         OS/Version|Solaris                     |All
           Platform|Sun                         |All



------- Additional Comments From dirk.herrmann@bb-data.de  2002-01-17 22:18 -------

under heavy load (more then 200 request at same time) this coud be help,
changes marked as !!! Changed !!!

################################################################################

/*
 * $Header:
/home/a430499/PROJECTS/C-JAVIS/repository/de/bbdata/javis30/fix/HttpConnector.java,v
1.1 2002/01/18 05:35:31 a430499 Exp $
 * $Revision: 1.1 $
 * $Date: 2002/01/18 05:35:31 $
 *
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 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.connector.http;


import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.AccessControlException;
import java.util.Stack;
import java.util.Vector;
import java.util.Enumeration;
import org.apache.catalina.Connector;
import org.apache.catalina.Container;
import org.apache.catalina.HttpRequest;
import org.apache.catalina.HttpResponse;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Logger;
import org.apache.catalina.Request;
import org.apache.catalina.Response;
import org.apache.catalina.Service;
import org.apache.catalina.net.DefaultServerSocketFactory;
import org.apache.catalina.net.ServerSocketFactory;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.catalina.util.StringManager;


/**
 * Implementation of an HTTP/1.1 connector.
 *
 * @author Craig R. McClanahan
 * @author Remy Maucherat
 * @version $Revision: 1.1 $ $Date: 2002/01/18 05:35:31 $
 */


public final class HttpConnector
implements Connector, Lifecycle, Runnable {
    
    
    // ----------------------------------------------------- Instance Variables
    

    // !!! START:Changes !!!
    private int sleep = Constants.DEFAULT_CONNECTION_TIMEOUT;
    private final short LOOPS = 128;
    // !!! END:Changes !!!
    

    /**
     * The <code>Service</code> we are associated with (if any).
     */
    private Service service = null;
    
    
    /**
     * The accept count for this Connector.
     */
    private int acceptCount = 10;
    
    
    /**
     * The IP address on which to bind, if any.  If <code>null</code>, all
     * addresses on the server will be bound.
     */
    private String address = null;
    
    
    /**
     * The input buffer size we should create on input streams.
     */
    private int bufferSize = 2048;
    
    
    /**
     * The Container used for processing requests received by this Connector.
     */
    protected Container container = null;
    
    
    /**
     * The set of processors that have ever been created.
     */
    private Vector created = new Vector();
    
    
    /**
     * The current number of processors that have been created.
     */
    private int curProcessors = 0;
    
    
    /**
     * The debugging detail level for this component.
     */
    private int debug = 0;
    
    
    /**
     * The "enable DNS lookups" flag for this Connector.
     */
    private boolean enableLookups = false;
    
    
    /**
     * The server socket factory for this component.
     */
    private ServerSocketFactory factory = null;
    
    
    /**
     * Descriptive information about this Connector implementation.
     */
    private static final String info =
    "org.apache.catalina.connector.http.HttpConnector/1.0";
    
    
    /**
     * The lifecycle event support for this component.
     */
    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
    
    
    /**
     * The minimum number of processors to start at initialization time.
     */
    protected int minProcessors = 5;
    
    
    /**
     * The maximum number of processors allowed, or <0 for unlimited.
     */
    private int maxProcessors = 20;
    
    
    /**
     * Timeout value on the incoming connection.
     * Note : a value of 0 means no timeout.
     */
    private int connectionTimeout = Constants.DEFAULT_CONNECTION_TIMEOUT;
    
    
    /**
     * The port number on which we listen for HTTP requests.
     */
    private int port = 8080;
    
    
    /**
     * The set of processors that have been created but are not currently
     * being used to process a request.
     */
    private Stack processors = new Stack();
    
    
    /**
     * The server name to which we should pretend requests to this Connector
     * were directed.  This is useful when operating Tomcat behind a proxy
     * server, so that redirects get constructed accurately.  If not specified,
     * the server name included in the <code>Host</code> header is used.
     */
    private String proxyName = null;
    
    
    /**
     * The server port to which we should pretent requests to this Connector
     * were directed.  This is useful when operating Tomcat behind a proxy
     * server, so that redirects get constructed accurately.  If not specified,
     * the port number specified by the <code>port</code> property is used.
     */
    private int proxyPort = 0;
    
    
    /**
     * The redirect port for non-SSL to SSL redirects.
     */
    private int redirectPort = 443;
    
    
    /**
     * The request scheme that will be set on all requests received
     * through this connector.
     */
    private String scheme = "http";
    
    
    /**
     * The secure connection flag that will be set on all requests received
     * through this connector.
     */
    private boolean secure = false;
    
    
    /**
     * The server socket through which we listen for incoming TCP connections.
     */
    private ServerSocket serverSocket = null;
    
    
    /**
     * The string manager for this package.
     */
    private StringManager sm =
    StringManager.getManager(Constants.Package);
    
    
    /**
     * Has this component been initialized yet?
     */
    private boolean initialized = false;
    
    
    /**
     * Has this component been started yet?
     */
    private boolean started = false;
    
    
    /**
     * The shutdown signal to our background thread
     */
    private boolean stopped = false;
    
    
    /**
     * The background thread.
     */
    private Thread thread = null;
    
    
    /**
     * The name to register for the background thread.
     */
    private String threadName = null;
    
    
    /**
     * The thread synchronization object.
     */
    private Object threadSync = new Object();
    
    
    /**
     * Is chunking allowed ?
     */
    private boolean allowChunking = true;
    
    
    /**
     * Use TCP no delay ?
     */
    private boolean tcpNoDelay = true;
    
    
    // ------------------------------------------------------------- Properties
    
    
    /**
     * Return the <code>Service</code> with which we are associated (if any).
     */
    public Service getService() {
        
        return (this.service);
        
    }
    
    
    /**
     * Set the <code>Service</code> with which we are associated (if any).
     *
     * @param service The service that owns this Engine
     */
    public void setService(Service service) {
        
        this.service = service;
        
    }
    
    
    /**
     * Return the connection timeout for this Connector.
     */
    public int getConnectionTimeout() {
        
        return (connectionTimeout);
        
    }
    
    
    /**
     * Set the connection timeout for this Connector.
     *
     * @param count The new connection timeout
     */
    public void setConnectionTimeout(int connectionTimeout) {
        
        this.connectionTimeout = connectionTimeout;
        
    }
    
    
    /**
     * Return the accept count for this Connector.
     */
    public int getAcceptCount() {
        
        return (acceptCount);
        
    }
    
    
    /**
     * Set the accept count for this Connector.
     *
     * @param count The new accept count
     */
    public void setAcceptCount(int count) {
        
        this.acceptCount = count;
        
    }
    
    
    /**
     * Get the allow chunking flag.
     */
    public boolean isChunkingAllowed() {
        
        return (allowChunking);
        
    }
    
    
    /**
     * Set the allow chunking flag.
     *
     * @param allowChunking Allow chunking flag
     */
    public void setAllowChunking(boolean allowChunking) {
        
        this.allowChunking = allowChunking;
        
    }
    
    
    /**
     * Return the bind IP address for this Connector.
     */
    public String getAddress() {
        
        return (this.address);
        
    }
    
    
    /**
     * Set the bind IP address for this Connector.
     *
     * @param address The bind IP address
     */
    public void setAddress(String address) {
        
        this.address = address;
        
    }
    
    
    /**
     * Is this connector available for processing requests?
     */
    public boolean isAvailable() {
        
        return (started);
        
    }
    
    
    /**
     * Return the input buffer size for this Connector.
     */
    public int getBufferSize() {
        
        return (this.bufferSize);
        
    }
    
    
    /**
     * Set the input buffer size for this Connector.
     *
     * @param bufferSize The new input buffer size.
     */
    public void setBufferSize(int bufferSize) {
        
        this.bufferSize = bufferSize;
        
    }
    
    
    /**
     * Return the Container used for processing requests received by this
     * Connector.
     */
    public Container getContainer() {
        
        return (container);
        
    }
    
    
    /**
     * Set the Container used for processing requests received by this
     * Connector.
     *
     * @param container The new Container to use
     */
    public void setContainer(Container container) {
        
        this.container = container;
        
    }
    
    
    /**
     * Return the current number of processors that have been created.
     */
    public int getCurProcessors() {
        
        return (curProcessors);
        
    }
    
    
    /**
     * Return the debugging detail level for this component.
     */
    public int getDebug() {
        
        return (debug);
        
    }
    
    
    /**
     * Set the debugging detail level for this component.
     *
     * @param debug The new debugging detail level
     */
    public void setDebug(int debug) {
        
        this.debug = debug;
        
    }
    
    
    /**
     * Return the "enable DNS lookups" flag.
     */
    public boolean getEnableLookups() {
        
        return (this.enableLookups);
        
    }
    
    
    /**
     * Set the "enable DNS lookups" flag.
     *
     * @param enableLookups The new "enable DNS lookups" flag value
     */
    public void setEnableLookups(boolean enableLookups) {
        
        this.enableLookups = enableLookups;
        
    }
    
    
    /**
     * Return the server socket factory used by this Container.
     */
    public ServerSocketFactory getFactory() {
        
        if (this.factory == null) {
            synchronized (this) {
                this.factory = new DefaultServerSocketFactory();
            }
        }
        
        return (this.factory);
        
    }
    
    
    /**
     * Set the server socket factory used by this Container.
     *
     * @param factory The new server socket factory
     */
    public void setFactory(ServerSocketFactory factory) {
        
        this.factory = factory;
        
    }
    
    
    /**
     * Return descriptive information about this Connector implementation.
     */
    public String getInfo() {
        
        return (info);
        
    }
    
    
    /**
     * Return the minimum number of processors to start at initialization.
     */
    public int getMinProcessors() {
        
        return (minProcessors);
        
    }
    
    
    /**
     * Set the minimum number of processors to start at initialization.
     *
     * @param minProcessors The new minimum processors
     */
    public void setMinProcessors(int minProcessors) {
        
        this.minProcessors = minProcessors;
        
    }
    
    
    /**
     * Return the maximum number of processors allowed, or <0 for unlimited.
     */
    public int getMaxProcessors() {
        
        return (maxProcessors);
        
    }
    
    
    /**
     * Set the maximum number of processors allowed, or <0 for unlimited.
     *
     * @param maxProcessors The new maximum processors
     */
    public void setMaxProcessors(int maxProcessors) {
        
        this.maxProcessors = maxProcessors;
        
    }
    
    
    /**
     * Return the port number on which we listen for HTTP requests.
     */
    public int getPort() {
        
        return (this.port);
        
    }
    
    
    /**
     * Set the port number on which we listen for HTTP requests.
     *
     * @param port The new port number
     */
    public void setPort(int port) {
        
        this.port = port;
        
    }
    
    
    /**
     * Return the proxy server name for this Connector.
     */
    public String getProxyName() {
        
        return (this.proxyName);
        
    }
    
    
    /**
     * Set the proxy server name for this Connector.
     *
     * @param proxyName The new proxy server name
     */
    public void setProxyName(String proxyName) {
        
        this.proxyName = proxyName;
        
    }
    
    
    /**
     * Return the proxy server port for this Connector.
     */
    public int getProxyPort() {
        
        return (this.proxyPort);
        
    }
    
    
    /**
     * Set the proxy server port for this Connector.
     *
     * @param proxyPort The new proxy server port
     */
    public void setProxyPort(int proxyPort) {
        
        this.proxyPort = proxyPort;
        
    }
    
    
    /**
     * Return the port number to which a request should be redirected if
     * it comes in on a non-SSL port and is subject to a security constraint
     * with a transport guarantee that requires SSL.
     */
    public int getRedirectPort() {
        
        return (this.redirectPort);
        
    }
    
    
    /**
     * Set the redirect port number.
     *
     * @param redirectPort The redirect port number (non-SSL to SSL)
     */
    public void setRedirectPort(int redirectPort) {
        
        this.redirectPort = redirectPort;
        
    }
    
    
    /**
     * Return the scheme that will be assigned to requests received
     * through this connector.  Default value is "http".
     */
    public String getScheme() {
        
        return (this.scheme);
        
    }
    
    
    /**
     * Set the scheme that will be assigned to requests received through
     * this connector.
     *
     * @param scheme The new scheme
     */
    public void setScheme(String scheme) {
        
        this.scheme = scheme;
        
    }
    
    
    /**
     * Return the secure connection flag that will be assigned to requests
     * received through this connector.  Default value is "false".
     */
    public boolean getSecure() {
        
        return (this.secure);
        
    }
    
    
    /**
     * Set the secure connection flag that will be assigned to requests
     * received through this connector.
     *
     * @param secure The new secure connection flag
     */
    public void setSecure(boolean secure) {
        
        this.secure = secure;
        
    }
    
    
    /**
     * Return the TCP no delay flag value.
     */
    public boolean getTcpNoDelay() {
        
        return (this.tcpNoDelay);
        
    }
    
    
    /**
     * Set the TCP no delay flag which will be set on the socket after
     * accepting a connection.
     *
     * @param tcpNoDelay The new TCP no delay flag
     */
    public void setTcpNoDelay(boolean tcpNoDelay) {
        
        this.tcpNoDelay = tcpNoDelay;
        
    }
    
    
    // --------------------------------------------------------- Public Methods
    
    
    /**
     * Create (or allocate) and return a Request object suitable for
     * specifying the contents of a Request to the responsible Container.
     */
    public Request createRequest() {
        
        //        if (debug >= 2)
        //            log("createRequest: Creating new request");
        HttpRequestImpl request = new HttpRequestImpl();
        request.setConnector(this);
        return (request);
        
    }
    
    
    /**
     * Create (or allocate) and return a Response object suitable for
     * receiving the contents of a Response from the responsible Container.
     */
    public Response createResponse() {
        
        //        if (debug >= 2)
        //            log("createResponse: Creating new response");
        HttpResponseImpl response = new HttpResponseImpl();
        response.setConnector(this);
        return (response);
        
    }
    
    
    // -------------------------------------------------------- Package Methods
    
    
    /**
     * Recycle the specified Processor so that it can be used again.
     *
     * @param processor The processor to be recycled
     */
    void recycle(HttpProcessor processor) {
        
        //        if (debug >= 2)
        //            log("recycle: Recycling processor " + processor);
        processors.push(processor);
        
    }
    
    
    // -------------------------------------------------------- Private Methods
    
    
    /**
     * Create (or allocate) and return an available processor for use in
     * processing a specific HTTP request, if possible.  If the maximum
     * allowed processors have already been created and are in use, return
     * <code>null</code> instead.
     */
    private HttpProcessor createProcessor() {
        
        synchronized (processors) {
            if (processors.size() > 0) {
                // if (debug >= 2)
                // log("createProcessor: Reusing existing processor");
                return ((HttpProcessor) processors.pop());
            }
            if ((maxProcessors > 0) && (curProcessors < maxProcessors)) {
                // if (debug >= 2)
                // log("createProcessor: Creating new processor");
                return (newProcessor());
            } else {
                if (maxProcessors < 0) {
                    // if (debug >= 2)
                    // log("createProcessor: Creating new processor");
                    return (newProcessor());
                } else {
                    // if (debug >= 2)
                    // log("createProcessor: Cannot create new processor");
                    return (null);
                }
            }
        }
        
    }
    
    
    /**
     * Log a message on the Logger associated with our Container (if any).
     *
     * @param message Message to be logged
     */
    private void log(String message) {
        
        Logger logger = container.getLogger();
        String localName = threadName;
        if (localName == null)
            localName = "HttpConnector";
        if (logger != null)
            logger.log(localName + " " + message);
        else
            System.out.println(localName + " " + message);
        
    }
    
    
    /**
     * Log a message on the Logger associated with our Container (if any).
     *
     * @param message Message to be logged
     * @param throwable Associated exception
     */
    private void log(String message, Throwable throwable) {
        
        Logger logger = container.getLogger();
        String localName = threadName;
        if (localName == null)
            localName = "HttpConnector";
        if (logger != null)
            logger.log(localName + " " + message, throwable);
        else {
            System.out.println(localName + " " + message);
            throwable.printStackTrace(System.out);
        }
        
    }
    
    
    /**
     * Create and return a new processor suitable for processing HTTP
     * requests and returning the corresponding responses.
     */
    private HttpProcessor newProcessor() {
        
        //        if (debug >= 2)
        //            log("newProcessor: Creating new processor");
        HttpProcessor processor = new HttpProcessor(this, curProcessors++);
        if (processor instanceof Lifecycle) {
            try {
                ((Lifecycle) processor).start();
            } catch (LifecycleException e) {
                log("newProcessor", e);
                return (null);
            }
        }
        created.addElement(processor);
        return (processor);
        
    }
    
    
    /**
     * Open and return the server socket for this Connector.  If an IP
     * address has been specified, the socket will be opened only on that
     * address; otherwise it will be opened on all addresses.
     *
     * @exception IOException if an input/output error occurs
     */
    private ServerSocket open() throws IOException {
        
        // Acquire the server socket factory for this Connector
        ServerSocketFactory factory = getFactory();
        
        // If no address is specified, open a connection on all addresses
        if (address == null) {
            log(sm.getString("httpConnector.allAddresses"));
            return (factory.createSocket(port, acceptCount));
        }
        
        // Open a server socket on the specified address
        try {
            InetAddress is = InetAddress.getByName(address);
            log(sm.getString("httpConnector.anAddress", address));
            return (factory.createSocket(port, acceptCount, is));
        } catch (Exception e) {
            log(sm.getString("httpConnector.noAddress", address));
            return (factory.createSocket(port, acceptCount));
        }
        
    }
    
    
    // ---------------------------------------------- Background Thread Methods
    
    
    /**
     * The background thread that listens for incoming TCP/IP connections and
     * hands them off to an appropriate processor.
     */
    public void run() {
        if (connectionTimeout > 0) {
            sleep = connectionTimeout / LOOPS;
        }
        
        
        // Loop until we receive a shutdown command
        while (!stopped) {
            
            // Accept the next incoming connection from the server socket
            Socket socket = null;
            try {
                //                if (debug >= 3)
                //                    log("run: Waiting on serverSocket.accept()");
                socket = serverSocket.accept();
                //                if (debug >= 3)
                //                    log("run: Returned from
serverSocket.accept()");
                if (connectionTimeout > 0)
                    socket.setSoTimeout(connectionTimeout);
                socket.setTcpNoDelay(tcpNoDelay);
            } catch (AccessControlException ace) {
                log("socket accept security exception", ace);
                continue;
            } catch (IOException e) {
                //                if (debug >= 3)
                //                    log("run: Accept returned IOException", e);
                try {
                    synchronized (threadSync) {
                        if (started && !stopped)
                            log("accept: ", e);
                        if (!stopped) {
                            //                    if (debug >= 3)
                            //                        log("run: Closing server
socket");
                            serverSocket.close();
                            //                        if (debug >= 3)
                            //                            log("run: Reopening
server socket");
                            serverSocket = open();
                        }
                    }
                    //                    if (debug >= 3)
                    //                        log("run: IOException processing
completed");
                } catch (IOException ex) {
                    // If reopening fails, exit
                    log("socket reopen: ", ex);
                    break;
                }
                continue;
            }
            
            
            
            // Hand this socket off to an appropriate processor
            // !!! START:Changed !!! 
            HttpProcessor processor = null; short loops = LOOPS;
            while (!stopped && (processor == null) && (--loops > 1)) {
                processor = createProcessor();
                if (processor == null) {
                    try {
                        Thread.currentThread().sleep(sleep);
                    } catch (InterruptedException ignored) {}
                }
                else {
                    //            if (debug >= 3)
                    //                log("run: Assigning socket to processor "
+ processor);
                    processor.assign(socket);
                    //log("run:try " + (LOOPS - loops) + "/" + sleep + "ms for ip
" + socket.getInetAddress().getHostAddress());
                    // The processor will recycle itself when it finishes
                    break;
                }
            }
            
            if (processor == null) {
                try {
                    log(sm.getString("httpConnector.noProcessor"));
                    socket.close();
                } catch (IOException e) {
                    ;
                }
            }
            // !!! END:Changed !!! 

        }
        
        // Notify the threadStop() method that we have shut ourselves down
        //        if (debug >= 3)
        //            log("run: Notifying threadStop() that we have shut down");
        synchronized (threadSync) {
            threadSync.notifyAll();
        }
        
    }
    
    
    /**
     * Start the background processing thread.
     */
    private void threadStart() {
        
        log(sm.getString("httpConnector.starting"));
        
        thread = new Thread(this, threadName);
        thread.setDaemon(true);
        thread.start();
        
    }
    
    
    /**
     * Stop the background processing thread.
     */
    private void threadStop() {
        
        log(sm.getString("httpConnector.stopping"));
        
        stopped = true;
        try {
            threadSync.wait(5000);
        } catch (InterruptedException e) {
            ;
        }
        thread = null;
        
    }
    
    
    // ------------------------------------------------------ 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 add
     */
    public void removeLifecycleListener(LifecycleListener listener) {
        
        lifecycle.removeLifecycleListener(listener);
        
    }
    
    
    /**
     * Initialize this connector (create ServerSocket here!)
     */
    public void initialize()
    throws LifecycleException {
        if (initialized)
            throw new LifecycleException(
            sm.getString("httpConnector.alreadyInitialized"));
        this.initialized=true;
        
        // Establish a server socket on the specified port
        try {
            serverSocket = open();
        } catch (IOException e) {
            throw new LifecycleException(threadName + ".open", e);
        }
        
    }
    
    
    /**
     * Begin processing requests via this Connector.
     *
     * @exception LifecycleException if a fatal startup error occurs
     */
    public void start() throws LifecycleException {
        
        // Validate and update our current state
        if (started)
            throw new LifecycleException
            (sm.getString("httpConnector.alreadyStarted"));
        threadName = "HttpConnector[" + port + "]";
        lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;
        
        // Start our background thread
        threadStart();
        
        // Create the specified minimum number of processors
        while (curProcessors < minProcessors) {
            if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
                break;
            HttpProcessor processor = newProcessor();
            recycle(processor);
        }
        
    }
    
    
    /**
     * Terminate processing requests via this Connector.
     *
     * @exception LifecycleException if a fatal shutdown error occurs
     */
    public void stop() throws LifecycleException {
        
        // Validate and update our current state
        if (!started)
            throw new LifecycleException
            (sm.getString("httpConnector.notStarted"));
        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
        started = false;
        
        // Gracefully shut down all processors we have created
        for (int i = created.size() - 1; i >= 0; i--) {
            HttpProcessor processor = (HttpProcessor) created.elementAt(i);
            if (processor instanceof Lifecycle) {
                try {
                    ((Lifecycle) processor).stop();
                } catch (LifecycleException e) {
                    log("HttpConnector.stop", e);
                }
            }
        }
        
        synchronized (threadSync) {
            // Close the server socket we were using
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    ;
                }
            }
            // Stop our background thread
            threadStop();
        }
        serverSocket = null;
        
    }
    
    
}

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>