michael@0: /*
michael@0: * ====================================================================
michael@0: * Licensed to the Apache Software Foundation (ASF) under one
michael@0: * or more contributor license agreements. See the NOTICE file
michael@0: * distributed with this work for additional information
michael@0: * regarding copyright ownership. The ASF licenses this file
michael@0: * to you under the Apache License, Version 2.0 (the
michael@0: * "License"); you may not use this file except in compliance
michael@0: * with the License. You may obtain a copy of the License at
michael@0: *
michael@0: * http://www.apache.org/licenses/LICENSE-2.0
michael@0: *
michael@0: * Unless required by applicable law or agreed to in writing,
michael@0: * software distributed under the License is distributed on an
michael@0: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
michael@0: * KIND, either express or implied. See the License for the
michael@0: * specific language governing permissions and limitations
michael@0: * under the License.
michael@0: * ====================================================================
michael@0: *
michael@0: * This software consists of voluntary contributions made by many
michael@0: * individuals on behalf of the Apache Software Foundation. For more
michael@0: * information on the Apache Software Foundation, please see
michael@0: *
michael@0: * The following parameters can be used to customize the behavior of this michael@0: * class: michael@0: *
michael@0: * This constructor will invoke {@link #createEntityDeserializer()} michael@0: * and {@link #createEntitySerializer()} methods in order to initialize michael@0: * HTTP entity serializer and deserializer implementations for this michael@0: * connection. michael@0: */ michael@0: public AbstractHttpClientConnection() { michael@0: super(); michael@0: this.entityserializer = createEntitySerializer(); michael@0: this.entitydeserializer = createEntityDeserializer(); michael@0: } michael@0: michael@0: /** michael@0: * Asserts if the connection is open. michael@0: * michael@0: * @throws IllegalStateException if the connection is not open. michael@0: */ michael@0: protected abstract void assertOpen() throws IllegalStateException; michael@0: michael@0: /** michael@0: * Creates an instance of {@link EntityDeserializer} with the michael@0: * {@link LaxContentLengthStrategy} implementation to be used for michael@0: * de-serializing entities received over this connection. michael@0: *
michael@0: * This method can be overridden in a super class in order to create michael@0: * instances of {@link EntityDeserializer} using a custom michael@0: * {@link ContentLengthStrategy}. michael@0: * michael@0: * @return HTTP entity deserializer michael@0: */ michael@0: protected EntityDeserializer createEntityDeserializer() { michael@0: return new EntityDeserializer(new LaxContentLengthStrategy()); michael@0: } michael@0: michael@0: /** michael@0: * Creates an instance of {@link EntitySerializer} with the michael@0: * {@link StrictContentLengthStrategy} implementation to be used for michael@0: * serializing HTTP entities sent over this connection. michael@0: *
michael@0: * This method can be overridden in a super class in order to create michael@0: * instances of {@link EntitySerializer} using a custom michael@0: * {@link ContentLengthStrategy}. michael@0: * michael@0: * @return HTTP entity serialzier. michael@0: */ michael@0: protected EntitySerializer createEntitySerializer() { michael@0: return new EntitySerializer(new StrictContentLengthStrategy()); michael@0: } michael@0: michael@0: /** michael@0: * Creates an instance of {@link DefaultHttpResponseFactory} to be used michael@0: * for creating {@link HttpResponse} objects received by over this michael@0: * connection. michael@0: *
michael@0: * This method can be overridden in a super class in order to provide michael@0: * a different implementation of the {@link HttpResponseFactory} interface. michael@0: * michael@0: * @return HTTP response factory. michael@0: */ michael@0: protected HttpResponseFactory createHttpResponseFactory() { michael@0: return new DefaultHttpResponseFactory(); michael@0: } michael@0: michael@0: /** michael@0: * Creates an instance of {@link HttpMessageParser} to be used for parsing michael@0: * HTTP responses received over this connection. michael@0: *
michael@0: * This method can be overridden in a super class in order to provide michael@0: * a different implementation of the {@link HttpMessageParser} interface or michael@0: * to pass a different implementation of {@link LineParser} to the michael@0: * the default implementation {@link HttpResponseParser}. michael@0: * michael@0: * @param buffer the session input buffer. michael@0: * @param responseFactory the HTTP response factory. michael@0: * @param params HTTP parameters. michael@0: * @return HTTP message parser. michael@0: */ michael@0: protected HttpMessageParser createResponseParser( michael@0: final SessionInputBuffer buffer, michael@0: final HttpResponseFactory responseFactory, michael@0: final HttpParams params) { michael@0: return new HttpResponseParser(buffer, null, responseFactory, params); michael@0: } michael@0: michael@0: /** michael@0: * Creates an instance of {@link HttpMessageWriter} to be used for michael@0: * writing out HTTP requests sent over this connection. michael@0: *
michael@0: * This method can be overridden in a super class in order to provide michael@0: * a different implementation of the {@link HttpMessageWriter} interface or michael@0: * to pass a different implementation of {@link LineFormatter} to the michael@0: * the default implementation {@link HttpRequestWriter}. michael@0: * michael@0: * @param buffer the session output buffer michael@0: * @param params HTTP parameters michael@0: * @return HTTP message writer michael@0: */ michael@0: protected HttpMessageWriter createRequestWriter( michael@0: final SessionOutputBuffer buffer, michael@0: final HttpParams params) { michael@0: return new HttpRequestWriter(buffer, null, params); michael@0: } michael@0: michael@0: /** michael@0: * @since 4.1 michael@0: */ michael@0: protected HttpConnectionMetricsImpl createConnectionMetrics( michael@0: final HttpTransportMetrics inTransportMetric, michael@0: final HttpTransportMetrics outTransportMetric) { michael@0: return new HttpConnectionMetricsImpl(inTransportMetric, outTransportMetric); michael@0: } michael@0: michael@0: /** michael@0: * Initializes this connection object with {@link SessionInputBuffer} and michael@0: * {@link SessionOutputBuffer} instances to be used for sending and michael@0: * receiving data. These session buffers can be bound to any arbitrary michael@0: * physical output medium. michael@0: *
michael@0: * This method will invoke {@link #createHttpResponseFactory()}, michael@0: * {@link #createRequestWriter(SessionOutputBuffer, HttpParams)} michael@0: * and {@link #createResponseParser(SessionInputBuffer, HttpResponseFactory, HttpParams)} michael@0: * methods to initialize HTTP request writer and response parser for this michael@0: * connection. michael@0: * michael@0: * @param inbuffer the session input buffer. michael@0: * @param outbuffer the session output buffer. michael@0: * @param params HTTP parameters. michael@0: */ michael@0: protected void init( michael@0: final SessionInputBuffer inbuffer, michael@0: final SessionOutputBuffer outbuffer, michael@0: final HttpParams params) { michael@0: if (inbuffer == null) { michael@0: throw new IllegalArgumentException("Input session buffer may not be null"); michael@0: } michael@0: if (outbuffer == null) { michael@0: throw new IllegalArgumentException("Output session buffer may not be null"); michael@0: } michael@0: this.inbuffer = inbuffer; michael@0: this.outbuffer = outbuffer; michael@0: if (inbuffer instanceof EofSensor) { michael@0: this.eofSensor = (EofSensor) inbuffer; michael@0: } michael@0: this.responseParser = createResponseParser( michael@0: inbuffer, michael@0: createHttpResponseFactory(), michael@0: params); michael@0: this.requestWriter = createRequestWriter( michael@0: outbuffer, params); michael@0: this.metrics = createConnectionMetrics( michael@0: inbuffer.getMetrics(), michael@0: outbuffer.getMetrics()); michael@0: } michael@0: michael@0: public boolean isResponseAvailable(int timeout) throws IOException { michael@0: assertOpen(); michael@0: return this.inbuffer.isDataAvailable(timeout); michael@0: } michael@0: michael@0: public void sendRequestHeader(final HttpRequest request) michael@0: throws HttpException, IOException { michael@0: if (request == null) { michael@0: throw new IllegalArgumentException("HTTP request may not be null"); michael@0: } michael@0: assertOpen(); michael@0: this.requestWriter.write(request); michael@0: this.metrics.incrementRequestCount(); michael@0: } michael@0: michael@0: public void sendRequestEntity(final HttpEntityEnclosingRequest request) michael@0: throws HttpException, IOException { michael@0: if (request == null) { michael@0: throw new IllegalArgumentException("HTTP request may not be null"); michael@0: } michael@0: assertOpen(); michael@0: if (request.getEntity() == null) { michael@0: return; michael@0: } michael@0: this.entityserializer.serialize( michael@0: this.outbuffer, michael@0: request, michael@0: request.getEntity()); michael@0: } michael@0: michael@0: protected void doFlush() throws IOException { michael@0: this.outbuffer.flush(); michael@0: } michael@0: michael@0: public void flush() throws IOException { michael@0: assertOpen(); michael@0: doFlush(); michael@0: } michael@0: michael@0: public HttpResponse receiveResponseHeader() michael@0: throws HttpException, IOException { michael@0: assertOpen(); michael@0: HttpResponse response = (HttpResponse) this.responseParser.parse(); michael@0: if (response.getStatusLine().getStatusCode() >= 200) { michael@0: this.metrics.incrementResponseCount(); michael@0: } michael@0: return response; michael@0: } michael@0: michael@0: public void receiveResponseEntity(final HttpResponse response) michael@0: throws HttpException, IOException { michael@0: if (response == null) { michael@0: throw new IllegalArgumentException("HTTP response may not be null"); michael@0: } michael@0: assertOpen(); michael@0: HttpEntity entity = this.entitydeserializer.deserialize(this.inbuffer, response); michael@0: response.setEntity(entity); michael@0: } michael@0: michael@0: protected boolean isEof() { michael@0: return this.eofSensor != null && this.eofSensor.isEof(); michael@0: } michael@0: michael@0: public boolean isStale() { michael@0: if (!isOpen()) { michael@0: return true; michael@0: } michael@0: if (isEof()) { michael@0: return true; michael@0: } michael@0: try { michael@0: this.inbuffer.isDataAvailable(1); michael@0: return isEof(); michael@0: } catch (IOException ex) { michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: public HttpConnectionMetrics getMetrics() { michael@0: return this.metrics; michael@0: } michael@0: michael@0: }