001: /*
002: * Copyright (c) xsocket.org, 2006 - 2008. All rights reserved.
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: * Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
019: * The latest copy of this software may be found on http://www.xsocket.org/
020: */
021: package org.xsocket.connection.http.server;
022:
023: import java.io.IOException;
024: import java.util.logging.Level;
025: import java.util.logging.Logger;
026:
027: import org.xsocket.Execution;
028: import org.xsocket.ILifeCycle;
029: import org.xsocket.Resource;
030: import org.xsocket.connection.IConnectHandler;
031: import org.xsocket.connection.IConnectionScoped;
032: import org.xsocket.connection.IHandlerAdapter;
033: import org.xsocket.connection.INonBlockingConnection;
034: import org.xsocket.connection.IServer;
035: import org.xsocket.connection.http.IHttpConnectHandler;
036: import org.xsocket.connection.http.IHttpConnectionTimeoutHandler;
037: import org.xsocket.connection.http.IHttpDisconnectHandler;
038: import org.xsocket.connection.http.IHttpHandler;
039: import org.xsocket.connection.http.server.ServerUtils.HttpHandlerInfo;
040: import org.xsocket.connection.http.server.ServerUtils.RequestHandlerInfo;
041:
042: /**
043: * The http protocol adapter. The protocol adapter implements the {@link IConnectHandler} interface, and
044: * "maps" each incoming connection into a {@link HttpServerConnection}. <br>
045: * HttpProtcol adapter is required, if the {@link HttpServer} will not be used.
046: *
047: * Example:
048: * <pre>
049: *
050: * // establishing a http server based on a mutliplexed tcp connection
051: * // for multiplexex connections see http://xsocket.sourceforge.net/multiplexed/tutorial/V2/TutorialMultiplexed.htm
052: *
053: * IRequestHandler hdl = new MyRequestHandler();
054: * IConnectHandler httpAdapter = new HttpProtocolAdapter(hdl);
055: *
056: *
057: * IServer mutliplexedHttpServer = new Server(port, new MultiplexedProtocolAdapter(httpAdapter)));
058: * ConnectionUtils.start(mutliplexedHttpServer);
059: * ...
060: * </pre>
061: *
062: *
063: * @author grro
064: */
065: @Execution(Execution.NONTHREADED)
066: public final class HttpProtocolAdapter implements IConnectHandler,
067: ILifeCycle, IHandlerAdapter {
068:
069: private static final Logger LOG = Logger
070: .getLogger(HttpProtocolAdapter.class.getName());
071:
072: @Resource
073: private IServer server = null;
074:
075: private IHttpHandler handler = null;
076: private RequestHandlerInfo serverHandlerInfo = null;
077: private HttpHandlerInfo httpHandlerInfo = null;
078: private boolean isConnectionScoped = false;
079: private boolean isLifeCycle = false;
080:
081: private Integer requestTimeoutMillis = null;
082:
083: private boolean isCloseOnSendingError = false;
084:
085: // keep alive support
086: private Integer maxTransactions = null;
087:
088: /**
089: * constructor
090: *
091: * @param handler the handler (supported: {@link IHttpRequestHandler}, {@link IHttpConnectHandler}, {@link IHttpDisconnectHandler}, {@link IHttpConnectionTimeoutHandler}, {@link ILifeCycle})
092: */
093: public HttpProtocolAdapter(IHttpHandler handler) {
094: this .handler = handler;
095: this .serverHandlerInfo = ServerUtils
096: .getServerHandlerInfo(handler);
097: this .httpHandlerInfo = ServerUtils.getHttpHandlerInfo(handler);
098: this .isConnectionScoped = (handler instanceof IConnectionScoped);
099: this .isLifeCycle = (handler instanceof ILifeCycle);
100: }
101:
102: /**
103: * sets the message receive timeout
104: *
105: * @param receivetimeout the message receive timeout
106: */
107: public void setRequestTimeoutMillis(int receivetimeout) {
108: this .requestTimeoutMillis = receivetimeout;
109: }
110:
111: /**
112: * returns the message receive timeout
113: *
114: * @return the message receive timeout
115: */
116: public int getRequestTimeoutMillis() {
117: return requestTimeoutMillis;
118: }
119:
120: /**
121: * set is if the server-side connection will closed, if an error message is sent
122: *
123: * @param isCloseOnSendingError if the connection will closed, if an error message is sent
124: */
125: public void setCloseOnSendingError(boolean isCloseOnSendingError) {
126: this .isCloseOnSendingError = isCloseOnSendingError;
127: }
128:
129: /**
130: * returns if the server-side connection will closed, if an error message will be sent
131: * @return true, if the connection will closed by sending an error message
132: */
133: public boolean isCloseOnSendingError() {
134: return isCloseOnSendingError;
135: }
136:
137: /**
138: * set the max transactions per connection. Setting this filed causes that
139: * a keep-alive response header will be added
140: *
141: * @param maxTransactions the max transactions
142: */
143: public void setMaxTransactions(int maxTransactions) {
144: this .maxTransactions = maxTransactions;
145: }
146:
147: /**
148: * {@inheritDoc}
149: */
150: public Object getAdaptee() {
151: return handler;
152: }
153:
154: /**
155: * {@inheritDoc}
156: */
157: public void onInit() {
158: server.setStartUpLogMessage(server.getStartUpLogMessage()
159: + "; http " + ServerUtils.getVersionInfo());
160:
161: ServerUtils.injectServerField(handler, server);
162: ServerUtils.injectProtocolAdapter(handler, this );
163:
164: if (isLifeCycle) {
165: ((ILifeCycle) handler).onInit();
166: }
167: }
168:
169: /**
170: * {@inheritDoc}
171: */
172: public void onDestroy() {
173: if (isLifeCycle) {
174: try {
175: ((ILifeCycle) handler).onDestroy();
176: } catch (IOException ioe) {
177: if (LOG.isLoggable(Level.FINE)) {
178: LOG.fine("exception occured by destroying "
179: + handler + " " + ioe.toString());
180: }
181: }
182: }
183: }
184:
185: /**
186: * {@inheritDoc}
187: */
188: public boolean onConnect(INonBlockingConnection connection)
189: throws IOException {
190:
191: HttpServerConnection httpCon = null;
192:
193: if (isConnectionScoped) {
194: try {
195: IHttpRequestHandler handlerCopy = (IHttpRequestHandler) ((IConnectionScoped) handler)
196: .clone();
197: httpCon = new HttpServerConnection(connection,
198: serverHandlerInfo, httpHandlerInfo,
199: handlerCopy, isCloseOnSendingError);
200: } catch (CloneNotSupportedException clne) {
201: throw new RuntimeException("couldn't clone handler "
202: + handler + " " + clne.toString());
203: }
204:
205: } else {
206: httpCon = new HttpServerConnection(connection,
207: serverHandlerInfo, httpHandlerInfo, handler,
208: isCloseOnSendingError);
209: }
210:
211: if (maxTransactions != null) {
212: httpCon.setMaxTransactions(maxTransactions);
213: }
214:
215: if (requestTimeoutMillis != null) {
216: httpCon.setRequestTimeoutMillis(requestTimeoutMillis);
217: }
218:
219: return true;
220: }
221: }
|