0001: /*
0002: * Copyright 1999-2004 The Apache Software Foundation
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.apache.ajp.tomcat4;
0018:
0019: import java.io.IOException;
0020: import java.net.InetAddress;
0021: import java.net.ServerSocket;
0022: import java.net.Socket;
0023: import java.security.AccessControlException;
0024: import java.util.Stack;
0025: import java.util.Vector;
0026:
0027: import org.apache.catalina.Connector;
0028: import org.apache.catalina.Container;
0029: import org.apache.catalina.Lifecycle;
0030: import org.apache.catalina.LifecycleException;
0031: import org.apache.catalina.LifecycleListener;
0032: import org.apache.catalina.Request;
0033: import org.apache.catalina.Response;
0034: import org.apache.catalina.Service;
0035: import org.apache.catalina.net.DefaultServerSocketFactory;
0036: import org.apache.catalina.net.ServerSocketFactory;
0037: import org.apache.catalina.util.LifecycleSupport;
0038: import org.apache.catalina.util.StringManager;
0039:
0040: /**
0041: * Implementation of an Ajp13 connector.
0042: *
0043: * @author Kevin Seguin
0044: * @version $Revision: 1.20 $ $Date: 2004/02/24 08:48:41 $
0045: */
0046:
0047: public final class Ajp13Connector implements Connector, Lifecycle,
0048: Runnable {
0049:
0050: // ----------------------------------------------------- Instance Variables
0051:
0052: /**
0053: * The accept count for this Connector.
0054: */
0055: private int acceptCount = 10;
0056:
0057: /**
0058: * The IP address on which to bind, if any. If <code>null</code>, all
0059: * addresses on the server will be bound.
0060: */
0061: private String address = null;
0062:
0063: /**
0064: * The input buffer size we should create on input streams.
0065: */
0066: private int bufferSize = 2048;
0067:
0068: /**
0069: * The Container used for processing requests received by this Connector.
0070: */
0071: protected Container container = null;
0072:
0073: /**
0074: * The set of processors that have ever been created.
0075: */
0076: private Vector created = new Vector();
0077:
0078: /**
0079: * The current number of processors that have been created.
0080: */
0081: private int curProcessors = 0;
0082:
0083: /**
0084: * The debugging detail level for this component.
0085: */
0086: private int debug = 0;
0087:
0088: /**
0089: * The server socket factory for this component.
0090: */
0091: private ServerSocketFactory factory = null;
0092:
0093: /**
0094: * Descriptive information about this Connector implementation.
0095: */
0096: private static final String info = "org.apache.catalina.connector.ajp.Ajp13Connector/1.0";
0097:
0098: /**
0099: * redirect port.
0100: */
0101: private int redirectPort = -1;
0102:
0103: /**
0104: * enable DNS lookups.
0105: */
0106: private boolean enableLookups = false;
0107:
0108: /**
0109: * The lifecycle event support for this component.
0110: */
0111: protected LifecycleSupport lifecycle = new LifecycleSupport(this );
0112:
0113: /**
0114: * The minimum number of processors to start at initialization time.
0115: */
0116: protected int minProcessors = 5;
0117:
0118: /**
0119: * The maximum number of processors allowed, or <0 for unlimited.
0120: */
0121: private int maxProcessors = 20;
0122:
0123: /**
0124: * Timeout value on the incoming connection.
0125: * Note : a value of 0 means no timeout.
0126: */
0127: private int connectionTimeout = -1;
0128:
0129: /**
0130: * Linger value to be used on socket close.
0131: * Note : a value of -1 means no linger used on close.
0132: */
0133: private int connectionLinger = -1;
0134:
0135: /**
0136: * The port number on which we listen for ajp13 requests.
0137: */
0138: private int port = 8009;
0139:
0140: /**
0141: * The set of processors that have been created but are not currently
0142: * being used to process a request.
0143: */
0144: private Stack processors = new Stack();
0145:
0146: /**
0147: * The request scheme that will be set on all requests received
0148: * through this connector.
0149: */
0150: private String scheme = "http";
0151:
0152: /**
0153: * The secure connection flag that will be set on all requests received
0154: * through this connector.
0155: */
0156: private boolean secure = false;
0157:
0158: /**
0159: * The server socket through which we listen for incoming TCP connections.
0160: */
0161: private ServerSocket serverSocket = null;
0162:
0163: /**
0164: * The string manager for this package.
0165: */
0166: private StringManager sm = StringManager
0167: .getManager(Constants.PACKAGE);
0168:
0169: /**
0170: * Has this component been started yet?
0171: */
0172: private boolean started = false;
0173:
0174: /**
0175: * The shutdown signal to our background thread
0176: */
0177: private boolean stopped = false;
0178:
0179: /**
0180: * The background thread.
0181: */
0182: private Thread thread = null;
0183:
0184: /**
0185: * This connector's thread group.
0186: */
0187: private ThreadGroup threadGroup = null;
0188:
0189: /**
0190: * The name to register for the background thread.
0191: */
0192: private String threadName = null;
0193:
0194: /**
0195: * A thread that periodically logs debug info if debug > 0.
0196: */
0197: private DebugThread debugThread = null;
0198:
0199: /**
0200: * The thread synchronization object.
0201: */
0202: private Object threadSync = new Object();
0203:
0204: private Ajp13Logger logger = new Ajp13Logger();
0205:
0206: /**
0207: * The service which which the connector is associated
0208: */
0209: private Service service = null;
0210:
0211: private String secret = null;
0212:
0213: /**
0214: * Tomcat authentication flag. If true, the authnetication is done by
0215: * Tomcat, otherwise, it is done by the native webserver.
0216: */
0217: private boolean tomcatAuthentication = true;
0218:
0219: // ------------------------------------------------------------- Properties
0220:
0221: /**
0222: * Return the connection timeout for this Connector.
0223: */
0224: public int getConnectionTimeout() {
0225:
0226: return (connectionTimeout);
0227:
0228: }
0229:
0230: /**
0231: * Set the connection timeout for this Connector.
0232: *
0233: * @param connectionTimeout The new connection timeout
0234: */
0235: public void setConnectionTimeout(int connectionTimeout) {
0236:
0237: this .connectionTimeout = connectionTimeout;
0238:
0239: }
0240:
0241: /**
0242: * Return the connection linger settings for this Connector.
0243: */
0244: public int getConnectionLinger() {
0245:
0246: return (connectionLinger);
0247:
0248: }
0249:
0250: /**
0251: * Set the connection linger for this Connector.
0252: *
0253: * @param connectionLinger The new connection linger
0254: */
0255: public void setConnectionLinger(int connectionLinger) {
0256:
0257: this .connectionLinger = connectionLinger;
0258:
0259: }
0260:
0261: public void setSecret(String s) {
0262: secret = s;
0263: }
0264:
0265: public String getSecret() {
0266: return secret;
0267: }
0268:
0269: /**
0270: * Return the accept count for this Connector.
0271: */
0272: public int getAcceptCount() {
0273:
0274: return (acceptCount);
0275:
0276: }
0277:
0278: /**
0279: * Set the accept count for this Connector.
0280: *
0281: * @param count The new accept count
0282: */
0283: public void setAcceptCount(int count) {
0284:
0285: this .acceptCount = count;
0286:
0287: }
0288:
0289: /**
0290: * Return the bind IP address for this Connector.
0291: */
0292: public String getAddress() {
0293:
0294: return (this .address);
0295:
0296: }
0297:
0298: /**
0299: * Set the bind IP address for this Connector.
0300: *
0301: * @param address The bind IP address
0302: */
0303: public void setAddress(String address) {
0304:
0305: this .address = address;
0306:
0307: }
0308:
0309: /**
0310: * Is this connector available for processing requests?
0311: */
0312: public boolean isAvailable() {
0313:
0314: return (started);
0315:
0316: }
0317:
0318: /**
0319: * Return the input buffer size for this Connector.
0320: */
0321: public int getBufferSize() {
0322:
0323: return (this .bufferSize);
0324:
0325: }
0326:
0327: /**
0328: * Set the input buffer size for this Connector.
0329: *
0330: * @param bufferSize The new input buffer size.
0331: */
0332: public void setBufferSize(int bufferSize) {
0333:
0334: this .bufferSize = bufferSize;
0335:
0336: }
0337:
0338: /**
0339: * Return the Container used for processing requests received by this
0340: * Connector.
0341: */
0342: public Container getContainer() {
0343:
0344: return (container);
0345:
0346: }
0347:
0348: /**
0349: * Set the Container used for processing requests received by this
0350: * Connector.
0351: *
0352: * @param container The new Container to use
0353: */
0354: public void setContainer(Container container) {
0355:
0356: this .container = container;
0357:
0358: }
0359:
0360: /**
0361: * Return the current number of processors that have been created.
0362: */
0363: public int getCurProcessors() {
0364:
0365: return (curProcessors);
0366:
0367: }
0368:
0369: /**
0370: * Return the debugging detail level for this component.
0371: */
0372: public int getDebug() {
0373:
0374: return (debug);
0375:
0376: }
0377:
0378: /**
0379: * Set the debugging detail level for this component.
0380: *
0381: * @param debug The new debugging detail level
0382: */
0383: public void setDebug(int debug) {
0384:
0385: this .debug = debug;
0386:
0387: }
0388:
0389: /**
0390: * Return the "enable DNS lookups" flag.
0391: */
0392: public boolean getEnableLookups() {
0393: return this .enableLookups;
0394: }
0395:
0396: /**
0397: * Set the "enable DNS lookups" flag.
0398: *
0399: * @param enableLookups The new "enable DNS lookups" flag value
0400: */
0401: public void setEnableLookups(boolean enableLookups) {
0402: this .enableLookups = enableLookups;
0403: }
0404:
0405: /**
0406: * Return the port number to which a request should be redirected if
0407: * it comes in on a non-SSL port and is subject to a security constraint
0408: * with a transport guarantee that requires SSL.
0409: */
0410: public int getRedirectPort() {
0411: return this .redirectPort;
0412: }
0413:
0414: /**
0415: * Set the redirect port number.
0416: *
0417: * @param redirectPort The redirect port number (non-SSL to SSL)
0418: */
0419: public void setRedirectPort(int redirectPort) {
0420: this .redirectPort = redirectPort;
0421: }
0422:
0423: /**
0424: * Return the server socket factory used by this Container.
0425: */
0426: public ServerSocketFactory getFactory() {
0427:
0428: if (this .factory == null) {
0429: synchronized (this ) {
0430: this .factory = new DefaultServerSocketFactory();
0431: }
0432: }
0433: return (this .factory);
0434:
0435: }
0436:
0437: /**
0438: * Set the server socket factory used by this Container.
0439: *
0440: * @param factory The new server socket factory
0441: */
0442: public void setFactory(ServerSocketFactory factory) {
0443:
0444: this .factory = factory;
0445:
0446: }
0447:
0448: /**
0449: * Return descriptive information about this Connector implementation.
0450: */
0451: public String getInfo() {
0452:
0453: return (info);
0454:
0455: }
0456:
0457: /**
0458: * Return the minimum number of processors to start at initialization.
0459: */
0460: public int getMinProcessors() {
0461:
0462: return (minProcessors);
0463:
0464: }
0465:
0466: /**
0467: * Set the minimum number of processors to start at initialization.
0468: *
0469: * @param minProcessors The new minimum processors
0470: */
0471: public void setMinProcessors(int minProcessors) {
0472:
0473: this .minProcessors = minProcessors;
0474:
0475: }
0476:
0477: /**
0478: * Return the maximum number of processors allowed, or <0 for unlimited.
0479: */
0480: public int getMaxProcessors() {
0481:
0482: return (maxProcessors);
0483:
0484: }
0485:
0486: /**
0487: * Set the maximum number of processors allowed, or <0 for unlimited.
0488: *
0489: * @param maxProcessors The new maximum processors
0490: */
0491: public void setMaxProcessors(int maxProcessors) {
0492:
0493: this .maxProcessors = maxProcessors;
0494:
0495: }
0496:
0497: /**
0498: * Return the port number on which we listen for AJP13 requests.
0499: */
0500: public int getPort() {
0501:
0502: return (this .port);
0503:
0504: }
0505:
0506: /**
0507: * Set the port number on which we listen for AJP13 requests.
0508: *
0509: * @param port The new port number
0510: */
0511: public void setPort(int port) {
0512:
0513: this .port = port;
0514:
0515: }
0516:
0517: /**
0518: * Return the scheme that will be assigned to requests received
0519: * through this connector. Default value is "http".
0520: */
0521: public String getScheme() {
0522:
0523: return (this .scheme);
0524:
0525: }
0526:
0527: /**
0528: * Set the scheme that will be assigned to requests received through
0529: * this connector.
0530: *
0531: * @param scheme The new scheme
0532: */
0533: public void setScheme(String scheme) {
0534:
0535: this .scheme = scheme;
0536:
0537: }
0538:
0539: /**
0540: * Return the secure connection flag that will be assigned to requests
0541: * received through this connector. Default value is "false".
0542: */
0543: public boolean getSecure() {
0544:
0545: return (this .secure);
0546:
0547: }
0548:
0549: /**
0550: * Set the secure connection flag that will be assigned to requests
0551: * received through this connector.
0552: *
0553: * @param secure The new secure connection flag
0554: */
0555: public void setSecure(boolean secure) {
0556:
0557: this .secure = secure;
0558:
0559: }
0560:
0561: /**
0562: * Returns the <code>Service</code> with which we are associated.
0563: */
0564: public Service getService() {
0565: return service;
0566: }
0567:
0568: /**
0569: * Set the <code>Service</code> with which we are associated.
0570: */
0571: public void setService(Service service) {
0572: this .service = service;
0573: }
0574:
0575: /**
0576: * Get the value of the tomcatAuthentication flag.
0577: */
0578: public boolean getTomcatAuthentication() {
0579: return tomcatAuthentication;
0580: }
0581:
0582: /**
0583: * Set the value of the tomcatAuthentication flag.
0584: */
0585: public void setTomcatAuthentication(boolean tomcatAuthentication) {
0586: this .tomcatAuthentication = tomcatAuthentication;
0587: }
0588:
0589: // --------------------------------------------------------- Public Methods
0590:
0591: /**
0592: * Create (or allocate) and return a Request object suitable for
0593: * specifying the contents of a Request to the responsible Container.
0594: */
0595: public Request createRequest() {
0596:
0597: Ajp13Request request = new Ajp13Request(this );
0598: request.setConnector(this );
0599: return (request);
0600:
0601: }
0602:
0603: /**
0604: * Create (or allocate) and return a Response object suitable for
0605: * receiving the contents of a Response from the responsible Container.
0606: */
0607: public Response createResponse() {
0608:
0609: Ajp13Response response = new Ajp13Response();
0610: response.setConnector(this );
0611: return (response);
0612:
0613: }
0614:
0615: /**
0616: * Invoke a pre-startup initialization. This is used to allow connectors
0617: * to bind to restricted ports under Unix operating environments.
0618: * ServerSocket (we start as root and change user? or I miss something?).
0619: */
0620: public void initialize() throws LifecycleException {
0621: }
0622:
0623: // -------------------------------------------------------- Package Methods
0624:
0625: /**
0626: * Recycle the specified Processor so that it can be used again.
0627: *
0628: * @param processor The processor to be recycled
0629: */
0630: void recycle(Ajp13Processor processor) {
0631:
0632: synchronized (processors) {
0633: if (debug > 0) {
0634: logger
0635: .log("added processor to available processors, available="
0636: + processors.size());
0637: }
0638: processors.push(processor);
0639: }
0640:
0641: }
0642:
0643: // -------------------------------------------------------- Private Methods
0644:
0645: /**
0646: * Create (or allocate) and return an available processor for use in
0647: * processing a specific AJP13 request, if possible. If the maximum
0648: * allowed processors have already been created and are in use, return
0649: * <code>null</code> instead.
0650: */
0651: private Ajp13Processor createProcessor() {
0652:
0653: synchronized (processors) {
0654: if (processors.size() > 0)
0655: return ((Ajp13Processor) processors.pop());
0656: if ((maxProcessors > 0) && (curProcessors < maxProcessors))
0657: return (newProcessor());
0658: else
0659: return (null);
0660: }
0661:
0662: }
0663:
0664: /**
0665: * Create and return a new processor suitable for processing AJP13
0666: * requests and returning the corresponding responses.
0667: */
0668: private Ajp13Processor newProcessor() {
0669:
0670: Ajp13Processor processor = new Ajp13Processor(this ,
0671: curProcessors++, threadGroup);
0672: if (processor instanceof Lifecycle) {
0673: try {
0674: ((Lifecycle) processor).start();
0675: } catch (LifecycleException e) {
0676: logger.log("newProcessor", e);
0677: curProcessors--;
0678: return (null);
0679: }
0680: }
0681: created.addElement(processor);
0682: return (processor);
0683:
0684: }
0685:
0686: /**
0687: * Open and return the server socket for this Connector. If an IP
0688: * address has been specified, the socket will be opened only on that
0689: * address; otherwise it will be opened on all addresses.
0690: *
0691: * @exception IOException if an input/output error occurs
0692: */
0693: private ServerSocket open() throws IOException {
0694:
0695: // Acquire the server socket factory for this Connector
0696: ServerSocketFactory factory = getFactory();
0697:
0698: // If no address is specified, open a connection on all addresses
0699: if (address == null) {
0700: logger.log(sm.getString("ajp13Connector.allAddresses"));
0701: try {
0702: return (factory.createSocket(port, acceptCount));
0703: } catch (Exception ex) {
0704: ex.printStackTrace();
0705: return null;
0706: }
0707: }
0708:
0709: // Open a server socket on the specified address
0710: try {
0711: InetAddress is = InetAddress.getByName(address);
0712: logger.log(sm
0713: .getString("ajp13Connector.anAddress", address));
0714: return (factory.createSocket(port, acceptCount, is));
0715: } catch (Exception e) {
0716: try {
0717: logger.log(sm.getString("ajp13Connector.noAddress",
0718: address));
0719: return (factory.createSocket(port, acceptCount));
0720: } catch (Exception e1) {
0721: e1.printStackTrace();
0722: return null;
0723: }
0724: }
0725:
0726: }
0727:
0728: // ---------------------------------------------- Background Thread Methods
0729:
0730: /**
0731: * The background thread that listens for incoming TCP/IP connections and
0732: * hands them off to an appropriate processor.
0733: */
0734: public void run() {
0735:
0736: // Loop until we receive a shutdown command
0737: while (!stopped) {
0738:
0739: // Accept the next incoming connection from the server socket
0740: Socket socket = null;
0741: try {
0742: if (debug > 0) {
0743: logger.log("accepting socket...");
0744: }
0745:
0746: socket = serverSocket.accept();
0747:
0748: if (debug > 0) {
0749: logger
0750: .log("accepted socket, assigning to processor.");
0751: }
0752:
0753: /* Warning :
0754: *
0755: * To be able to close more quickly a connection, it's recommanded
0756: * to set linger to a small value.
0757: *
0758: * AJP13 connection SHOULD be closed under webserver responsability and
0759: * in such case it's safe to close socket on Tomcat side without delay,
0760: * which may be also the case for HTTP connectors.
0761: *
0762: * I (henri) recommand to set Linger to 0, making socket closed immediatly
0763: * so the OS will free faster the underlying io descriptor and resources.
0764: * It's very important under heavy load !
0765: */
0766:
0767: if (connectionLinger < 0)
0768: socket.setSoLinger(false, 0);
0769: else
0770: socket.setSoLinger(true, connectionLinger);
0771:
0772: /* We don't need it since it's the native side which
0773: * will set the connection with keep alive
0774: * if specified in workers.properties.
0775: *
0776: * socket.setKeepAlive(true);
0777: */
0778:
0779: /* Warning :
0780: *
0781: * AJP13 shouldn't use socket timeout on tomcat site since
0782: * when Tomcat close a connection after a timeout is reached
0783: * the socket stay in half-closed state until the webserver
0784: * try to send a request to tomcat and detect the socket close
0785: * when it will try to read the reply.
0786: *
0787: * On many Unix platforms the write() call didn't told
0788: * webserver that the socket is closed.
0789: */
0790:
0791: if (connectionTimeout >= 0) {
0792: socket.setSoTimeout(connectionTimeout);
0793: }
0794: } catch (AccessControlException ace) {
0795: logger.log("socket accept security exception: "
0796: + ace.getMessage());
0797: continue;
0798: } catch (IOException e) {
0799: if (started && !stopped)
0800: logger.log("accept: ", e);
0801: try {
0802: if (serverSocket != null) {
0803: serverSocket.close();
0804: }
0805: if (stopped) {
0806: if (debug > 0) {
0807: logger.log("run(): stopped, so breaking");
0808: }
0809: break;
0810: } else {
0811: if (debug > 0) {
0812: logger.log("run(): not stopped, "
0813: + "so reopening server socket");
0814: }
0815: serverSocket = open();
0816: }
0817: } catch (IOException ex) {
0818: // If reopening fails, exit
0819: logger.log("socket reopen: ", ex);
0820: break;
0821: }
0822: continue;
0823: }
0824:
0825: // Hand this socket off to an appropriate processor
0826: if (debug > 0) {
0827: synchronized (processors) {
0828: logger
0829: .log("about to create a processor, available="
0830: + processors.size()
0831: + ", created="
0832: + created.size()
0833: + ", maxProcessors="
0834: + maxProcessors);
0835: }
0836: }
0837: Ajp13Processor processor = createProcessor();
0838: if (processor == null) {
0839: try {
0840: logger.log(sm
0841: .getString("ajp13Connector.noProcessor"));
0842: socket.close();
0843: } catch (IOException e) {
0844: ;
0845: }
0846: continue;
0847: }
0848: processor.assign(socket);
0849:
0850: // The processor will recycle itself when it finishes
0851:
0852: }
0853:
0854: // Notify the threadStop() method that we have shut ourselves down
0855: synchronized (threadSync) {
0856: threadSync.notifyAll();
0857: }
0858:
0859: }
0860:
0861: /**
0862: * Start the background processing thread.
0863: */
0864: private void threadStart() {
0865:
0866: logger.log(sm.getString("ajp13Connector.starting"));
0867:
0868: thread = new Thread(threadGroup, this , threadName);
0869: thread.setDaemon(true);
0870: thread.start();
0871:
0872: }
0873:
0874: /**
0875: * Stop the background processing thread.
0876: */
0877: private void threadStop() {
0878:
0879: logger.log(sm.getString("ajp13Connector.stopping"));
0880:
0881: stopped = true;
0882: synchronized (threadSync) {
0883: try {
0884: threadSync.wait(5000);
0885: } catch (InterruptedException e) {
0886: ;
0887: }
0888: }
0889: thread = null;
0890:
0891: }
0892:
0893: // ------------------------------------------------------ Lifecycle Methods
0894:
0895: /**
0896: * Add a lifecycle event listener to this component.
0897: *
0898: * @param listener The listener to add
0899: */
0900: public void addLifecycleListener(LifecycleListener listener) {
0901:
0902: lifecycle.addLifecycleListener(listener);
0903:
0904: }
0905:
0906: /**
0907: * Get the lifecycle listeners associated with this lifecycle. If this
0908: * Lifecycle has no listeners registered, a zero-length array is returned.
0909: */
0910: public LifecycleListener[] findLifecycleListeners() {
0911: return null; // FIXME: lifecycle.findLifecycleListeners();
0912: }
0913:
0914: /**
0915: * Remove a lifecycle event listener from this component.
0916: *
0917: * @param listener The listener to add
0918: */
0919: public void removeLifecycleListener(LifecycleListener listener) {
0920:
0921: lifecycle.removeLifecycleListener(listener);
0922:
0923: }
0924:
0925: /**
0926: * Begin processing requests via this Connector.
0927: *
0928: * @exception LifecycleException if a fatal startup error occurs
0929: */
0930: public void start() throws LifecycleException {
0931:
0932: // Validate and update our current state
0933: if (started)
0934: throw new LifecycleException(sm
0935: .getString("ajp13Connector.alreadyStarted"));
0936:
0937: if (debug > 0) {
0938: debugThread = new DebugThread();
0939: debugThread.setDaemon(true);
0940: debugThread.start();
0941: }
0942:
0943: threadName = "Ajp13Connector[" + port + "]";
0944: threadGroup = new ThreadGroup(threadName);
0945: threadGroup.setDaemon(true);
0946: logger.setConnector(this );
0947: logger.setName(threadName);
0948: lifecycle.fireLifecycleEvent(START_EVENT, null);
0949: started = true;
0950:
0951: // Establish a server socket on the specified port
0952: try {
0953: serverSocket = open();
0954: } catch (IOException e) {
0955: throw new LifecycleException(threadName + ".open", e);
0956: }
0957:
0958: // Start our background thread
0959: threadStart();
0960:
0961: // Create the specified minimum number of processors
0962: while (curProcessors < minProcessors) {
0963: if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
0964: break;
0965: Ajp13Processor processor = newProcessor();
0966: recycle(processor);
0967: }
0968:
0969: }
0970:
0971: /**
0972: * Terminate processing requests via this Connector.
0973: *
0974: * @exception LifecycleException if a fatal shutdown error occurs
0975: */
0976: public void stop() throws LifecycleException {
0977:
0978: // Validate and update our current state
0979: if (!started)
0980: throw new LifecycleException(sm
0981: .getString("ajp13Connector.notStarted"));
0982: lifecycle.fireLifecycleEvent(STOP_EVENT, null);
0983: started = false;
0984:
0985: // Gracefully shut down all processors we have created
0986: for (int i = created.size() - 1; i >= 0; i--) {
0987: Ajp13Processor processor = (Ajp13Processor) created
0988: .elementAt(i);
0989: if (processor instanceof Lifecycle) {
0990: try {
0991: ((Lifecycle) processor).stop();
0992: } catch (LifecycleException e) {
0993: logger.log("Ajp13Connector.stop", e);
0994: }
0995: }
0996: }
0997:
0998: // Stop our background thread
0999: threadStop();
1000:
1001: // Close the server socket we were using
1002: if (serverSocket != null) {
1003: try {
1004: serverSocket.close();
1005: } catch (IOException e) {
1006: ;
1007: }
1008: serverSocket = null;
1009: }
1010:
1011: }
1012:
1013: /**
1014: * Debugging thread used to debug thread activity in this
1015: * connector.
1016: */
1017: private class DebugThread extends Thread {
1018: public void run() {
1019: while (true) {
1020: try {
1021: sleep(60 * 1000);
1022: } catch (InterruptedException e) {
1023: break;
1024: }
1025: logger.log("active threads="
1026: + threadGroup.activeCount());
1027: System.out
1028: .println("===================================");
1029: System.out.println("Ajp13Connector active threads="
1030: + threadGroup.activeCount());
1031: threadGroup.list();
1032: System.out
1033: .println("===================================");
1034: }
1035: }
1036: }
1037:
1038: }
|