001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.tomcat.util.net;
019:
020: import java.net.InetAddress;
021: import java.util.concurrent.Executor;
022:
023: import org.apache.juli.logging.Log;
024: import org.apache.juli.logging.LogFactory;
025: import org.apache.tomcat.util.res.StringManager;
026:
027: /**
028: * APR tailored thread pool, providing the following services:
029: * <ul>
030: * <li>Socket acceptor thread</li>
031: * <li>Socket poller thread</li>
032: * <li>Sendfile thread</li>
033: * <li>Worker threads pool</li>
034: * </ul>
035: *
036: * When switching to Java 5, there's an opportunity to use the virtual
037: * machine's thread pool.
038: *
039: * @author Mladen Turk
040: * @author Remy Maucherat
041: */
042: public abstract class BaseEndpoint {
043:
044: // -------------------------------------------------------------- Constants
045:
046: protected static Log log = LogFactory.getLog(BaseEndpoint.class);
047:
048: protected static StringManager sm = StringManager
049: .getManager("org.apache.tomcat.util.net.res");
050:
051: /**
052: * The Request attribute key for the cipher suite.
053: */
054: public static final String CIPHER_SUITE_KEY = "javax.servlet.request.cipher_suite";
055:
056: /**
057: * The Request attribute key for the key size.
058: */
059: public static final String KEY_SIZE_KEY = "javax.servlet.request.key_size";
060:
061: /**
062: * The Request attribute key for the client certificate chain.
063: */
064: public static final String CERTIFICATE_KEY = "javax.servlet.request.X509Certificate";
065:
066: /**
067: * The Request attribute key for the session id.
068: * This one is a Tomcat extension to the Servlet spec.
069: */
070: public static final String SESSION_ID_KEY = "javax.servlet.request.ssl_session";
071:
072: // ----------------------------------------------------------------- Fields
073:
074: /**
075: * Running state of the endpoint.
076: */
077: protected volatile boolean running = false;
078:
079: /**
080: * Will be set to true whenever the endpoint is paused.
081: */
082: protected volatile boolean paused = false;
083:
084: /**
085: * Track the initialization state of the endpoint.
086: */
087: protected boolean initialized = false;
088:
089: /**
090: * Current worker threads busy count.
091: */
092: protected int curThreadsBusy = 0;
093:
094: /**
095: * Current worker threads count.
096: */
097: protected int curThreads = 0;
098:
099: /**
100: * Sequence number used to generate thread names.
101: */
102: protected int sequence = 0;
103:
104: // ------------------------------------------------------------- Properties
105:
106: /**
107: * External Executor based thread pool.
108: */
109: protected Executor executor = null;
110:
111: public void setExecutor(Executor executor) {
112: this .executor = executor;
113: }
114:
115: public Executor getExecutor() {
116: return executor;
117: }
118:
119: /**
120: * Maximum amount of worker threads.
121: */
122: protected int maxThreads = 40;
123:
124: public void setMaxThreads(int maxThreads) {
125: this .maxThreads = maxThreads;
126: }
127:
128: public int getMaxThreads() {
129: return maxThreads;
130: }
131:
132: /**
133: * Priority of the acceptor and poller threads.
134: */
135: protected int threadPriority = Thread.NORM_PRIORITY;
136:
137: public void setThreadPriority(int threadPriority) {
138: this .threadPriority = threadPriority;
139: }
140:
141: public int getThreadPriority() {
142: return threadPriority;
143: }
144:
145: /**
146: * Server socket port.
147: */
148: protected int port;
149:
150: public int getPort() {
151: return port;
152: }
153:
154: public void setPort(int port) {
155: this .port = port;
156: }
157:
158: /**
159: * Address for the server socket.
160: */
161: protected InetAddress address;
162:
163: public InetAddress getAddress() {
164: return address;
165: }
166:
167: public void setAddress(InetAddress address) {
168: this .address = address;
169: }
170:
171: /**
172: * Allows the server developer to specify the backlog that
173: * should be used for server sockets. By default, this value
174: * is 100.
175: */
176: protected int backlog = 100;
177:
178: public void setBacklog(int backlog) {
179: if (backlog > 0)
180: this .backlog = backlog;
181: }
182:
183: public int getBacklog() {
184: return backlog;
185: }
186:
187: /**
188: * Socket TCP no delay.
189: */
190: protected boolean tcpNoDelay = false;
191:
192: public boolean getTcpNoDelay() {
193: return tcpNoDelay;
194: }
195:
196: public void setTcpNoDelay(boolean tcpNoDelay) {
197: this .tcpNoDelay = tcpNoDelay;
198: }
199:
200: /**
201: * Socket linger.
202: */
203: protected int soLinger = 100;
204:
205: public int getSoLinger() {
206: return soLinger;
207: }
208:
209: public void setSoLinger(int soLinger) {
210: this .soLinger = soLinger;
211: }
212:
213: /**
214: * Socket timeout.
215: */
216: protected int soTimeout = -1;
217:
218: public int getSoTimeout() {
219: return soTimeout;
220: }
221:
222: public void setSoTimeout(int soTimeout) {
223: this .soTimeout = soTimeout;
224: }
225:
226: /**
227: * The default is true - the created threads will be
228: * in daemon mode. If set to false, the control thread
229: * will not be daemon - and will keep the process alive.
230: */
231: protected boolean daemon = true;
232:
233: public void setDaemon(boolean b) {
234: daemon = b;
235: }
236:
237: public boolean getDaemon() {
238: return daemon;
239: }
240:
241: /**
242: * Name of the thread pool, which will be used for naming child threads.
243: */
244: protected String name = "TP";
245:
246: public void setName(String name) {
247: this .name = name;
248: }
249:
250: public String getName() {
251: return name;
252: }
253:
254: /**
255: * Dummy maxSpareThreads property.
256: */
257: public int getMaxSpareThreads() {
258: return 0;
259: }
260:
261: /**
262: * Dummy minSpareThreads property.
263: */
264: public int getMinSpareThreads() {
265: return 0;
266: }
267:
268: // --------------------------------------------------------- Public Methods
269:
270: /**
271: * Return the amount of threads that are managed by the pool.
272: *
273: * @return the amount of threads that are managed by the pool
274: */
275: public int getCurrentThreadCount() {
276: return curThreads;
277: }
278:
279: /**
280: * Return the amount of threads currently busy.
281: *
282: * @return the amount of threads currently busy
283: */
284: public int getCurrentThreadsBusy() {
285: return curThreadsBusy;
286: }
287:
288: /**
289: * Return the state of the endpoint.
290: *
291: * @return true if the endpoint is running, false otherwise
292: */
293: public boolean isRunning() {
294: return running;
295: }
296:
297: /**
298: * Return the state of the endpoint.
299: *
300: * @return true if the endpoint is paused, false otherwise
301: */
302: public boolean isPaused() {
303: return paused;
304: }
305:
306: // ----------------------------------------------- Public Lifecycle Methods
307:
308: /**
309: * Initialize the endpoint.
310: */
311: public abstract void init() throws Exception;
312:
313: /**
314: * Start the APR endpoint, creating acceptor, poller and sendfile threads.
315: */
316: public abstract void start() throws Exception;
317:
318: /**
319: * Pause the endpoint, which will make it stop accepting new sockets.
320: */
321: public void pause() {
322: if (running && !paused) {
323: paused = true;
324: unlockAccept();
325: }
326: }
327:
328: /**
329: * Resume the endpoint, which will make it start accepting new sockets
330: * again.
331: */
332: public void resume() {
333: if (running) {
334: paused = false;
335: }
336: }
337:
338: /**
339: * Stop the endpoint. This will cause all processing threads to stop.
340: */
341: public abstract void stop();
342:
343: /**
344: * Deallocate APR memory pools, and close server socket.
345: */
346: public abstract void destroy() throws Exception;
347:
348: // ------------------------------------------------------ Protected Methods
349:
350: /**
351: * Get a sequence number used for thread naming.
352: */
353: protected int getSequence() {
354: return sequence++;
355: }
356:
357: /**
358: * Unlock the server socket accept using a bugus connection.
359: */
360: protected void unlockAccept() {
361: java.net.Socket s = null;
362: try {
363: // Need to create a connection to unlock the accept();
364: if (address == null) {
365: s = new java.net.Socket("127.0.0.1", port);
366: } else {
367: s = new java.net.Socket(address, port);
368: // setting soLinger to a small value will help shutdown the
369: // connection quicker
370: s.setSoLinger(true, 0);
371: }
372: } catch (Exception e) {
373: if (log.isDebugEnabled()) {
374: log.debug(sm.getString("endpoint.debug.unlock", ""
375: + port), e);
376: }
377: } finally {
378: if (s != null) {
379: try {
380: s.close();
381: } catch (Exception e) {
382: // Ignore
383: }
384: }
385: }
386: }
387:
388: }
|