Source code: org/apache/ajp/tomcat4/Ajp13Connector.java
1 /*
2 * Copyright 1999-2004 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.ajp.tomcat4;
18
19 import java.io.IOException;
20 import java.net.InetAddress;
21 import java.net.ServerSocket;
22 import java.net.Socket;
23 import java.security.AccessControlException;
24 import java.util.Stack;
25 import java.util.Vector;
26
27 import org.apache.catalina.Connector;
28 import org.apache.catalina.Container;
29 import org.apache.catalina.Lifecycle;
30 import org.apache.catalina.LifecycleException;
31 import org.apache.catalina.LifecycleListener;
32 import org.apache.catalina.Request;
33 import org.apache.catalina.Response;
34 import org.apache.catalina.Service;
35 import org.apache.catalina.net.DefaultServerSocketFactory;
36 import org.apache.catalina.net.ServerSocketFactory;
37 import org.apache.catalina.util.LifecycleSupport;
38 import org.apache.catalina.util.StringManager;
39
40 /**
41 * Implementation of an Ajp13 connector.
42 *
43 * @author Kevin Seguin
44 * @version $Revision: 299218 $ $Date: 2004-02-24 03:48:44 -0500 (Tue, 24 Feb 2004) $
45 */
46
47
48 public final class Ajp13Connector
49 implements Connector, Lifecycle, Runnable {
50
51
52 // ----------------------------------------------------- Instance Variables
53
54
55 /**
56 * The accept count for this Connector.
57 */
58 private int acceptCount = 10;
59
60
61 /**
62 * The IP address on which to bind, if any. If <code>null</code>, all
63 * addresses on the server will be bound.
64 */
65 private String address = null;
66
67
68 /**
69 * The input buffer size we should create on input streams.
70 */
71 private int bufferSize = 2048;
72
73
74 /**
75 * The Container used for processing requests received by this Connector.
76 */
77 protected Container container = null;
78
79
80 /**
81 * The set of processors that have ever been created.
82 */
83 private Vector created = new Vector();
84
85
86 /**
87 * The current number of processors that have been created.
88 */
89 private int curProcessors = 0;
90
91
92 /**
93 * The debugging detail level for this component.
94 */
95 private int debug = 0;
96
97
98 /**
99 * The server socket factory for this component.
100 */
101 private ServerSocketFactory factory = null;
102
103
104 /**
105 * Descriptive information about this Connector implementation.
106 */
107 private static final String info =
108 "org.apache.catalina.connector.ajp.Ajp13Connector/1.0";
109
110
111 /**
112 * redirect port.
113 */
114 private int redirectPort = -1;
115
116 /**
117 * enable DNS lookups.
118 */
119 private boolean enableLookups = false;
120
121 /**
122 * The lifecycle event support for this component.
123 */
124 protected LifecycleSupport lifecycle = new LifecycleSupport(this);
125
126
127 /**
128 * The minimum number of processors to start at initialization time.
129 */
130 protected int minProcessors = 5;
131
132
133 /**
134 * The maximum number of processors allowed, or <0 for unlimited.
135 */
136 private int maxProcessors = 20;
137
138
139 /**
140 * Timeout value on the incoming connection.
141 * Note : a value of 0 means no timeout.
142 */
143 private int connectionTimeout = -1;
144
145
146 /**
147 * Linger value to be used on socket close.
148 * Note : a value of -1 means no linger used on close.
149 */
150 private int connectionLinger = -1;
151
152
153 /**
154 * The port number on which we listen for ajp13 requests.
155 */
156 private int port = 8009;
157
158
159 /**
160 * The set of processors that have been created but are not currently
161 * being used to process a request.
162 */
163 private Stack processors = new Stack();
164
165
166 /**
167 * The request scheme that will be set on all requests received
168 * through this connector.
169 */
170 private String scheme = "http";
171
172
173 /**
174 * The secure connection flag that will be set on all requests received
175 * through this connector.
176 */
177 private boolean secure = false;
178
179
180 /**
181 * The server socket through which we listen for incoming TCP connections.
182 */
183 private ServerSocket serverSocket = null;
184
185
186 /**
187 * The string manager for this package.
188 */
189 private StringManager sm =
190 StringManager.getManager(Constants.PACKAGE);
191
192
193 /**
194 * Has this component been started yet?
195 */
196 private boolean started = false;
197
198
199 /**
200 * The shutdown signal to our background thread
201 */
202 private boolean stopped = false;
203
204
205 /**
206 * The background thread.
207 */
208 private Thread thread = null;
209
210
211 /**
212 * This connector's thread group.
213 */
214 private ThreadGroup threadGroup = null;
215
216
217 /**
218 * The name to register for the background thread.
219 */
220 private String threadName = null;
221
222
223 /**
224 * A thread that periodically logs debug info if debug > 0.
225 */
226 private DebugThread debugThread = null;
227
228
229 /**
230 * The thread synchronization object.
231 */
232 private Object threadSync = new Object();
233
234 private Ajp13Logger logger = new Ajp13Logger();
235
236 /**
237 * The service which which the connector is associated
238 */
239 private Service service = null;
240
241 private String secret = null;
242
243
244 /**
245 * Tomcat authentication flag. If true, the authnetication is done by
246 * Tomcat, otherwise, it is done by the native webserver.
247 */
248 private boolean tomcatAuthentication = true;
249
250
251 // ------------------------------------------------------------- Properties
252
253
254 /**
255 * Return the connection timeout for this Connector.
256 */
257 public int getConnectionTimeout() {
258
259 return (connectionTimeout);
260
261 }
262
263
264 /**
265 * Set the connection timeout for this Connector.
266 *
267 * @param connectionTimeout The new connection timeout
268 */
269 public void setConnectionTimeout(int connectionTimeout) {
270
271 this.connectionTimeout = connectionTimeout;
272
273 }
274
275 /**
276 * Return the connection linger settings for this Connector.
277 */
278 public int getConnectionLinger() {
279
280 return (connectionLinger);
281
282 }
283
284
285 /**
286 * Set the connection linger for this Connector.
287 *
288 * @param connectionLinger The new connection linger
289 */
290 public void setConnectionLinger(int connectionLinger) {
291
292 this.connectionLinger = connectionLinger;
293
294 }
295
296 public void setSecret( String s ) {
297 secret=s;
298 }
299
300 public String getSecret() {
301 return secret;
302 }
303
304
305 /**
306 * Return the accept count for this Connector.
307 */
308 public int getAcceptCount() {
309
310 return (acceptCount);
311
312 }
313
314
315 /**
316 * Set the accept count for this Connector.
317 *
318 * @param count The new accept count
319 */
320 public void setAcceptCount(int count) {
321
322 this.acceptCount = count;
323
324 }
325
326
327
328 /**
329 * Return the bind IP address for this Connector.
330 */
331 public String getAddress() {
332
333 return (this.address);
334
335 }
336
337
338 /**
339 * Set the bind IP address for this Connector.
340 *
341 * @param address The bind IP address
342 */
343 public void setAddress(String address) {
344
345 this.address = address;
346
347 }
348
349
350 /**
351 * Is this connector available for processing requests?
352 */
353 public boolean isAvailable() {
354
355 return (started);
356
357 }
358
359
360 /**
361 * Return the input buffer size for this Connector.
362 */
363 public int getBufferSize() {
364
365 return (this.bufferSize);
366
367 }
368
369
370 /**
371 * Set the input buffer size for this Connector.
372 *
373 * @param bufferSize The new input buffer size.
374 */
375 public void setBufferSize(int bufferSize) {
376
377 this.bufferSize = bufferSize;
378
379 }
380
381
382 /**
383 * Return the Container used for processing requests received by this
384 * Connector.
385 */
386 public Container getContainer() {
387
388 return (container);
389
390 }
391
392
393 /**
394 * Set the Container used for processing requests received by this
395 * Connector.
396 *
397 * @param container The new Container to use
398 */
399 public void setContainer(Container container) {
400
401 this.container = container;
402
403 }
404
405
406 /**
407 * Return the current number of processors that have been created.
408 */
409 public int getCurProcessors() {
410
411 return (curProcessors);
412
413 }
414
415
416 /**
417 * Return the debugging detail level for this component.
418 */
419 public int getDebug() {
420
421 return (debug);
422
423 }
424
425
426 /**
427 * Set the debugging detail level for this component.
428 *
429 * @param debug The new debugging detail level
430 */
431 public void setDebug(int debug) {
432
433 this.debug = debug;
434
435 }
436
437 /**
438 * Return the "enable DNS lookups" flag.
439 */
440 public boolean getEnableLookups() {
441 return this.enableLookups;
442 }
443
444 /**
445 * Set the "enable DNS lookups" flag.
446 *
447 * @param enableLookups The new "enable DNS lookups" flag value
448 */
449 public void setEnableLookups(boolean enableLookups) {
450 this.enableLookups = enableLookups;
451 }
452
453 /**
454 * Return the port number to which a request should be redirected if
455 * it comes in on a non-SSL port and is subject to a security constraint
456 * with a transport guarantee that requires SSL.
457 */
458 public int getRedirectPort() {
459 return this.redirectPort;
460 }
461
462
463 /**
464 * Set the redirect port number.
465 *
466 * @param redirectPort The redirect port number (non-SSL to SSL)
467 */
468 public void setRedirectPort(int redirectPort) {
469 this.redirectPort = redirectPort;
470 }
471
472 /**
473 * Return the server socket factory used by this Container.
474 */
475 public ServerSocketFactory getFactory() {
476
477 if (this.factory == null) {
478 synchronized (this) {
479 this.factory = new DefaultServerSocketFactory();
480 }
481 }
482 return (this.factory);
483
484 }
485
486
487 /**
488 * Set the server socket factory used by this Container.
489 *
490 * @param factory The new server socket factory
491 */
492 public void setFactory(ServerSocketFactory factory) {
493
494 this.factory = factory;
495
496 }
497
498
499 /**
500 * Return descriptive information about this Connector implementation.
501 */
502 public String getInfo() {
503
504 return (info);
505
506 }
507
508
509 /**
510 * Return the minimum number of processors to start at initialization.
511 */
512 public int getMinProcessors() {
513
514 return (minProcessors);
515
516 }
517
518
519 /**
520 * Set the minimum number of processors to start at initialization.
521 *
522 * @param minProcessors The new minimum processors
523 */
524 public void setMinProcessors(int minProcessors) {
525
526 this.minProcessors = minProcessors;
527
528 }
529
530
531 /**
532 * Return the maximum number of processors allowed, or <0 for unlimited.
533 */
534 public int getMaxProcessors() {
535
536 return (maxProcessors);
537
538 }
539
540
541 /**
542 * Set the maximum number of processors allowed, or <0 for unlimited.
543 *
544 * @param maxProcessors The new maximum processors
545 */
546 public void setMaxProcessors(int maxProcessors) {
547
548 this.maxProcessors = maxProcessors;
549
550 }
551
552
553 /**
554 * Return the port number on which we listen for AJP13 requests.
555 */
556 public int getPort() {
557
558 return (this.port);
559
560 }
561
562
563 /**
564 * Set the port number on which we listen for AJP13 requests.
565 *
566 * @param port The new port number
567 */
568 public void setPort(int port) {
569
570 this.port = port;
571
572 }
573
574
575 /**
576 * Return the scheme that will be assigned to requests received
577 * through this connector. Default value is "http".
578 */
579 public String getScheme() {
580
581 return (this.scheme);
582
583 }
584
585
586 /**
587 * Set the scheme that will be assigned to requests received through
588 * this connector.
589 *
590 * @param scheme The new scheme
591 */
592 public void setScheme(String scheme) {
593
594 this.scheme = scheme;
595
596 }
597
598
599 /**
600 * Return the secure connection flag that will be assigned to requests
601 * received through this connector. Default value is "false".
602 */
603 public boolean getSecure() {
604
605 return (this.secure);
606
607 }
608
609
610 /**
611 * Set the secure connection flag that will be assigned to requests
612 * received through this connector.
613 *
614 * @param secure The new secure connection flag
615 */
616 public void setSecure(boolean secure) {
617
618 this.secure = secure;
619
620 }
621
622
623 /**
624 * Returns the <code>Service</code> with which we are associated.
625 */
626 public Service getService() {
627 return service;
628 }
629
630
631 /**
632 * Set the <code>Service</code> with which we are associated.
633 */
634 public void setService(Service service) {
635 this.service = service;
636 }
637
638
639 /**
640 * Get the value of the tomcatAuthentication flag.
641 */
642 public boolean getTomcatAuthentication() {
643 return tomcatAuthentication;
644 }
645
646
647 /**
648 * Set the value of the tomcatAuthentication flag.
649 */
650 public void setTomcatAuthentication(boolean tomcatAuthentication) {
651 this.tomcatAuthentication = tomcatAuthentication;
652 }
653
654
655 // --------------------------------------------------------- Public Methods
656
657
658 /**
659 * Create (or allocate) and return a Request object suitable for
660 * specifying the contents of a Request to the responsible Container.
661 */
662 public Request createRequest() {
663
664 Ajp13Request request = new Ajp13Request(this);
665 request.setConnector(this);
666 return (request);
667
668 }
669
670
671 /**
672 * Create (or allocate) and return a Response object suitable for
673 * receiving the contents of a Response from the responsible Container.
674 */
675 public Response createResponse() {
676
677 Ajp13Response response = new Ajp13Response();
678 response.setConnector(this);
679 return (response);
680
681 }
682
683 /**
684 * Invoke a pre-startup initialization. This is used to allow connectors
685 * to bind to restricted ports under Unix operating environments.
686 * ServerSocket (we start as root and change user? or I miss something?).
687 */
688 public void initialize() throws LifecycleException {
689 }
690
691
692 // -------------------------------------------------------- Package Methods
693
694
695 /**
696 * Recycle the specified Processor so that it can be used again.
697 *
698 * @param processor The processor to be recycled
699 */
700 void recycle(Ajp13Processor processor) {
701
702 synchronized(processors) {
703 if (debug > 0) {
704 logger.log("added processor to available processors, available="
705 + processors.size());
706 }
707 processors.push(processor);
708 }
709
710 }
711
712
713 // -------------------------------------------------------- Private Methods
714
715
716 /**
717 * Create (or allocate) and return an available processor for use in
718 * processing a specific AJP13 request, if possible. If the maximum
719 * allowed processors have already been created and are in use, return
720 * <code>null</code> instead.
721 */
722 private Ajp13Processor createProcessor() {
723
724 synchronized (processors) {
725 if (processors.size() > 0)
726 return ((Ajp13Processor) processors.pop());
727 if ((maxProcessors > 0) && (curProcessors < maxProcessors))
728 return (newProcessor());
729 else
730 return (null);
731 }
732
733 }
734
735
736 /**
737 * Create and return a new processor suitable for processing AJP13
738 * requests and returning the corresponding responses.
739 */
740 private Ajp13Processor newProcessor() {
741
742 Ajp13Processor processor = new Ajp13Processor(this, curProcessors++, threadGroup);
743 if (processor instanceof Lifecycle) {
744 try {
745 ((Lifecycle) processor).start();
746 } catch (LifecycleException e) {
747 logger.log("newProcessor", e);
748 curProcessors--;
749 return (null);
750 }
751 }
752 created.addElement(processor);
753 return (processor);
754
755 }
756
757
758 /**
759 * Open and return the server socket for this Connector. If an IP
760 * address has been specified, the socket will be opened only on that
761 * address; otherwise it will be opened on all addresses.
762 *
763 * @exception IOException if an input/output error occurs
764 */
765 private ServerSocket open() throws IOException {
766
767 // Acquire the server socket factory for this Connector
768 ServerSocketFactory factory = getFactory();
769
770 // If no address is specified, open a connection on all addresses
771 if (address == null) {
772 logger.log(sm.getString("ajp13Connector.allAddresses"));
773 try {
774 return (factory.createSocket(port, acceptCount));
775 } catch(Exception ex ) {
776 ex.printStackTrace();
777 return null;
778 }
779 }
780
781 // Open a server socket on the specified address
782 try {
783 InetAddress is = InetAddress.getByName(address);
784 logger.log(sm.getString("ajp13Connector.anAddress", address));
785 return (factory.createSocket(port, acceptCount, is));
786 } catch (Exception e) {
787 try {
788 logger.log(sm.getString("ajp13Connector.noAddress", address));
789 return (factory.createSocket(port, acceptCount));
790 } catch( Exception e1 ) {
791 e1.printStackTrace();
792 return null;
793 }
794 }
795
796 }
797
798
799 // ---------------------------------------------- Background Thread Methods
800
801
802 /**
803 * The background thread that listens for incoming TCP/IP connections and
804 * hands them off to an appropriate processor.
805 */
806 public void run() {
807
808 // Loop until we receive a shutdown command
809 while (!stopped) {
810
811 // Accept the next incoming connection from the server socket
812 Socket socket = null;
813 try {
814 if (debug > 0) {
815 logger.log("accepting socket...");
816 }
817
818 socket = serverSocket.accept();
819
820 if (debug > 0) {
821 logger.log("accepted socket, assigning to processor.");
822 }
823
824 /* Warning :
825 *
826 * To be able to close more quickly a connection, it's recommanded
827 * to set linger to a small value.
828 *
829 * AJP13 connection SHOULD be closed under webserver responsability and
830 * in such case it's safe to close socket on Tomcat side without delay,
831 * which may be also the case for HTTP connectors.
832 *
833 * I (henri) recommand to set Linger to 0, making socket closed immediatly
834 * so the OS will free faster the underlying io descriptor and resources.
835 * It's very important under heavy load !
836 */
837
838 if (connectionLinger < 0)
839 socket.setSoLinger(false, 0);
840 else
841 socket.setSoLinger(true, connectionLinger);
842
843 /* We don't need it since it's the native side which
844 * will set the connection with keep alive
845 * if specified in workers.properties.
846 *
847 * socket.setKeepAlive(true);
848 */
849
850 /* Warning :
851 *
852 * AJP13 shouldn't use socket timeout on tomcat site since
853 * when Tomcat close a connection after a timeout is reached
854 * the socket stay in half-closed state until the webserver
855 * try to send a request to tomcat and detect the socket close
856 * when it will try to read the reply.
857 *
858 * On many Unix platforms the write() call didn't told
859 * webserver that the socket is closed.
860 */
861
862 if (connectionTimeout >= 0) {
863 socket.setSoTimeout(connectionTimeout);
864 }
865 } catch (AccessControlException ace) {
866 logger.log("socket accept security exception: "
867 + ace.getMessage());
868 continue;
869 } catch (IOException e) {
870 if (started && !stopped)
871 logger.log("accept: ", e);
872 try {
873 if (serverSocket != null) {
874 serverSocket.close();
875 }
876 if (stopped) {
877 if (debug > 0) {
878 logger.log("run(): stopped, so breaking");
879 }
880 break;
881 } else {
882 if (debug > 0) {
883 logger.log("run(): not stopped, " +
884 "so reopening server socket");
885 }
886 serverSocket = open();
887 }
888 } catch (IOException ex) {
889 // If reopening fails, exit
890 logger.log("socket reopen: ", ex);
891 break;
892 }
893 continue;
894 }
895
896 // Hand this socket off to an appropriate processor
897 if (debug > 0) {
898 synchronized(processors) {
899 logger.log("about to create a processor, available="
900 + processors.size() + ", created=" + created.size()
901 + ", maxProcessors=" + maxProcessors);
902 }
903 }
904 Ajp13Processor processor = createProcessor();
905 if (processor == null) {
906 try {
907 logger.log(sm.getString("ajp13Connector.noProcessor"));
908 socket.close();
909 } catch (IOException e) {
910 ;
911 }
912 continue;
913 }
914 processor.assign(socket);
915
916 // The processor will recycle itself when it finishes
917
918 }
919
920 // Notify the threadStop() method that we have shut ourselves down
921 synchronized (threadSync) {
922 threadSync.notifyAll();
923 }
924
925 }
926
927
928 /**
929 * Start the background processing thread.
930 */
931 private void threadStart() {
932
933 logger.log(sm.getString("ajp13Connector.starting"));
934
935 thread = new Thread(threadGroup, this, threadName);
936 thread.setDaemon(true);
937 thread.start();
938
939 }
940
941
942 /**
943 * Stop the background processing thread.
944 */
945 private void threadStop() {
946
947 logger.log(sm.getString("ajp13Connector.stopping"));
948
949 stopped = true;
950 synchronized (threadSync) {
951 try {
952 threadSync.wait(5000);
953 } catch (InterruptedException e) {
954 ;
955 }
956 }
957 thread = null;
958
959 }
960
961
962 // ------------------------------------------------------ Lifecycle Methods
963
964
965 /**
966 * Add a lifecycle event listener to this component.
967 *
968 * @param listener The listener to add
969 */
970 public void addLifecycleListener(LifecycleListener listener) {
971
972 lifecycle.addLifecycleListener(listener);
973
974 }
975
976 /**
977 * Get the lifecycle listeners associated with this lifecycle. If this
978 * Lifecycle has no listeners registered, a zero-length array is returned.
979 */
980 public LifecycleListener[] findLifecycleListeners() {
981 return null; // FIXME: lifecycle.findLifecycleListeners();
982 }
983
984
985 /**
986 * Remove a lifecycle event listener from this component.
987 *
988 * @param listener The listener to add
989 */
990 public void removeLifecycleListener(LifecycleListener listener) {
991
992 lifecycle.removeLifecycleListener(listener);
993
994 }
995
996
997 /**
998 * Begin processing requests via this Connector.
999 *
1000 * @exception LifecycleException if a fatal startup error occurs
1001 */
1002 public void start() throws LifecycleException {
1003
1004 // Validate and update our current state
1005 if (started)
1006 throw new LifecycleException
1007 (sm.getString("ajp13Connector.alreadyStarted"));
1008
1009 if (debug > 0) {
1010 debugThread = new DebugThread();
1011 debugThread.setDaemon(true);
1012 debugThread.start();
1013 }
1014
1015 threadName = "Ajp13Connector[" + port + "]";
1016 threadGroup = new ThreadGroup(threadName);
1017 threadGroup.setDaemon(true);
1018 logger.setConnector(this);
1019 logger.setName(threadName);
1020 lifecycle.fireLifecycleEvent(START_EVENT, null);
1021 started = true;
1022
1023 // Establish a server socket on the specified port
1024 try {
1025 serverSocket = open();
1026 } catch (IOException e) {
1027 throw new LifecycleException(threadName + ".open", e);
1028 }
1029
1030 // Start our background thread
1031 threadStart();
1032
1033 // Create the specified minimum number of processors
1034 while (curProcessors < minProcessors) {
1035 if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
1036 break;
1037 Ajp13Processor processor = newProcessor();
1038 recycle(processor);
1039 }
1040
1041 }
1042
1043
1044 /**
1045 * Terminate processing requests via this Connector.
1046 *
1047 * @exception LifecycleException if a fatal shutdown error occurs
1048 */
1049 public void stop() throws LifecycleException {
1050
1051 // Validate and update our current state
1052 if (!started)
1053 throw new LifecycleException
1054 (sm.getString("ajp13Connector.notStarted"));
1055 lifecycle.fireLifecycleEvent(STOP_EVENT, null);
1056 started = false;
1057
1058 // Gracefully shut down all processors we have created
1059 for (int i = created.size() - 1; i >= 0; i--) {
1060 Ajp13Processor processor = (Ajp13Processor) created.elementAt(i);
1061 if (processor instanceof Lifecycle) {
1062 try {
1063 ((Lifecycle) processor).stop();
1064 } catch (LifecycleException e) {
1065 logger.log("Ajp13Connector.stop", e);
1066 }
1067 }
1068 }
1069
1070 // Stop our background thread
1071 threadStop();
1072
1073 // Close the server socket we were using
1074 if (serverSocket != null) {
1075 try {
1076 serverSocket.close();
1077 } catch (IOException e) {
1078 ;
1079 }
1080 serverSocket = null;
1081 }
1082
1083 }
1084
1085 /**
1086 * Debugging thread used to debug thread activity in this
1087 * connector.
1088 */
1089 private class DebugThread extends Thread
1090 {
1091 public void run() {
1092 while (true) {
1093 try {
1094 sleep(60 * 1000);
1095 } catch (InterruptedException e) {
1096 break;
1097 }
1098 logger.log("active threads=" + threadGroup.activeCount());
1099 System.out.println("===================================");
1100 System.out.println("Ajp13Connector active threads="
1101 + threadGroup.activeCount());
1102 threadGroup.list();
1103 System.out.println("===================================");
1104 }
1105 }
1106 }
1107
1108}