001: /*
002: * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/httpcore/tags/4.0-beta1/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java $
003: * $Revision: 613298 $
004: * $Date: 2008-01-18 23:09:22 +0100 (Fri, 18 Jan 2008) $
005: *
006: * ====================================================================
007: * Licensed to the Apache Software Foundation (ASF) under one
008: * or more contributor license agreements. See the NOTICE file
009: * distributed with this work for additional information
010: * regarding copyright ownership. The ASF licenses this file
011: * to you under the Apache License, Version 2.0 (the
012: * "License"); you may not use this file except in compliance
013: * with the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing,
018: * software distributed under the License is distributed on an
019: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
020: * KIND, either express or implied. See the License for the
021: * specific language governing permissions and limitations
022: * under the License.
023: * ====================================================================
024: *
025: * This software consists of voluntary contributions made by many
026: * individuals on behalf of the Apache Software Foundation. For more
027: * information on the Apache Software Foundation, please see
028: * <http://www.apache.org/>.
029: *
030: */
031:
032: package org.apache.http.impl.nio;
033:
034: import java.io.IOException;
035:
036: import org.apache.http.HttpEntity;
037: import org.apache.http.HttpEntityEnclosingRequest;
038: import org.apache.http.HttpException;
039: import org.apache.http.HttpRequest;
040: import org.apache.http.HttpRequestFactory;
041: import org.apache.http.HttpResponse;
042: import org.apache.http.impl.nio.codecs.HttpRequestParser;
043: import org.apache.http.impl.nio.codecs.HttpResponseWriter;
044: import org.apache.http.nio.NHttpMessageParser;
045: import org.apache.http.nio.NHttpMessageWriter;
046: import org.apache.http.nio.NHttpServerIOTarget;
047: import org.apache.http.nio.NHttpServiceHandler;
048: import org.apache.http.nio.reactor.EventMask;
049: import org.apache.http.nio.reactor.IOSession;
050: import org.apache.http.nio.reactor.SessionInputBuffer;
051: import org.apache.http.nio.reactor.SessionOutputBuffer;
052: import org.apache.http.nio.util.ByteBufferAllocator;
053: import org.apache.http.params.HttpParams;
054:
055: public class DefaultNHttpServerConnection extends NHttpConnectionBase
056: implements NHttpServerIOTarget {
057:
058: private final NHttpMessageParser requestParser;
059: private final NHttpMessageWriter responseWriter;
060:
061: public DefaultNHttpServerConnection(final IOSession session,
062: final HttpRequestFactory requestFactory,
063: final ByteBufferAllocator allocator, final HttpParams params) {
064: super (session, allocator, params);
065: if (requestFactory == null) {
066: throw new IllegalArgumentException(
067: "Request factory may not be null");
068: }
069: this .requestParser = createRequestParser(this .inbuf,
070: requestFactory, params);
071: this .responseWriter = createResponseWriter(this .outbuf, params);
072: }
073:
074: protected NHttpMessageParser createRequestParser(
075: final SessionInputBuffer buffer,
076: final HttpRequestFactory requestFactory,
077: final HttpParams params) {
078: // override in derived class to specify a line parser
079: return new HttpRequestParser(buffer, null, requestFactory,
080: params);
081: }
082:
083: protected NHttpMessageWriter createResponseWriter(
084: final SessionOutputBuffer buffer, final HttpParams params) {
085: // override in derived class to specify a line formatter
086: return new HttpResponseWriter(buffer, null, params);
087: }
088:
089: public void resetInput() {
090: this .request = null;
091: this .contentDecoder = null;
092: this .requestParser.reset();
093: }
094:
095: public void resetOutput() {
096: this .response = null;
097: this .contentEncoder = null;
098: this .responseWriter.reset();
099: }
100:
101: public void consumeInput(final NHttpServiceHandler handler) {
102: if (this .status != ACTIVE) {
103: this .session.clearEvent(EventMask.READ);
104: return;
105: }
106: try {
107: if (this .request == null) {
108: int bytesRead;
109: do {
110: bytesRead = this .requestParser
111: .fillBuffer(this .session.channel());
112: if (bytesRead > 0) {
113: this .inTransportMetrics
114: .incrementBytesTransferred(bytesRead);
115: }
116: this .request = (HttpRequest) this .requestParser
117: .parse();
118: } while (bytesRead > 0 && this .request == null);
119: if (this .request != null) {
120: if (this .request instanceof HttpEntityEnclosingRequest) {
121: // Receive incoming entity
122: HttpEntity entity = prepareDecoder(this .request);
123: ((HttpEntityEnclosingRequest) this .request)
124: .setEntity(entity);
125: }
126: this .connMetrics.incrementRequestCount();
127: handler.requestReceived(this );
128: if (this .contentDecoder == null) {
129: // No request entity is expected
130: // Ready to receive a new request
131: resetInput();
132: }
133: }
134: if (bytesRead == -1) {
135: close();
136: }
137: }
138: if (this .contentDecoder != null) {
139: handler.inputReady(this , this .contentDecoder);
140: if (this .contentDecoder.isCompleted()) {
141: // Request entity received
142: // Ready to receive a new request
143: resetInput();
144: }
145: }
146: } catch (IOException ex) {
147: handler.exception(this , ex);
148: } catch (HttpException ex) {
149: resetInput();
150: handler.exception(this , ex);
151: } finally {
152: // Finally set buffered input flag
153: this .hasBufferedInput = this .inbuf.hasData();
154: }
155: }
156:
157: public void produceOutput(final NHttpServiceHandler handler) {
158: try {
159: if (this .outbuf.hasData()) {
160: int bytesWritten = this .outbuf.flush(this .session
161: .channel());
162: if (bytesWritten > 0) {
163: this .outTransportMetrics
164: .incrementBytesTransferred(bytesWritten);
165: }
166: }
167: if (!this .outbuf.hasData()) {
168: if (this .status == CLOSING) {
169: this .session.close();
170: this .status = CLOSED;
171: resetOutput();
172: return;
173: } else {
174: if (this .contentEncoder != null) {
175: handler.outputReady(this , this .contentEncoder);
176: if (this .contentEncoder.isCompleted()) {
177: resetOutput();
178: }
179: }
180: }
181:
182: if (this .contentEncoder == null
183: && !this .outbuf.hasData()) {
184: if (this .status == CLOSING) {
185: this .session.close();
186: this .status = CLOSED;
187: return;
188: }
189:
190: this .session.clearEvent(EventMask.WRITE);
191:
192: handler.responseReady(this );
193: }
194: }
195: } catch (IOException ex) {
196: handler.exception(this , ex);
197: } finally {
198: // Finally set the buffered output flag
199: this .hasBufferedOutput = this .outbuf.hasData();
200: }
201: }
202:
203: public void submitResponse(final HttpResponse response)
204: throws IOException, HttpException {
205: if (response == null) {
206: throw new IllegalArgumentException(
207: "HTTP response may not be null");
208: }
209: assertNotClosed();
210: if (this .response != null) {
211: throw new HttpException("Response already submitted");
212: }
213: this .responseWriter.write(response);
214: this .hasBufferedOutput = this .outbuf.hasData();
215:
216: if (response.getStatusLine().getStatusCode() >= 200) {
217: this .connMetrics.incrementRequestCount();
218: if (response.getEntity() != null) {
219: this .response = response;
220: prepareEncoder(response);
221: }
222: }
223:
224: this .session.setEvent(EventMask.WRITE);
225: }
226:
227: public boolean isResponseSubmitted() {
228: return this .response != null;
229: }
230:
231: @Override
232: public String toString() {
233: StringBuffer buffer = new StringBuffer();
234: buffer.append("[");
235: if (isOpen()) {
236: buffer.append(this .session.getRemoteAddress());
237: } else {
238: buffer.append("closed");
239: }
240: buffer.append("]");
241: return buffer.toString();
242: }
243:
244: }
|