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/NHttpConnectionBase.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: import java.net.InetAddress;
036: import java.net.InetSocketAddress;
037: import java.net.SocketAddress;
038:
039: import org.apache.http.ConnectionClosedException;
040: import org.apache.http.Header;
041: import org.apache.http.HttpConnectionMetrics;
042: import org.apache.http.HttpEntity;
043: import org.apache.http.HttpException;
044: import org.apache.http.HttpInetConnection;
045: import org.apache.http.HttpMessage;
046: import org.apache.http.HttpRequest;
047: import org.apache.http.HttpResponse;
048: import org.apache.http.entity.BasicHttpEntity;
049: import org.apache.http.entity.ContentLengthStrategy;
050: import org.apache.http.impl.HttpConnectionMetricsImpl;
051: import org.apache.http.impl.entity.LaxContentLengthStrategy;
052: import org.apache.http.impl.entity.StrictContentLengthStrategy;
053: import org.apache.http.impl.io.HttpTransportMetricsImpl;
054: import org.apache.http.nio.ContentDecoder;
055: import org.apache.http.nio.ContentEncoder;
056: import org.apache.http.nio.NHttpConnection;
057: import org.apache.http.impl.nio.codecs.ChunkDecoder;
058: import org.apache.http.impl.nio.codecs.ChunkEncoder;
059: import org.apache.http.impl.nio.codecs.IdentityDecoder;
060: import org.apache.http.impl.nio.codecs.IdentityEncoder;
061: import org.apache.http.impl.nio.codecs.LengthDelimitedDecoder;
062: import org.apache.http.impl.nio.codecs.LengthDelimitedEncoder;
063: import org.apache.http.impl.nio.reactor.SessionInputBufferImpl;
064: import org.apache.http.impl.nio.reactor.SessionOutputBufferImpl;
065: import org.apache.http.nio.reactor.EventMask;
066: import org.apache.http.nio.reactor.IOSession;
067: import org.apache.http.nio.reactor.SessionBufferStatus;
068: import org.apache.http.nio.util.ByteBufferAllocator;
069: import org.apache.http.params.HttpConnectionParams;
070: import org.apache.http.params.HttpParams;
071: import org.apache.http.protocol.HTTP;
072: import org.apache.http.protocol.HttpContext;
073: import org.apache.http.protocol.SyncBasicHttpContext;
074:
075: public class NHttpConnectionBase implements NHttpConnection,
076: HttpInetConnection, SessionBufferStatus {
077:
078: protected final IOSession session;
079: protected final HttpContext context;
080:
081: protected final ContentLengthStrategy incomingContentStrategy;
082: protected final ContentLengthStrategy outgoingContentStrategy;
083:
084: protected final SessionInputBufferImpl inbuf;
085: protected final SessionOutputBufferImpl outbuf;
086:
087: protected final HttpTransportMetricsImpl inTransportMetrics;
088: protected final HttpTransportMetricsImpl outTransportMetrics;
089: protected final HttpConnectionMetricsImpl connMetrics;
090:
091: protected volatile ContentDecoder contentDecoder;
092: protected volatile boolean hasBufferedInput;
093: protected volatile ContentEncoder contentEncoder;
094: protected volatile boolean hasBufferedOutput;
095: protected volatile HttpRequest request;
096: protected volatile HttpResponse response;
097:
098: protected volatile int status;
099:
100: public NHttpConnectionBase(final IOSession session,
101: final ByteBufferAllocator allocator, final HttpParams params) {
102: super ();
103: if (session == null) {
104: throw new IllegalArgumentException(
105: "I/O session may not be null");
106: }
107: if (params == null) {
108: throw new IllegalArgumentException(
109: "HTTP params may not be null");
110: }
111: this .session = session;
112: this .context = new SyncBasicHttpContext(null);
113:
114: int buffersize = HttpConnectionParams
115: .getSocketBufferSize(params);
116: int linebuffersize = buffersize;
117: if (linebuffersize > 512) {
118: linebuffersize = 512;
119: }
120:
121: this .inbuf = new SessionInputBufferImpl(buffersize,
122: linebuffersize, allocator, params);
123: this .outbuf = new SessionOutputBufferImpl(buffersize,
124: linebuffersize, allocator, params);
125:
126: this .incomingContentStrategy = new LaxContentLengthStrategy();
127: this .outgoingContentStrategy = new StrictContentLengthStrategy();
128:
129: this .inTransportMetrics = new HttpTransportMetricsImpl();
130: this .outTransportMetrics = new HttpTransportMetricsImpl();
131: this .connMetrics = new HttpConnectionMetricsImpl(
132: this .inTransportMetrics, this .outTransportMetrics);
133:
134: this .session.setBufferStatus(this );
135: this .session.setEvent(EventMask.READ);
136: this .status = ACTIVE;
137: }
138:
139: public int getStatus() {
140: return this .status;
141: }
142:
143: public HttpContext getContext() {
144: return this .context;
145: }
146:
147: public HttpRequest getHttpRequest() {
148: return this .request;
149: }
150:
151: public HttpResponse getHttpResponse() {
152: return this .response;
153: }
154:
155: public void requestInput() {
156: this .session.setEvent(EventMask.READ);
157: }
158:
159: public void requestOutput() {
160: this .session.setEvent(EventMask.WRITE);
161: }
162:
163: public void suspendInput() {
164: this .session.clearEvent(EventMask.READ);
165: }
166:
167: public void suspendOutput() {
168: this .session.clearEvent(EventMask.WRITE);
169: }
170:
171: protected HttpEntity prepareDecoder(final HttpMessage message)
172: throws HttpException {
173: BasicHttpEntity entity = new BasicHttpEntity();
174: long len = this .incomingContentStrategy
175: .determineLength(message);
176: if (len == ContentLengthStrategy.CHUNKED) {
177: this .contentDecoder = new ChunkDecoder(this .session
178: .channel(), this .inbuf, this .inTransportMetrics);
179: entity.setChunked(true);
180: entity.setContentLength(-1);
181: } else if (len == ContentLengthStrategy.IDENTITY) {
182: this .contentDecoder = new IdentityDecoder(this .session
183: .channel(), this .inbuf, this .inTransportMetrics);
184: entity.setChunked(false);
185: entity.setContentLength(-1);
186: } else {
187: this .contentDecoder = new LengthDelimitedDecoder(
188: this .session.channel(), this .inbuf,
189: this .inTransportMetrics, len);
190: entity.setChunked(false);
191: entity.setContentLength(len);
192: }
193:
194: Header contentTypeHeader = message
195: .getFirstHeader(HTTP.CONTENT_TYPE);
196: if (contentTypeHeader != null) {
197: entity.setContentType(contentTypeHeader);
198: }
199: Header contentEncodingHeader = message
200: .getFirstHeader(HTTP.CONTENT_ENCODING);
201: if (contentEncodingHeader != null) {
202: entity.setContentEncoding(contentEncodingHeader);
203: }
204: return entity;
205: }
206:
207: protected void prepareEncoder(final HttpMessage message)
208: throws HttpException {
209: long len = this .outgoingContentStrategy
210: .determineLength(message);
211: if (len == ContentLengthStrategy.CHUNKED) {
212: this .contentEncoder = new ChunkEncoder(this .session
213: .channel(), this .outbuf, this .outTransportMetrics);
214: } else if (len == ContentLengthStrategy.IDENTITY) {
215: this .contentEncoder = new IdentityEncoder(this .session
216: .channel(), this .outbuf, this .outTransportMetrics);
217: } else {
218: this .contentEncoder = new LengthDelimitedEncoder(
219: this .session.channel(), this .outbuf,
220: this .outTransportMetrics, len);
221: }
222: }
223:
224: public boolean hasBufferedInput() {
225: return this .hasBufferedInput;
226: }
227:
228: public boolean hasBufferedOutput() {
229: return this .hasBufferedOutput;
230: }
231:
232: protected void assertNotClosed() throws IOException {
233: if (this .status != ACTIVE) {
234: throw new ConnectionClosedException("Connection is closed");
235: }
236: }
237:
238: public void close() throws IOException {
239: if (this .status != ACTIVE) {
240: return;
241: }
242: this .status = CLOSING;
243: if (this .outbuf.hasData()) {
244: this .session.setEvent(EventMask.WRITE);
245: } else {
246: this .session.close();
247: this .status = CLOSED;
248: }
249: }
250:
251: public boolean isOpen() {
252: return this .status == ACTIVE && !this .session.isClosed();
253: }
254:
255: public boolean isStale() {
256: return this .session.isClosed();
257: }
258:
259: public InetAddress getLocalAddress() {
260: SocketAddress address = this .session.getLocalAddress();
261: if (address instanceof InetSocketAddress) {
262: return ((InetSocketAddress) address).getAddress();
263: } else {
264: return null;
265: }
266: }
267:
268: public int getLocalPort() {
269: SocketAddress address = this .session.getLocalAddress();
270: if (address instanceof InetSocketAddress) {
271: return ((InetSocketAddress) address).getPort();
272: } else {
273: return -1;
274: }
275: }
276:
277: public InetAddress getRemoteAddress() {
278: SocketAddress address = this .session.getRemoteAddress();
279: if (address instanceof InetSocketAddress) {
280: return ((InetSocketAddress) address).getAddress();
281: } else {
282: return null;
283: }
284: }
285:
286: public int getRemotePort() {
287: SocketAddress address = this .session.getRemoteAddress();
288: if (address instanceof InetSocketAddress) {
289: return ((InetSocketAddress) address).getPort();
290: } else {
291: return -1;
292: }
293: }
294:
295: public void setSocketTimeout(int timeout) {
296: this .session.setSocketTimeout(timeout);
297: }
298:
299: public int getSocketTimeout() {
300: return this .session.getSocketTimeout();
301: }
302:
303: public void shutdown() throws IOException {
304: this .status = CLOSED;
305: this .session.shutdown();
306: }
307:
308: public HttpConnectionMetrics getMetrics() {
309: return this.connMetrics;
310: }
311:
312: }
|