AbstractHttpClientConnection.java revision 091f7ca4958c6f41c79808913c84ceea56d73b12
1/*
2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/AbstractHttpClientConnection.java $
3 * $Revision: 627457 $
4 * $Date: 2008-02-13 07:14:19 -0800 (Wed, 13 Feb 2008) $
5 *
6 * ====================================================================
7 * Licensed to the Apache Software Foundation (ASF) under one
8 * or more contributor license agreements.  See the NOTICE file
9 * distributed with this work for additional information
10 * regarding copyright ownership.  The ASF licenses this file
11 * to you under the Apache License, Version 2.0 (the
12 * "License"); you may not use this file except in compliance
13 * with the License.  You may obtain a copy of the License at
14 *
15 *   http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing,
18 * software distributed under the License is distributed on an
19 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 * KIND, either express or implied.  See the License for the
21 * specific language governing permissions and limitations
22 * under the License.
23 * ====================================================================
24 *
25 * This software consists of voluntary contributions made by many
26 * individuals on behalf of the Apache Software Foundation.  For more
27 * information on the Apache Software Foundation, please see
28 * <http://www.apache.org/>.
29 *
30 */
31
32package org.apache.http.impl;
33
34import java.io.IOException;
35
36import org.apache.http.HttpClientConnection;
37import org.apache.http.HttpConnectionMetrics;
38import org.apache.http.HttpEntity;
39import org.apache.http.HttpEntityEnclosingRequest;
40import org.apache.http.HttpException;
41import org.apache.http.HttpRequest;
42import org.apache.http.HttpResponse;
43import org.apache.http.HttpResponseFactory;
44import org.apache.http.impl.entity.EntityDeserializer;
45import org.apache.http.impl.entity.EntitySerializer;
46import org.apache.http.impl.entity.LaxContentLengthStrategy;
47import org.apache.http.impl.entity.StrictContentLengthStrategy;
48import org.apache.http.impl.io.HttpRequestWriter;
49import org.apache.http.impl.io.HttpResponseParser;
50import org.apache.http.impl.io.SocketInputBuffer;
51import org.apache.http.io.HttpMessageParser;
52import org.apache.http.io.HttpMessageWriter;
53import org.apache.http.io.SessionInputBuffer;
54import org.apache.http.io.SessionOutputBuffer;
55import org.apache.http.params.HttpParams;
56
57/**
58 * Abstract client-side HTTP connection capable of transmitting and receiving data
59 * using arbitrary {@link SessionInputBuffer} and {@link SessionOutputBuffer}
60 *
61 * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
62 *
63 * @version $Revision: 627457 $
64 *
65 * @since 4.0
66 */
67public abstract class AbstractHttpClientConnection implements HttpClientConnection {
68
69    private final EntitySerializer entityserializer;
70    private final EntityDeserializer entitydeserializer;
71
72    private SessionInputBuffer inbuffer = null;
73    private SessionOutputBuffer outbuffer = null;
74    private HttpMessageParser responseParser = null;
75    private HttpMessageWriter requestWriter = null;
76    private HttpConnectionMetricsImpl metrics = null;
77
78
79
80    public AbstractHttpClientConnection() {
81        super();
82        this.entityserializer = createEntitySerializer();
83        this.entitydeserializer = createEntityDeserializer();
84    }
85
86    protected abstract void assertOpen() throws IllegalStateException;
87
88    protected EntityDeserializer createEntityDeserializer() {
89        return new EntityDeserializer(new LaxContentLengthStrategy());
90    }
91
92    protected EntitySerializer createEntitySerializer() {
93        return new EntitySerializer(new StrictContentLengthStrategy());
94    }
95
96    protected HttpResponseFactory createHttpResponseFactory() {
97        return new DefaultHttpResponseFactory();
98    }
99
100    protected HttpMessageParser createResponseParser(
101            final SessionInputBuffer buffer,
102            final HttpResponseFactory responseFactory,
103            final HttpParams params) {
104        // override in derived class to specify a line parser
105        return new HttpResponseParser(buffer, null, responseFactory, params);
106    }
107
108    protected HttpMessageWriter createRequestWriter(
109            final SessionOutputBuffer buffer,
110            final HttpParams params) {
111        // override in derived class to specify a line formatter
112        return new HttpRequestWriter(buffer, null, params);
113    }
114
115    protected void init(
116            final SessionInputBuffer inbuffer,
117            final SessionOutputBuffer outbuffer,
118            final HttpParams params) {
119        if (inbuffer == null) {
120            throw new IllegalArgumentException("Input session buffer may not be null");
121        }
122        if (outbuffer == null) {
123            throw new IllegalArgumentException("Output session buffer may not be null");
124        }
125        this.inbuffer = inbuffer;
126        this.outbuffer = outbuffer;
127        this.responseParser = createResponseParser(
128                inbuffer,
129                createHttpResponseFactory(),
130                params);
131        this.requestWriter = createRequestWriter(
132                outbuffer, params);
133        this.metrics = new HttpConnectionMetricsImpl(
134                inbuffer.getMetrics(),
135                outbuffer.getMetrics());
136    }
137
138    public boolean isResponseAvailable(int timeout) throws IOException {
139        assertOpen();
140        return this.inbuffer.isDataAvailable(timeout);
141    }
142
143    public void sendRequestHeader(final HttpRequest request)
144            throws HttpException, IOException {
145        if (request == null) {
146            throw new IllegalArgumentException("HTTP request may not be null");
147        }
148        assertOpen();
149        this.requestWriter.write(request);
150        this.metrics.incrementRequestCount();
151    }
152
153    public void sendRequestEntity(final HttpEntityEnclosingRequest request)
154            throws HttpException, IOException {
155        if (request == null) {
156            throw new IllegalArgumentException("HTTP request may not be null");
157        }
158        assertOpen();
159        if (request.getEntity() == null) {
160            return;
161        }
162        this.entityserializer.serialize(
163                this.outbuffer,
164                request,
165                request.getEntity());
166    }
167
168    protected void doFlush() throws IOException {
169        this.outbuffer.flush();
170    }
171
172    public void flush() throws IOException {
173        assertOpen();
174        doFlush();
175    }
176
177    public HttpResponse receiveResponseHeader()
178            throws HttpException, IOException {
179        assertOpen();
180        HttpResponse response = (HttpResponse) this.responseParser.parse();
181        if (response.getStatusLine().getStatusCode() >= 200) {
182            this.metrics.incrementResponseCount();
183        }
184        return response;
185    }
186
187    public void receiveResponseEntity(final HttpResponse response)
188            throws HttpException, IOException {
189        if (response == null) {
190            throw new IllegalArgumentException("HTTP response may not be null");
191        }
192        assertOpen();
193        HttpEntity entity = this.entitydeserializer.deserialize(this.inbuffer, response);
194        response.setEntity(entity);
195    }
196
197    public boolean isStale() {
198        if (!isOpen()) {
199            return true;
200        }
201        try {
202            // BEGIN android-added
203            //     don't reuse connections when the socket input stream is exhausted
204            if (inbuffer instanceof SocketInputBuffer) {
205                return ((SocketInputBuffer) inbuffer).isStale();
206            }
207            // END android-added
208            this.inbuffer.isDataAvailable(1);
209            return false;
210        } catch (IOException ex) {
211            return true;
212        }
213    }
214
215    public HttpConnectionMetrics getMetrics() {
216        return this.metrics;
217    }
218
219}
220