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/DefaultNHttpClientConnection.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.HttpResponse;
041: import org.apache.http.HttpResponseFactory;
042: import org.apache.http.impl.nio.codecs.HttpRequestWriter;
043: import org.apache.http.impl.nio.codecs.HttpResponseParser;
044: import org.apache.http.nio.NHttpClientIOTarget;
045: import org.apache.http.nio.NHttpClientHandler;
046: import org.apache.http.nio.NHttpMessageParser;
047: import org.apache.http.nio.NHttpMessageWriter;
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 DefaultNHttpClientConnection extends NHttpConnectionBase
056: implements NHttpClientIOTarget {
057:
058: private final NHttpMessageParser responseParser;
059: private final NHttpMessageWriter requestWriter;
060:
061: public DefaultNHttpClientConnection(final IOSession session,
062: final HttpResponseFactory responseFactory,
063: final ByteBufferAllocator allocator, final HttpParams params) {
064: super (session, allocator, params);
065: if (responseFactory == null) {
066: throw new IllegalArgumentException(
067: "Response factory may not be null");
068: }
069: this .responseParser = createResponseParser(this .inbuf,
070: responseFactory, params);
071: this .requestWriter = createRequestWriter(this .outbuf, params);
072: this .hasBufferedInput = false;
073: this .hasBufferedOutput = false;
074: this .session.setBufferStatus(this );
075: }
076:
077: protected NHttpMessageParser createResponseParser(
078: final SessionInputBuffer buffer,
079: final HttpResponseFactory responseFactory,
080: final HttpParams params) {
081: // override in derived class to specify a line parser
082: return new HttpResponseParser(buffer, null, responseFactory,
083: params);
084: }
085:
086: protected NHttpMessageWriter createRequestWriter(
087: final SessionOutputBuffer buffer, final HttpParams params) {
088: // override in derived class to specify a line formatter
089: return new HttpRequestWriter(buffer, null, params);
090: }
091:
092: public void resetInput() {
093: this .response = null;
094: this .contentDecoder = null;
095: this .responseParser.reset();
096: }
097:
098: public void resetOutput() {
099: this .request = null;
100: this .contentEncoder = null;
101: this .requestWriter.reset();
102: }
103:
104: public void consumeInput(final NHttpClientHandler handler) {
105: if (this .status != ACTIVE) {
106: this .session.clearEvent(EventMask.READ);
107: return;
108: }
109: try {
110: if (this .response == null) {
111: int bytesRead;
112: do {
113: bytesRead = this .responseParser
114: .fillBuffer(this .session.channel());
115: if (bytesRead > 0) {
116: this .inTransportMetrics
117: .incrementBytesTransferred(bytesRead);
118: }
119: this .response = (HttpResponse) this .responseParser
120: .parse();
121: } while (bytesRead > 0 && this .response == null);
122: if (this .response != null) {
123: if (this .response.getStatusLine().getStatusCode() >= 200) {
124: HttpEntity entity = prepareDecoder(this .response);
125: this .response.setEntity(entity);
126: this .connMetrics.incrementRequestCount();
127: }
128: handler.responseReceived(this );
129: if (this .contentDecoder == null) {
130: resetInput();
131: }
132: }
133: if (bytesRead == -1) {
134: close();
135: }
136: }
137: if (this .contentDecoder != null) {
138: handler.inputReady(this , this .contentDecoder);
139: if (this .contentDecoder.isCompleted()) {
140: // Response entity received
141: // Ready to receive a new response
142: resetInput();
143: }
144: }
145: } catch (IOException ex) {
146: handler.exception(this , ex);
147: } catch (HttpException ex) {
148: resetInput();
149: handler.exception(this , ex);
150: } finally {
151: // Finally set buffered input flag
152: this .hasBufferedInput = this .inbuf.hasData();
153: }
154: }
155:
156: public void produceOutput(final NHttpClientHandler handler) {
157:
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.requestReady(this );
193: }
194: }
195: } catch (IOException ex) {
196: handler.exception(this , ex);
197: } finally {
198: // Finally set buffered output flag
199: this .hasBufferedOutput = this .outbuf.hasData();
200: }
201: }
202:
203: public void submitRequest(final HttpRequest request)
204: throws IOException, HttpException {
205: if (request == null) {
206: throw new IllegalArgumentException(
207: "HTTP request may not be null");
208: }
209: assertNotClosed();
210: if (this .request != null) {
211: throw new HttpException("Request already submitted");
212: }
213: this .requestWriter.write(request);
214: this .hasBufferedOutput = this .outbuf.hasData();
215:
216: if (request instanceof HttpEntityEnclosingRequest) {
217: prepareEncoder(request);
218: this .request = request;
219: }
220: this .connMetrics.incrementRequestCount();
221: this .session.setEvent(EventMask.WRITE);
222: }
223:
224: public boolean isRequestSubmitted() {
225: return this .request != null;
226: }
227:
228: @Override
229: public String toString() {
230: StringBuffer buffer = new StringBuffer();
231: buffer.append("[");
232: if (isOpen()) {
233: buffer.append(this .session.getRemoteAddress());
234: } else {
235: buffer.append("closed");
236: }
237: buffer.append("]");
238: return buffer.toString();
239: }
240:
241: }
|