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