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.HttpConnectionMetrics;
33 import ch.boye.httpclientandroidlib.HttpEntity;
34 import ch.boye.httpclientandroidlib.HttpEntityEnclosingRequest;
35 import ch.boye.httpclientandroidlib.HttpException;
36 import ch.boye.httpclientandroidlib.HttpRequest;
37 import ch.boye.httpclientandroidlib.HttpRequestFactory;
38 import ch.boye.httpclientandroidlib.HttpResponse;
39 import ch.boye.httpclientandroidlib.HttpServerConnection;
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.HttpRequestParser;
46 import ch.boye.httpclientandroidlib.impl.io.HttpResponseWriter;
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 server-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 AbstractHttpServerConnection implements HttpServerConnection {
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 requestParser = null;
80 private HttpMessageWriter responseWriter = 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 AbstractHttpServerConnection() {
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 DefaultHttpRequestFactory} to be used
136 * for creating {@link HttpRequest} 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 HttpRequestFactory} interface.
141 *
142 * @return HTTP request factory.
143 */
144 protected HttpRequestFactory createHttpRequestFactory() {
145 return new DefaultHttpRequestFactory();
146 }
148 /**
149 * Creates an instance of {@link HttpMessageParser} to be used for parsing
150 * HTTP requests 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 HttpRequestParser}.
156 *
157 * @param buffer the session input buffer.
158 * @param requestFactory the HTTP request factory.
159 * @param params HTTP parameters.
160 * @return HTTP message parser.
161 */
162 protected HttpMessageParser createRequestParser(
163 final SessionInputBuffer buffer,
164 final HttpRequestFactory requestFactory,
165 final HttpParams params) {
166 return new HttpRequestParser(buffer, null, requestFactory, params);
167 }
169 /**
170 * Creates an instance of {@link HttpMessageWriter} to be used for
171 * writing out HTTP responses 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 HttpResponseWriter}.
177 *
178 * @param buffer the session output buffer
179 * @param params HTTP parameters
180 * @return HTTP message writer
181 */
182 protected HttpMessageWriter createResponseWriter(
183 final SessionOutputBuffer buffer,
184 final HttpParams params) {
185 return new HttpResponseWriter(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 #createHttpRequestFactory},
204 * {@link #createRequestParser(SessionInputBuffer, HttpRequestFactory, HttpParams)}
205 * and {@link #createResponseWriter(SessionOutputBuffer, HttpParams)}
206 * methods to initialize HTTP request parser and response writer 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.requestParser = createRequestParser(
229 inbuffer,
230 createHttpRequestFactory(),
231 params);
232 this.responseWriter = createResponseWriter(
233 outbuffer, params);
234 this.metrics = createConnectionMetrics(
235 inbuffer.getMetrics(),
236 outbuffer.getMetrics());
237 }
239 public HttpRequest receiveRequestHeader()
240 throws HttpException, IOException {
241 assertOpen();
242 HttpRequest request = (HttpRequest) this.requestParser.parse();
243 this.metrics.incrementRequestCount();
244 return request;
245 }
247 public void receiveRequestEntity(final HttpEntityEnclosingRequest request)
248 throws HttpException, IOException {
249 if (request == null) {
250 throw new IllegalArgumentException("HTTP request may not be null");
251 }
252 assertOpen();
253 HttpEntity entity = this.entitydeserializer.deserialize(this.inbuffer, request);
254 request.setEntity(entity);
255 }
257 protected void doFlush() throws IOException {
258 this.outbuffer.flush();
259 }
261 public void flush() throws IOException {
262 assertOpen();
263 doFlush();
264 }
266 public void sendResponseHeader(final HttpResponse response)
267 throws HttpException, IOException {
268 if (response == null) {
269 throw new IllegalArgumentException("HTTP response may not be null");
270 }
271 assertOpen();
272 this.responseWriter.write(response);
273 if (response.getStatusLine().getStatusCode() >= 200) {
274 this.metrics.incrementResponseCount();
275 }
276 }
278 public void sendResponseEntity(final HttpResponse response)
279 throws HttpException, IOException {
280 if (response.getEntity() == null) {
281 return;
282 }
283 this.entityserializer.serialize(
284 this.outbuffer,
285 response,
286 response.getEntity());
287 }
289 protected boolean isEof() {
290 return this.eofSensor != null && this.eofSensor.isEof();
291 }
293 public boolean isStale() {
294 if (!isOpen()) {
295 return true;
296 }
297 if (isEof()) {
298 return true;
299 }
300 try {
301 this.inbuffer.isDataAvailable(1);
302 return isEof();
303 } catch (IOException ex) {
304 return true;
305 }
306 }
308 public HttpConnectionMetrics getMetrics() {
309 return this.metrics;
310 }
312 }