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      @Override
69      public CloseableHttpResponse execute(
70              final HttpHost target,
71              final HttpRequest request,
72              final HttpContext context) throws IOException, ClientProtocolException {
73          return doExecute(target, request, context);
74      }
75  
76      /**
77       * {@inheritDoc}
78       */
79      @Override
80      public CloseableHttpResponse execute(
81              final HttpUriRequest request,
82              final HttpContext context) throws IOException, ClientProtocolException {
83          Args.notNull(request, "HTTP request");
84          return doExecute(determineTarget(request), request, context);
85      }
86  
87      private static HttpHost determineTarget(final HttpUriRequest request) throws ClientProtocolException {
88          // A null target may be acceptable if there is a default target.
89          // Otherwise, the null target is detected in the director.
90          HttpHost target = null;
91  
92          final URI requestURI = request.getURI();
93          if (requestURI.isAbsolute()) {
94              target = URIUtils.extractHost(requestURI);
95              if (target == null) {
96                  throw new ClientProtocolException("URI does not specify a valid host name: "
97                          + requestURI);
98              }
99          }
100         return target;
101     }
102 
103     /**
104      * {@inheritDoc}
105      */
106     @Override
107     public CloseableHttpResponse execute(
108             final HttpUriRequest request) throws IOException, ClientProtocolException {
109         return execute(request, (HttpContext) null);
110     }
111 
112     /**
113      * {@inheritDoc}
114      */
115     @Override
116     public CloseableHttpResponse execute(
117             final HttpHost target,
118             final HttpRequest request) throws IOException, ClientProtocolException {
119         return doExecute(target, request, null);
120     }
121 
122     /**
123      * Executes a request using the default context and processes the
124      * response using the given response handler. The content entity associated
125      * with the response is fully consumed and the underlying connection is
126      * released back to the connection manager automatically in all cases
127      * relieving individual {@link ResponseHandler}s from having to manage
128      * resource deallocation internally.
129      *
130      * @param request   the request to execute
131      * @param responseHandler the response handler
132      *
133      * @return  the response object as generated by the response handler.
134      * @throws IOException in case of a problem or the connection was aborted
135      * @throws ClientProtocolException in case of an http protocol error
136      */
137     @Override
138     public <T> T execute(final HttpUriRequest request,
139             final ResponseHandler<? extends T> responseHandler) throws IOException,
140             ClientProtocolException {
141         return execute(request, responseHandler, null);
142     }
143 
144     /**
145      * Executes a request using the default context and processes the
146      * response using the given response handler. The content entity associated
147      * with the response is fully consumed and the underlying connection is
148      * released back to the connection manager automatically in all cases
149      * relieving individual {@link ResponseHandler}s from having to manage
150      * resource deallocation internally.
151      *
152      * @param request   the request to execute
153      * @param responseHandler the response handler
154      * @param context   the context to use for the execution, or
155      *                  <code>null</code> to use the default context
156      *
157      * @return  the response object as generated by the response handler.
158      * @throws IOException in case of a problem or the connection was aborted
159      * @throws ClientProtocolException in case of an http protocol error
160      */
161     @Override
162     public <T> T execute(final HttpUriRequest request,
163             final ResponseHandler<? extends T> responseHandler, final HttpContext context)
164             throws IOException, ClientProtocolException {
165         final HttpHost target = determineTarget(request);
166         return execute(target, request, responseHandler, context);
167     }
168 
169     /**
170      * Executes a request using the default context and processes the
171      * response using the given response handler. The content entity associated
172      * with the response is fully consumed and the underlying connection is
173      * released back to the connection manager automatically in all cases
174      * relieving individual {@link ResponseHandler}s from having to manage
175      * resource deallocation internally.
176      *
177      * @param target    the target host for the request.
178      *                  Implementations may accept <code>null</code>
179      *                  if they can still determine a route, for example
180      *                  to a default target or by inspecting the request.
181      * @param request   the request to execute
182      * @param responseHandler the response handler
183      *
184      * @return  the response object as generated by the response handler.
185      * @throws IOException in case of a problem or the connection was aborted
186      * @throws ClientProtocolException in case of an http protocol error
187      */
188     @Override
189     public <T> T execute(final HttpHost target, final HttpRequest request,
190             final ResponseHandler<? extends T> responseHandler) throws IOException,
191             ClientProtocolException {
192         return execute(target, request, responseHandler, null);
193     }
194 
195     /**
196      * Executes a request using the default context and processes the
197      * response using the given response handler. The content entity associated
198      * with the response is fully consumed and the underlying connection is
199      * released back to the connection manager automatically in all cases
200      * relieving individual {@link ResponseHandler}s from having to manage
201      * resource deallocation internally.
202      *
203      * @param target    the target host for the request.
204      *                  Implementations may accept <code>null</code>
205      *                  if they can still determine a route, for example
206      *                  to a default target or by inspecting the request.
207      * @param request   the request to execute
208      * @param responseHandler the response handler
209      * @param context   the context to use for the execution, or
210      *                  <code>null</code> to use the default context
211      *
212      * @return  the response object as generated by the response handler.
213      * @throws IOException in case of a problem or the connection was aborted
214      * @throws ClientProtocolException in case of an http protocol error
215      */
216     @Override
217     public <T> T execute(final HttpHost target, final HttpRequest request,
218             final ResponseHandler<? extends T> responseHandler, final HttpContext context)
219             throws IOException, ClientProtocolException {
220         Args.notNull(responseHandler, "Response handler");
221 
222         final HttpResponse response = execute(target, request, context);
223 
224         final T result;
225         try {
226             result = responseHandler.handleResponse(response);
227         } catch (final Exception t) {
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             if (t instanceof RuntimeException) {
237                 throw (RuntimeException) t;
238             }
239             if (t instanceof IOException) {
240                 throw (IOException) t;
241             }
242             throw new UndeclaredThrowableException(t);
243         }
244 
245         // Handling the response was successful. Ensure that the content has
246         // been fully consumed.
247         final HttpEntity entity = response.getEntity();
248         EntityUtils.consume(entity);
249         return result;
250     }
251 
252 }