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: package org.apache.axis2.transport.nhttp;
020:
021: import java.io.IOException;
022: import java.io.InterruptedIOException;
023: import java.net.InetSocketAddress;
024: import java.net.UnknownHostException;
025:
026: import javax.net.ssl.SSLContext;
027:
028: import org.apache.axis2.AxisFault;
029: import org.apache.axis2.addressing.EndpointReference;
030: import org.apache.axis2.context.ConfigurationContext;
031: import org.apache.axis2.context.SessionContext;
032: import org.apache.axis2.context.MessageContext;
033: import org.apache.axis2.description.Parameter;
034: import org.apache.axis2.description.TransportInDescription;
035: import org.apache.axis2.transport.TransportListener;
036: import org.apache.commons.logging.Log;
037: import org.apache.commons.logging.LogFactory;
038: import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor;
039: import org.apache.http.impl.nio.reactor.SSLIOSessionHandler;
040: import org.apache.http.nio.NHttpServiceHandler;
041: import org.apache.http.nio.reactor.IOEventDispatch;
042: import org.apache.http.nio.reactor.ListeningIOReactor;
043: import org.apache.http.params.BasicHttpParams;
044: import org.apache.http.params.HttpConnectionParams;
045: import org.apache.http.params.HttpParams;
046: import org.apache.http.params.HttpProtocolParams;
047:
048: /**
049: * NIO transport listener for Axis2 based on HttpCore and NIO extensions
050: */
051: public class HttpCoreNIOListener implements TransportListener {
052:
053: private static final Log log = LogFactory
054: .getLog(HttpCoreNIOListener.class);
055:
056: /** The Axis2 configuration context */
057: private ConfigurationContext cfgCtx;
058: /** The IOReactor */
059: private ListeningIOReactor ioReactor = null;
060:
061: /** The EPR prefix for services available over this transport */
062: private String serviceEPRPrefix;
063: /** The port to listen on, defaults to 8080 */
064: private int port = 8080;
065: /** The hostname to use, defaults to localhost */
066: private String host = "localhost";
067: /** SSLContext if this listener is a SSL listener */
068: private SSLContext sslContext = null;
069: /** The SSL session handler that manages client authentication etc */
070: private SSLIOSessionHandler sslIOSessionHandler = null;
071:
072: /**
073: * configure and start the IO reactor on the specified port
074: * @param port port to start the listener on
075: */
076: private void startServerEngine(int port) {
077: HttpParams params = getServerParameters();
078: try {
079: ioReactor = new DefaultListeningIOReactor(
080: NHttpConfiguration.getInstance()
081: .getServerIOWorkers(), params);
082: } catch (IOException e) {
083: log.error("Error starting the IOReactor", e);
084: }
085:
086: NHttpServiceHandler handler = new ServerHandler(cfgCtx, params,
087: sslContext != null);
088: IOEventDispatch ioEventDispatch = getEventDispatch(handler,
089: sslContext, sslIOSessionHandler, params);
090:
091: try {
092: ioReactor.listen(new InetSocketAddress(port));
093: ioReactor.execute(ioEventDispatch);
094: } catch (InterruptedIOException ex) {
095: log.fatal("Reactor Interrupted");
096: } catch (IOException e) {
097: log.fatal("Encountered an I/O error: " + e.getMessage(), e);
098: }
099: log.info("Listener Shutdown");
100: }
101:
102: protected IOEventDispatch getEventDispatch(
103: NHttpServiceHandler handler, SSLContext sslContext,
104: SSLIOSessionHandler sslioSessionHandler, HttpParams params) {
105: return new PlainServerIOEventDispatch(handler, params);
106: }
107:
108: /**
109: * get HTTP protocol parameters to which the listener must adhere to
110: * @return the applicable HTTP protocol parameters
111: */
112: private HttpParams getServerParameters() {
113: HttpParams params = new BasicHttpParams();
114: NHttpConfiguration cfg = NHttpConfiguration.getInstance();
115: params
116: .setIntParameter(
117: HttpConnectionParams.SO_TIMEOUT,
118: cfg.getProperty(
119: HttpConnectionParams.SO_TIMEOUT, 60000))
120: .setIntParameter(
121: HttpConnectionParams.SOCKET_BUFFER_SIZE,
122: cfg
123: .getProperty(
124: HttpConnectionParams.SOCKET_BUFFER_SIZE,
125: 8 * 1024))
126: .setBooleanParameter(
127: HttpConnectionParams.STALE_CONNECTION_CHECK,
128: cfg
129: .getProperty(
130: HttpConnectionParams.STALE_CONNECTION_CHECK,
131: 0) == 1)
132: .setBooleanParameter(
133: HttpConnectionParams.TCP_NODELAY,
134: cfg.getProperty(
135: HttpConnectionParams.TCP_NODELAY, 1) == 1)
136: .setParameter(HttpProtocolParams.ORIGIN_SERVER,
137: "Axis2-HttpComponents-NIO");
138: return params;
139: }
140:
141: /**
142: * Initialize the transport listener, and execute reactor in new seperate thread
143: * @param cfgCtx the Axis2 configuration context
144: * @param transprtIn the description of the http/s transport from Axis2 configuration
145: * @throws AxisFault on error
146: */
147: public void init(ConfigurationContext cfgCtx,
148: TransportInDescription transprtIn) throws AxisFault {
149:
150: this .cfgCtx = cfgCtx;
151: Parameter param = transprtIn.getParameter(PARAM_PORT);
152: if (param != null) {
153: port = Integer.parseInt((String) param.getValue());
154: }
155:
156: param = transprtIn.getParameter(HOST_ADDRESS);
157: if (param != null) {
158: host = ((String) param.getValue()).trim();
159: } else {
160: try {
161: host = java.net.InetAddress.getLocalHost()
162: .getHostName();
163: } catch (UnknownHostException e) {
164: log
165: .warn("Unable to lookup local host name, using 'localhost'");
166: }
167: }
168:
169: // is this an SSL listener?
170: sslContext = getSSLContext(transprtIn);
171: //sslIOSessionHandler = getSSLIOSessionHandler(transprtIn);
172:
173: serviceEPRPrefix = getServiceEPRPrefix(cfgCtx, host, port);
174: }
175:
176: /**
177: * Return the EPR prefix for services made available over this transport
178: * @return
179: */
180: protected String getServiceEPRPrefix(ConfigurationContext cfgCtx,
181: String host, int port) {
182: return "http://"
183: + host
184: + (port == 80 ? "" : ":" + port)
185: + (!cfgCtx.getServiceContextPath().startsWith("/") ? "/"
186: : "")
187: + cfgCtx.getServiceContextPath()
188: + (!cfgCtx.getServiceContextPath().endsWith("/") ? "/"
189: : "");
190: }
191:
192: /**
193: * Create the SSLContext to be used by this listener
194: * @param transportIn
195: * @return always null
196: */
197: protected SSLContext getSSLContext(
198: TransportInDescription transportIn) throws AxisFault {
199: return null;
200: }
201:
202: /**
203: * Create the SSL IO Session handler to be used by this listener
204: * @param transportIn
205: * @return always null
206: */
207: // protected SSLIOSessionHandler getSSLIOSessionHandler(TransportInDescription transportIn)
208: // throws AxisFault {
209: // return null;
210: // }
211: /**
212: * Start the transport listener on a new thread
213: * @throws AxisFault
214: */
215: public void start() throws AxisFault {
216: log.debug("Starting Listener...");
217: // start the Listener in a new seperate thread
218: Thread t = new Thread(new Runnable() {
219: public void run() {
220: try {
221: startServerEngine(port);
222: } catch (Exception e) {
223: e.printStackTrace();
224: }
225: }
226: }, "HttpCoreNIOListener");
227:
228: t.start();
229: log.info((sslContext == null ? "HTTP" : "HTTPS")
230: + " Listener starting on port : " + port);
231: }
232:
233: /**
234: * Stop the listener
235: * @throws AxisFault on error
236: */
237: public void stop() throws AxisFault {
238: try {
239: ioReactor.shutdown();
240: log.info("Listener shut down");
241: } catch (IOException e) {
242: handleException("Error shutting down IOReactor", e);
243: }
244: }
245:
246: /**
247: * Return the EPR for the given service (implements deprecated method temporarily)
248: */
249: public EndpointReference getEPRForService(String serviceName,
250: String ip) throws AxisFault {
251: return new EndpointReference(serviceEPRPrefix + serviceName);
252: }
253:
254: /**
255: * Return the EPRs for the given service over this transport
256: * @param serviceName name of the service
257: * @param ip IP address
258: * @return the EndpointReferences for this service over the transport
259: * @throws AxisFault on error
260: */
261: public EndpointReference[] getEPRsForService(String serviceName,
262: String ip) throws AxisFault {
263: EndpointReference[] endpointReferences = new EndpointReference[1];
264: endpointReferences[0] = new EndpointReference(serviceEPRPrefix
265: + serviceName);
266: return endpointReferences;
267: }
268:
269: /**
270: * TODO: Return session context from transport, this is an improvement in axis2 1.2 and
271: * is not currently supported
272: * @param messageContext
273: * @return
274: */
275: public SessionContext getSessionContext(
276: MessageContext messageContext) {
277: return null;
278: }
279:
280: public void destroy() {
281: ioReactor = null;
282: }
283:
284: // -------------- utility methods -------------
285: private void handleException(String msg, Exception e)
286: throws AxisFault {
287: log.error(msg, e);
288: throw new AxisFault(msg, e);
289: }
290:
291: }
|