Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /*
2 * ====================================================================
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 * ====================================================================
20 *
21 * This software consists of voluntary contributions made by many
22 * individuals on behalf of the Apache Software Foundation. For more
23 * information on the Apache Software Foundation, please see
24 * <http://www.apache.org/>.
25 *
26 */
28 package ch.boye.httpclientandroidlib.impl;
30 import java.io.IOException;
32 import ch.boye.httpclientandroidlib.HttpClientConnection;
33 import ch.boye.httpclientandroidlib.HttpConnectionMetrics;
34 import ch.boye.httpclientandroidlib.HttpEntity;
35 import ch.boye.httpclientandroidlib.HttpEntityEnclosingRequest;
36 import ch.boye.httpclientandroidlib.HttpException;
37 import ch.boye.httpclientandroidlib.HttpRequest;
38 import ch.boye.httpclientandroidlib.HttpResponse;
39 import ch.boye.httpclientandroidlib.HttpResponseFactory;
40 import ch.boye.httpclientandroidlib.entity.ContentLengthStrategy;
41 import ch.boye.httpclientandroidlib.impl.entity.EntityDeserializer;
42 import ch.boye.httpclientandroidlib.impl.entity.EntitySerializer;
43 import ch.boye.httpclientandroidlib.impl.entity.LaxContentLengthStrategy;
44 import ch.boye.httpclientandroidlib.impl.entity.StrictContentLengthStrategy;
45 import ch.boye.httpclientandroidlib.impl.io.HttpRequestWriter;
46 import ch.boye.httpclientandroidlib.impl.io.HttpResponseParser;
47 import ch.boye.httpclientandroidlib.io.EofSensor;
48 import ch.boye.httpclientandroidlib.io.HttpMessageParser;
49 import ch.boye.httpclientandroidlib.io.HttpMessageWriter;
50 import ch.boye.httpclientandroidlib.io.HttpTransportMetrics;
51 import ch.boye.httpclientandroidlib.io.SessionInputBuffer;
52 import ch.boye.httpclientandroidlib.io.SessionOutputBuffer;
53 import ch.boye.httpclientandroidlib.message.LineFormatter;
54 import ch.boye.httpclientandroidlib.message.LineParser;
55 import ch.boye.httpclientandroidlib.params.HttpParams;
57 /**
58 * Abstract client-side HTTP connection capable of transmitting and receiving
59 * data using arbitrary {@link SessionInputBuffer} and
60 * {@link SessionOutputBuffer} implementations.
61 * <p>
62 * The following parameters can be used to customize the behavior of this
63 * class:
64 * <ul>
65 * <li>{@link ch.boye.httpclientandroidlib.params.CoreProtocolPNames#STRICT_TRANSFER_ENCODING}</li>
66 * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MAX_HEADER_COUNT}</li>
67 * </ul>
68 *
69 * @since 4.0
70 */
71 public abstract class AbstractHttpClientConnection implements HttpClientConnection {
73 private final EntitySerializer entityserializer;
74 private final EntityDeserializer entitydeserializer;
76 private SessionInputBuffer inbuffer = null;
77 private SessionOutputBuffer outbuffer = null;
78 private EofSensor eofSensor = null;
79 private HttpMessageParser responseParser = null;
80 private HttpMessageWriter requestWriter = null;
81 private HttpConnectionMetricsImpl metrics = null;
83 /**
84 * Creates an instance of this class.
85 * <p>
86 * This constructor will invoke {@link #createEntityDeserializer()}
87 * and {@link #createEntitySerializer()} methods in order to initialize
88 * HTTP entity serializer and deserializer implementations for this
89 * connection.
90 */
91 public AbstractHttpClientConnection() {
92 super();
93 this.entityserializer = createEntitySerializer();
94 this.entitydeserializer = createEntityDeserializer();
95 }
97 /**
98 * Asserts if the connection is open.
99 *
100 * @throws IllegalStateException if the connection is not open.
101 */
102 protected abstract void assertOpen() throws IllegalStateException;
104 /**
105 * Creates an instance of {@link EntityDeserializer} with the
106 * {@link LaxContentLengthStrategy} implementation to be used for
107 * de-serializing entities received over this connection.
108 * <p>
109 * This method can be overridden in a super class in order to create
110 * instances of {@link EntityDeserializer} using a custom
111 * {@link ContentLengthStrategy}.
112 *
113 * @return HTTP entity deserializer
114 */
115 protected EntityDeserializer createEntityDeserializer() {
116 return new EntityDeserializer(new LaxContentLengthStrategy());
117 }
119 /**
120 * Creates an instance of {@link EntitySerializer} with the
121 * {@link StrictContentLengthStrategy} implementation to be used for
122 * serializing HTTP entities sent over this connection.
123 * <p>
124 * This method can be overridden in a super class in order to create
125 * instances of {@link EntitySerializer} using a custom
126 * {@link ContentLengthStrategy}.
127 *
128 * @return HTTP entity serialzier.
129 */
130 protected EntitySerializer createEntitySerializer() {
131 return new EntitySerializer(new StrictContentLengthStrategy());
132 }
134 /**
135 * Creates an instance of {@link DefaultHttpResponseFactory} to be used
136 * for creating {@link HttpResponse} objects received by over this
137 * connection.
138 * <p>
139 * This method can be overridden in a super class in order to provide
140 * a different implementation of the {@link HttpResponseFactory} interface.
141 *
142 * @return HTTP response factory.
143 */
144 protected HttpResponseFactory createHttpResponseFactory() {
145 return new DefaultHttpResponseFactory();
146 }
148 /**
149 * Creates an instance of {@link HttpMessageParser} to be used for parsing
150 * HTTP responses received over this connection.
151 * <p>
152 * This method can be overridden in a super class in order to provide
153 * a different implementation of the {@link HttpMessageParser} interface or
154 * to pass a different implementation of {@link LineParser} to the
155 * the default implementation {@link HttpResponseParser}.
156 *
157 * @param buffer the session input buffer.
158 * @param responseFactory the HTTP response factory.
159 * @param params HTTP parameters.
160 * @return HTTP message parser.
161 */
162 protected HttpMessageParser createResponseParser(
163 final SessionInputBuffer buffer,
164 final HttpResponseFactory responseFactory,
165 final HttpParams params) {
166 return new HttpResponseParser(buffer, null, responseFactory, params);
167 }
169 /**
170 * Creates an instance of {@link HttpMessageWriter} to be used for
171 * writing out HTTP requests sent over this connection.
172 * <p>
173 * This method can be overridden in a super class in order to provide
174 * a different implementation of the {@link HttpMessageWriter} interface or
175 * to pass a different implementation of {@link LineFormatter} to the
176 * the default implementation {@link HttpRequestWriter}.
177 *
178 * @param buffer the session output buffer
179 * @param params HTTP parameters
180 * @return HTTP message writer
181 */
182 protected HttpMessageWriter createRequestWriter(
183 final SessionOutputBuffer buffer,
184 final HttpParams params) {
185 return new HttpRequestWriter(buffer, null, params);
186 }
188 /**
189 * @since 4.1
190 */
191 protected HttpConnectionMetricsImpl createConnectionMetrics(
192 final HttpTransportMetrics inTransportMetric,
193 final HttpTransportMetrics outTransportMetric) {
194 return new HttpConnectionMetricsImpl(inTransportMetric, outTransportMetric);
195 }
197 /**
198 * Initializes this connection object with {@link SessionInputBuffer} and
199 * {@link SessionOutputBuffer} instances to be used for sending and
200 * receiving data. These session buffers can be bound to any arbitrary
201 * physical output medium.
202 * <p>
203 * This method will invoke {@link #createHttpResponseFactory()},
204 * {@link #createRequestWriter(SessionOutputBuffer, HttpParams)}
205 * and {@link #createResponseParser(SessionInputBuffer, HttpResponseFactory, HttpParams)}
206 * methods to initialize HTTP request writer and response parser for this
207 * connection.
208 *
209 * @param inbuffer the session input buffer.
210 * @param outbuffer the session output buffer.
211 * @param params HTTP parameters.
212 */
213 protected void init(
214 final SessionInputBuffer inbuffer,
215 final SessionOutputBuffer outbuffer,
216 final HttpParams params) {
217 if (inbuffer == null) {
218 throw new IllegalArgumentException("Input session buffer may not be null");
219 }
220 if (outbuffer == null) {
221 throw new IllegalArgumentException("Output session buffer may not be null");
222 }
223 this.inbuffer = inbuffer;
224 this.outbuffer = outbuffer;
225 if (inbuffer instanceof EofSensor) {
226 this.eofSensor = (EofSensor) inbuffer;
227 }
228 this.responseParser = createResponseParser(
229 inbuffer,
230 createHttpResponseFactory(),
231 params);
232 this.requestWriter = createRequestWriter(
233 outbuffer, params);
234 this.metrics = createConnectionMetrics(
235 inbuffer.getMetrics(),
236 outbuffer.getMetrics());
237 }
239 public boolean isResponseAvailable(int timeout) throws IOException {
240 assertOpen();
241 return this.inbuffer.isDataAvailable(timeout);
242 }
244 public void sendRequestHeader(final HttpRequest request)
245 throws HttpException, IOException {
246 if (request == null) {
247 throw new IllegalArgumentException("HTTP request may not be null");
248 }
249 assertOpen();
250 this.requestWriter.write(request);
251 this.metrics.incrementRequestCount();
252 }
254 public void sendRequestEntity(final HttpEntityEnclosingRequest request)
255 throws HttpException, IOException {
256 if (request == null) {
257 throw new IllegalArgumentException("HTTP request may not be null");
258 }
259 assertOpen();
260 if (request.getEntity() == null) {
261 return;
262 }
263 this.entityserializer.serialize(
264 this.outbuffer,
265 request,
266 request.getEntity());
267 }
269 protected void doFlush() throws IOException {
270 this.outbuffer.flush();
271 }
273 public void flush() throws IOException {
274 assertOpen();
275 doFlush();
276 }
278 public HttpResponse receiveResponseHeader()
279 throws HttpException, IOException {
280 assertOpen();
281 HttpResponse response = (HttpResponse) this.responseParser.parse();
282 if (response.getStatusLine().getStatusCode() >= 200) {
283 this.metrics.incrementResponseCount();
284 }
285 return response;
286 }
288 public void receiveResponseEntity(final HttpResponse response)
289 throws HttpException, IOException {
290 if (response == null) {
291 throw new IllegalArgumentException("HTTP response may not be null");
292 }
293 assertOpen();
294 HttpEntity entity = this.entitydeserializer.deserialize(this.inbuffer, response);
295 response.setEntity(entity);
296 }
298 protected boolean isEof() {
299 return this.eofSensor != null && this.eofSensor.isEof();
300 }
302 public boolean isStale() {
303 if (!isOpen()) {
304 return true;
305 }
306 if (isEof()) {
307 return true;
308 }
309 try {
310 this.inbuffer.isDataAvailable(1);
311 return isEof();
312 } catch (IOException ex) {
313 return true;
314 }
315 }
317 public HttpConnectionMetrics getMetrics() {
318 return this.metrics;
319 }
321 }