View Javadoc

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   */
27  
28  package org.apache.http.impl.client;
29  
30  import java.io.Closeable;
31  import java.io.IOException;
32  import java.net.URI;
33  
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  import org.apache.http.HttpEntity;
37  import org.apache.http.HttpHost;
38  import org.apache.http.HttpRequest;
39  import org.apache.http.annotation.ThreadSafe;
40  import org.apache.http.client.ClientProtocolException;
41  import org.apache.http.client.HttpClient;
42  import org.apache.http.client.ResponseHandler;
43  import org.apache.http.client.methods.CloseableHttpResponse;
44  import org.apache.http.client.methods.HttpUriRequest;
45  import org.apache.http.client.utils.URIUtils;
46  import org.apache.http.protocol.HttpContext;
47  import org.apache.http.util.Args;
48  import org.apache.http.util.EntityUtils;
49  
50  /**
51   * Base implementation of {@link HttpClient} that also implements {@link Closeable}.
52   *
53   * @since 4.3
54   */
55  @ThreadSafe
56  public abstract class CloseableHttpClient implements HttpClient, Closeable {
57  
58      private final Log log = LogFactory.getLog(getClass());
59  
60      protected abstract CloseableHttpResponse doExecute(HttpHost target, HttpRequest request,
61              HttpContext context) throws IOException, ClientProtocolException;
62  
63      /**
64       * {@inheritDoc}
65       */
66      @Override
67      public CloseableHttpResponse execute(
68              final HttpHost target,
69              final HttpRequest request,
70              final HttpContext context) throws IOException, ClientProtocolException {
71          return doExecute(target, request, context);
72      }
73  
74      /**
75       * {@inheritDoc}
76       */
77      @Override
78      public CloseableHttpResponse execute(
79              final HttpUriRequest request,
80              final HttpContext context) throws IOException, ClientProtocolException {
81          Args.notNull(request, "HTTP request");
82          return doExecute(determineTarget(request), request, context);
83      }
84  
85      private static HttpHost determineTarget(final HttpUriRequest request) throws ClientProtocolException {
86          // A null target may be acceptable if there is a default target.
87          // Otherwise, the null target is detected in the director.
88          HttpHost target = null;
89  
90          final URI requestURI = request.getURI();
91          if (requestURI.isAbsolute()) {
92              target = URIUtils.extractHost(requestURI);
93              if (target == null) {
94                  throw new ClientProtocolException("URI does not specify a valid host name: "
95                          + requestURI);
96              }
97          }
98          return target;
99      }
100 
101     /**
102      * {@inheritDoc}
103      */
104     @Override
105     public CloseableHttpResponse execute(
106             final HttpUriRequest request) throws IOException, ClientProtocolException {
107         return execute(request, (HttpContext) null);
108     }
109 
110     /**
111      * {@inheritDoc}
112      */
113     @Override
114     public CloseableHttpResponse execute(
115             final HttpHost target,
116             final HttpRequest request) throws IOException, ClientProtocolException {
117         return doExecute(target, request, null);
118     }
119 
120     /**
121      * Executes a request using the default context and processes the
122      * response using the given response handler. The content entity associated
123      * with the response is fully consumed and the underlying connection is
124      * released back to the connection manager automatically in all cases
125      * relieving individual {@link ResponseHandler}s from having to manage
126      * resource deallocation internally.
127      *
128      * @param request   the request to execute
129      * @param responseHandler the response handler
130      *
131      * @return  the response object as generated by the response handler.
132      * @throws IOException in case of a problem or the connection was aborted
133      * @throws ClientProtocolException in case of an http protocol error
134      */
135     @Override
136     public <T> T execute(final HttpUriRequest request,
137             final ResponseHandler<? extends T> responseHandler) throws IOException,
138             ClientProtocolException {
139         return execute(request, responseHandler, null);
140     }
141 
142     /**
143      * Executes a request using the default context and processes the
144      * response using the given response handler. The content entity associated
145      * with the response is fully consumed and the underlying connection is
146      * released back to the connection manager automatically in all cases
147      * relieving individual {@link ResponseHandler}s from having to manage
148      * resource deallocation internally.
149      *
150      * @param request   the request to execute
151      * @param responseHandler the response handler
152      * @param context   the context to use for the execution, or
153      *                  {@code null} to use the default context
154      *
155      * @return  the response object as generated by the response handler.
156      * @throws IOException in case of a problem or the connection was aborted
157      * @throws ClientProtocolException in case of an http protocol error
158      */
159     @Override
160     public <T> T execute(final HttpUriRequest request,
161             final ResponseHandler<? extends T> responseHandler, final HttpContext context)
162             throws IOException, ClientProtocolException {
163         final HttpHost target = determineTarget(request);
164         return execute(target, request, responseHandler, context);
165     }
166 
167     /**
168      * Executes a request using the default context and processes the
169      * response using the given response handler. The content entity associated
170      * with the response is fully consumed and the underlying connection is
171      * released back to the connection manager automatically in all cases
172      * relieving individual {@link ResponseHandler}s from having to manage
173      * resource deallocation internally.
174      *
175      * @param target    the target host for the request.
176      *                  Implementations may accept {@code null}
177      *                  if they can still determine a route, for example
178      *                  to a default target or by inspecting the request.
179      * @param request   the request to execute
180      * @param responseHandler the response handler
181      *
182      * @return  the response object as generated by the response handler.
183      * @throws IOException in case of a problem or the connection was aborted
184      * @throws ClientProtocolException in case of an http protocol error
185      */
186     @Override
187     public <T> T execute(final HttpHost target, final HttpRequest request,
188             final ResponseHandler<? extends T> responseHandler) throws IOException,
189             ClientProtocolException {
190         return execute(target, request, responseHandler, null);
191     }
192 
193     /**
194      * Executes a request using the default context and processes the
195      * response using the given response handler. The content entity associated
196      * with the response is fully consumed and the underlying connection is
197      * released back to the connection manager automatically in all cases
198      * relieving individual {@link ResponseHandler}s from having to manage
199      * resource deallocation internally.
200      *
201      * @param target    the target host for the request.
202      *                  Implementations may accept {@code null}
203      *                  if they can still determine a route, for example
204      *                  to a default target or by inspecting the request.
205      * @param request   the request to execute
206      * @param responseHandler the response handler
207      * @param context   the context to use for the execution, or
208      *                  {@code null} to use the default context
209      *
210      * @return  the response object as generated by the response handler.
211      * @throws IOException in case of a problem or the connection was aborted
212      * @throws ClientProtocolException in case of an http protocol error
213      */
214     @Override
215     public <T> T execute(final HttpHost target, final HttpRequest request,
216             final ResponseHandler<? extends T> responseHandler, final HttpContext context)
217             throws IOException, ClientProtocolException {
218         Args.notNull(responseHandler, "Response handler");
219 
220         final CloseableHttpResponse response = execute(target, request, context);
221         try {
222             final T result = responseHandler.handleResponse(response);
223             final HttpEntity entity = response.getEntity();
224             EntityUtils.consume(entity);
225             return result;
226         } catch (final ClientProtocolException t) {
227             // Try to salvage the underlying connection in case of a protocol exception
228             final HttpEntity entity = response.getEntity();
229             try {
230                 EntityUtils.consume(entity);
231             } catch (final Exception t2) {
232                 // Log this exception. The original exception is more
233                 // important and will be thrown to the caller.
234                 this.log.warn("Error consuming content after an exception.", t2);
235             }
236             throw t;
237         } finally {
238             response.close();
239         }
240     }
241 
242 }