001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.axis2.transport.http.server;
021:
022: import java.io.IOException;
023:
024: import org.apache.axis2.AxisFault;
025: import org.apache.axis2.Constants;
026: import org.apache.axis2.context.ConfigurationContext;
027: import org.apache.axis2.description.Parameter;
028: import org.apache.axis2.description.TransportInDescription;
029: import org.apache.axis2.engine.ListenerManager;
030: import org.apache.axis2.transport.http.HTTPWorkerFactory;
031: import org.apache.http.ConnectionReuseStrategy;
032: import org.apache.http.HttpResponseFactory;
033: import org.apache.http.impl.DefaultConnectionReuseStrategy;
034: import org.apache.http.impl.DefaultHttpResponseFactory;
035: import org.apache.http.params.BasicHttpParams;
036: import org.apache.http.params.HttpConnectionParams;
037: import org.apache.http.params.HttpParams;
038: import org.apache.http.params.HttpProtocolParams;
039: import org.apache.http.protocol.BasicHttpProcessor;
040: import org.apache.http.protocol.HttpProcessor;
041: import org.apache.http.protocol.ResponseConnControl;
042: import org.apache.http.protocol.ResponseContent;
043: import org.apache.http.protocol.ResponseDate;
044: import org.apache.http.protocol.ResponseServer;
045:
046: import edu.emory.mathcs.backport.java.util.concurrent.BlockingQueue;
047: import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService;
048: import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue;
049: import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor;
050: import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
051:
052: /**
053: * Factory used to configure and create the various instances required in http transports.
054: * Either configure this class in axis2.xml, or in code via the setters, or subclass it and specialize some factory methods to gain more control.
055: *
056: * @author Chuck Williams
057: */
058: public class HttpFactory {
059:
060: /**
061: * Name of axis2.xml port parameter for SimpleHTTPServer configuration
062: */
063: public static final String PARAMETER_PORT = "port";
064:
065: /**
066: * Name of axis2.xml hostname parameter for SimpleHTTPServer configuration
067: */
068: public static final String PARAMETER_HOST_ADDRESS = "hostname";
069:
070: /**
071: * Name of axis2.xml originServer parameter for SimpleHTTPServer configuration
072: */
073: public static final String PARAMETER_ORIGIN_SERVER = "originServer";
074:
075: /**
076: * Name of axis2.xml requestTimeout parameter for SimpleHTTPServer configuration
077: */
078: public static final String PARAMETER_REQUEST_SOCKET_TIMEOUT = "requestTimeout";
079:
080: /**
081: * Name of axis2.xml requestTcpNoDelay parameter for SimpleHTTPServer configuration
082: */
083: public static final String PARAMETER_REQUEST_TCP_NO_DELAY = "requestTcpNoDelay";
084:
085: /**
086: * Name of axis2.xml requestCoreThreadPoolSize parameter for SimpleHTTPServer configuration
087: */
088: public static final String PARAMETER_REQUEST_CORE_THREAD_POOL_SIZE = "requestCoreThreadPoolSize";
089:
090: /**
091: * Name of axis2.xml requestMaxThreadPoolSize parameter for SimpleHTTPServer configuration
092: */
093: public static final String PARAMETER_REQUEST_MAX_THREAD_POOL_SIZE = "requestMaxThreadPoolSize";
094:
095: /**
096: * Name of axis2.xml threadKeepAliveTime parameter for SimpleHTTPServer configuration
097: */
098: public static final String PARAMETER_THREAD_KEEP_ALIVE_TIME = "threadKeepAliveTime";
099:
100: /**
101: * Name of axis2.xml threadKeepAliveTimeUnit parameter for SimpleHTTPServer configuration
102: */
103: public static final String PARAMETER_THREAD_KEEP_ALIVE_TIME_UNIT = "threadKeepAliveTimeUnit";
104:
105: private ConfigurationContext configurationContext;
106: private TransportInDescription httpConfiguration;
107: private int port;
108: private String hostAddress;
109: private String originServer;
110: private int requestSocketTimeout;
111: private boolean requestTcpNoDelay;
112: private int requestCoreThreadPoolSize;
113: private int requestMaxThreadPoolSize;
114: private long threadKeepAliveTime;
115: private TimeUnit threadKeepAliveTimeUnit;
116:
117: private WorkerFactory requestWorkerFactory = null;
118:
119: /**
120: * Create and configure a new HttpFactory
121: */
122: public HttpFactory(ConfigurationContext configurationContext)
123: throws AxisFault {
124: this .configurationContext = configurationContext;
125: httpConfiguration = configurationContext.getAxisConfiguration()
126: .getTransportIn(Constants.TRANSPORT_HTTP);
127: port = getIntParam(PARAMETER_PORT, 6060);
128: hostAddress = getStringParam(PARAMETER_HOST_ADDRESS, null);
129: originServer = getStringParam(PARAMETER_ORIGIN_SERVER,
130: "Simple-Server/1.1");
131: requestSocketTimeout = getIntParam(
132: PARAMETER_REQUEST_SOCKET_TIMEOUT, 20000);
133: requestTcpNoDelay = getBooleanParam(
134: PARAMETER_REQUEST_TCP_NO_DELAY, true);
135: requestCoreThreadPoolSize = getIntParam(
136: PARAMETER_REQUEST_CORE_THREAD_POOL_SIZE, 100);
137: requestMaxThreadPoolSize = getIntParam(
138: PARAMETER_REQUEST_MAX_THREAD_POOL_SIZE, 150);
139: threadKeepAliveTime = getLongParam(
140: PARAMETER_THREAD_KEEP_ALIVE_TIME, 180L);
141: threadKeepAliveTimeUnit = getTimeUnitParam(
142: PARAMETER_THREAD_KEEP_ALIVE_TIME_UNIT, TimeUnit.SECONDS);
143: }
144:
145: /**
146: * Create and configure a new HttpFactory
147: */
148: public HttpFactory(ConfigurationContext configurationContext,
149: int port) throws AxisFault {
150: this (configurationContext);
151: this .port = port;
152: }
153:
154: /**
155: * Create and configure a new HttpFactory
156: */
157: public HttpFactory(ConfigurationContext configurationContext,
158: int port, WorkerFactory requestWorkerFactory)
159: throws AxisFault {
160: this (configurationContext, port);
161: this .requestWorkerFactory = requestWorkerFactory;
162: }
163:
164: private int getIntParam(String name, int def) {
165: String config = getStringParam(name, null);
166: if (config != null) {
167: return Integer.parseInt(config);
168: } else {
169: return def;
170: }
171: }
172:
173: private long getLongParam(String name, long def) {
174: String config = getStringParam(name, null);
175: if (config != null) {
176: return Long.parseLong(config);
177: } else {
178: return def;
179: }
180: }
181:
182: private boolean getBooleanParam(String name, boolean def)
183: throws AxisFault {
184: String config = getStringParam(name, null);
185: if (config != null) {
186: if (config.equals("yes") || config.equals("true")) {
187: return true;
188: } else if (config.equals("no") || config.equals("false")) {
189: return false;
190: } else {
191: throw new AxisFault(
192: "Boolean value must be yes, true, no or false for parameter "
193: + name + ": " + config);
194: }
195: }
196: return def;
197: }
198:
199: private TimeUnit getTimeUnitParam(String name, TimeUnit def)
200: throws AxisFault {
201: String config = getStringParam(name, null);
202: if (config != null) {
203: try {
204: return (TimeUnit) TimeUnit.class.getField(config).get(
205: null);
206: } catch (Exception e) {
207: throw AxisFault.makeFault(e);
208: }
209: }
210: return def;
211: }
212:
213: private String getStringParam(String name, String def) {
214: Parameter param = httpConfiguration.getParameter(name);
215: if (param != null) {
216: // assert param.getParameterType() == Parameter.TEXT_PARAMETER;
217: String config = (String) param.getValue();
218: if (config != null) {
219: return config;
220: }
221: }
222: return def;
223: }
224:
225: /**
226: * Return the configured listener manager or create and configure one with configurationContext
227: */
228: public ListenerManager getListenerManager() {
229: ListenerManager lm = configurationContext.getListenerManager();
230: if (lm == null) {
231: lm = new ListenerManager();
232: lm.init(configurationContext);
233: }
234: return lm;
235: }
236:
237: /**
238: * Create the executor used to launch the single requestConnectionListener
239: */
240: public ExecutorService newListenerExecutor(int port) {
241: return new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
242: new LinkedBlockingQueue(), new DefaultThreadFactory(
243: new ThreadGroup("Listener thread group"),
244: "HttpListener-" + this .port));
245: }
246:
247: /**
248: * Create the listener for request connections
249: */
250: public IOProcessor newRequestConnectionListener(int port,
251: final HttpConnectionManager manager, final HttpParams params)
252: throws IOException {
253: return new DefaultConnectionListener(port, manager,
254: new DefaultConnectionListenerFailureHandler(), params);
255: }
256:
257: /**
258: * Create and set the parameters applied to incoming request connections
259: */
260: public HttpParams newRequestConnectionParams() {
261: HttpParams params = new BasicHttpParams();
262: params.setIntParameter(HttpConnectionParams.SO_TIMEOUT,
263: requestSocketTimeout).setBooleanParameter(
264: HttpConnectionParams.TCP_NODELAY, requestTcpNoDelay)
265: .setIntParameter(HttpConnectionParams.MAX_LINE_LENGTH,
266: 4000).setIntParameter(
267: HttpConnectionParams.MAX_HEADER_COUNT, 500)
268: .setIntParameter(
269: HttpConnectionParams.SOCKET_BUFFER_SIZE,
270: 8 * 1024).setParameter(
271: HttpProtocolParams.ORIGIN_SERVER, originServer);
272: return params;
273: }
274:
275: /**
276: * Create the connection manager used to launch request threads
277: */
278: public HttpConnectionManager newRequestConnectionManager(
279: ExecutorService requestExecutor,
280: WorkerFactory workerFactory, HttpParams params) {
281: return new DefaultHttpConnectionManager(configurationContext,
282: requestExecutor, workerFactory, params);
283: }
284:
285: /**
286: * Create the executor use the manage request processing threads
287: */
288: public ExecutorService newRequestExecutor(int port) {
289: return new ThreadPoolExecutor(requestCoreThreadPoolSize,
290: requestMaxThreadPoolSize, threadKeepAliveTime,
291: threadKeepAliveTimeUnit, newRequestBlockingQueue(),
292: new DefaultThreadFactory(new ThreadGroup(
293: "Connection thread group"), "HttpConnection-"
294: + port));
295: }
296:
297: /**
298: * Create the queue used to hold incoming requests when requestCoreThreadPoolSize threads are busy.
299: * Default is an unbounded queue.
300: */
301: public BlockingQueue newRequestBlockingQueue() {
302: return new LinkedBlockingQueue();
303: }
304:
305: /**
306: * Create the factory for request workers
307: */
308: public WorkerFactory newRequestWorkerFactory() {
309: if (requestWorkerFactory != null) {
310: return requestWorkerFactory;
311: } else {
312: return new HTTPWorkerFactory();
313: }
314: }
315:
316: public HttpProcessor newHttpProcessor() {
317: BasicHttpProcessor httpProcessor = new BasicHttpProcessor();
318: httpProcessor.addInterceptor(new RequestSessionCookie());
319: httpProcessor.addInterceptor(new ResponseDate());
320: httpProcessor.addInterceptor(new ResponseServer());
321: httpProcessor.addInterceptor(new ResponseContent());
322: httpProcessor.addInterceptor(new ResponseConnControl());
323: httpProcessor.addInterceptor(new ResponseSessionCookie());
324: return httpProcessor;
325: }
326:
327: public ConnectionReuseStrategy newConnStrategy() {
328: return new DefaultConnectionReuseStrategy();
329: }
330:
331: public HttpResponseFactory newResponseFactory() {
332: return new DefaultHttpResponseFactory();
333: }
334:
335: // *****
336: // Getters and Setters
337: // *****
338:
339: /**
340: * Getter for configurationContext
341: */
342: public ConfigurationContext getConfigurationContext() {
343: return configurationContext;
344: }
345:
346: /**
347: * Getter for httpConfiguration
348: */
349: public TransportInDescription getHttpConfiguration() {
350: return httpConfiguration;
351: }
352:
353: /**
354: * Getter for port
355: * return the port on which to listen for http connections (default = 6060)
356: */
357: public int getPort() {
358: return port;
359: }
360:
361: /**
362: * Setter for port
363: */
364: public void setPort(int port) {
365: this .port = port;
366: }
367:
368: /**
369: * Getter for hostAddress
370: *
371: * @return the host address (or name) to be use in reply-to endpoint references, or null if not specified (default = null)
372: */
373: public String getHostAddress() {
374: return hostAddress;
375: }
376:
377: /**
378: * Setter for hostAddress
379: */
380: public void setHostAddress(String hostAddress) {
381: this .hostAddress = hostAddress;
382: }
383:
384: /**
385: * Getter for originServer
386: *
387: * @return the Server header string for outgoing messages (default "Simple-Server/1.1")
388: */
389: public String getOriginServer() {
390: return originServer;
391: }
392:
393: /**
394: * Setter for originServer
395: */
396: public void setOriginServer(String originServer) {
397: this .originServer = originServer;
398: }
399:
400: /**
401: * Getter for requestSocketTimeout
402: *
403: * @return the maximum time in millis to wait for data on a request socket (default 20000)
404: */
405: public int getRequestSocketTimeout() {
406: return requestSocketTimeout;
407: }
408:
409: /**
410: * Setter for requestSocketTimeout
411: */
412: public void setRequestSocketTimeout(int requestSocketTimeout) {
413: this .requestSocketTimeout = requestSocketTimeout;
414: }
415:
416: /**
417: * Getter for requestTcpNoDelay
418: * return false iff Nagle's algorithm should be used to conserve bandwidth by minimizing segments
419: * at the cost of latency and performance (default true, i.e. maximize performance at
420: * the cost of bandwidth)
421: */
422: public boolean getRequestTcpNoDelay() {
423: return requestTcpNoDelay;
424: }
425:
426: /**
427: * Setter for requestTcpNoDelay
428: */
429: public void setRequestTcpNoDelay(boolean requestTcpNoDelay) {
430: this .requestTcpNoDelay = requestTcpNoDelay;
431: }
432:
433: /**
434: * Getter for RequestCoreThreadPoolSize
435: *
436: * @return the size of the thread pool use to process requests assuming there is adequate queue space (default 25)
437: */
438: public int getRequestCoreThreadPoolSize() {
439: return requestCoreThreadPoolSize;
440: }
441:
442: /**
443: * Setter for RequestCoreThreadPoolSize
444: */
445: public void setRequestCoreThreadPoolSize(
446: int requestCoreThreadPoolSize) {
447: this .requestCoreThreadPoolSize = requestCoreThreadPoolSize;
448: }
449:
450: /**
451: * Getter for requestMaxThreadPoolSize
452: *
453: * @return the maximum size of the thread pool used to process requests if the queue fills up (default 150).
454: * Since the default queue is unbounded this parameter is meaningless unless you override newRequestBlockingQueue()
455: */
456: public int getRequestMaxThreadPoolSize() {
457: return requestMaxThreadPoolSize;
458: }
459:
460: /**
461: * Setter for requestMaxThreadPoolSize
462: */
463: public void setRequestMaxThreadPoolSize(int requestMaxThreadPoolSize) {
464: this .requestMaxThreadPoolSize = requestMaxThreadPoolSize;
465: }
466:
467: /**
468: * Getter for threadKeepAliveTime
469: *
470: * @return how long a request processing thread in excess of the core pool size will be kept alive it if is inactive
471: * (default with threadKeepAliveTimeUnit to 180 seconds)
472: */
473: public long getThreadKeepAliveTime() {
474: return threadKeepAliveTime;
475: }
476:
477: /**
478: * Setter for threadKeepAliveTime
479: */
480: public void setThreadKeepAliveTime(long threadKeepAliveTime) {
481: this .threadKeepAliveTime = threadKeepAliveTime;
482: }
483:
484: /**
485: * Getter for threadKeepAliveTimeUnit
486: * return the time unit for threadKeepAliveTime (default SECONDS)
487: */
488: public TimeUnit getThreadKeepAliveTimeUnit() {
489: return threadKeepAliveTimeUnit;
490: }
491:
492: /**
493: * Setter for threadKeepAliveTimeUnit
494: */
495: public void setThreadKeepAliveTimeUnit(
496: TimeUnit threadKeepAliveTimeUnit) {
497: this.threadKeepAliveTimeUnit = threadKeepAliveTimeUnit;
498: }
499:
500: }
|