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