Home | History | Annotate | Download | only in client
      1 /*
      2  * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/AbstractHttpClient.java $
      3  * $Revision: 677250 $
      4  * $Date: 2008-07-16 04:45:47 -0700 (Wed, 16 Jul 2008) $
      5  *
      6  * ====================================================================
      7  * Licensed to the Apache Software Foundation (ASF) under one
      8  * or more contributor license agreements.  See the NOTICE file
      9  * distributed with this work for additional information
     10  * regarding copyright ownership.  The ASF licenses this file
     11  * to you under the Apache License, Version 2.0 (the
     12  * "License"); you may not use this file except in compliance
     13  * with the License.  You may obtain a copy of the License at
     14  *
     15  *   http://www.apache.org/licenses/LICENSE-2.0
     16  *
     17  * Unless required by applicable law or agreed to in writing,
     18  * software distributed under the License is distributed on an
     19  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     20  * KIND, either express or implied.  See the License for the
     21  * specific language governing permissions and limitations
     22  * under the License.
     23  * ====================================================================
     24  *
     25  * This software consists of voluntary contributions made by many
     26  * individuals on behalf of the Apache Software Foundation.  For more
     27  * information on the Apache Software Foundation, please see
     28  * <http://www.apache.org/>.
     29  *
     30  */
     31 
     32 package org.apache.http.impl.client;
     33 
     34 import java.io.IOException;
     35 import java.net.URI;
     36 import java.lang.reflect.UndeclaredThrowableException;
     37 
     38 import org.apache.commons.logging.Log;
     39 import org.apache.commons.logging.LogFactory;
     40 import org.apache.http.ConnectionReuseStrategy;
     41 import org.apache.http.HttpException;
     42 import org.apache.http.HttpHost;
     43 import org.apache.http.HttpRequest;
     44 import org.apache.http.HttpRequestInterceptor;
     45 import org.apache.http.HttpResponse;
     46 import org.apache.http.HttpResponseInterceptor;
     47 import org.apache.http.HttpEntity;
     48 import org.apache.http.auth.AuthSchemeRegistry;
     49 import org.apache.http.client.AuthenticationHandler;
     50 import org.apache.http.client.ClientProtocolException;
     51 import org.apache.http.client.RequestDirector;
     52 import org.apache.http.client.ResponseHandler;
     53 import org.apache.http.client.CookieStore;
     54 import org.apache.http.client.CredentialsProvider;
     55 import org.apache.http.client.HttpClient;
     56 import org.apache.http.client.HttpRequestRetryHandler;
     57 import org.apache.http.client.RedirectHandler;
     58 import org.apache.http.client.UserTokenHandler;
     59 import org.apache.http.client.methods.HttpUriRequest;
     60 import org.apache.http.conn.ClientConnectionManager;
     61 import org.apache.http.conn.ConnectionKeepAliveStrategy;
     62 import org.apache.http.conn.routing.HttpRoutePlanner;
     63 import org.apache.http.cookie.CookieSpecRegistry;
     64 import org.apache.http.params.HttpParams;
     65 import org.apache.http.protocol.BasicHttpProcessor;
     66 import org.apache.http.protocol.DefaultedHttpContext;
     67 import org.apache.http.protocol.HttpContext;
     68 import org.apache.http.protocol.HttpProcessor;
     69 import org.apache.http.protocol.HttpRequestExecutor;
     70 
     71 /**
     72  * Convenience base class for HTTP client implementations.
     73  *
     74  * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
     75  * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
     76  *
     77  * <!-- empty lines to avoid svn diff problems -->
     78  * @version   $Revision: 677250 $
     79  *
     80  * @since 4.0
     81  */
     82 public abstract class AbstractHttpClient implements HttpClient {
     83 
     84     private final Log log = LogFactory.getLog(getClass());
     85 
     86     /** The parameters. */
     87     private HttpParams defaultParams;
     88 
     89     /** The request executor. */
     90     private HttpRequestExecutor requestExec;
     91 
     92     /** The connection manager. */
     93     private ClientConnectionManager connManager;
     94 
     95     /** The connection re-use strategy. */
     96     private ConnectionReuseStrategy reuseStrategy;
     97 
     98     /** The connection keep-alive strategy. */
     99     private ConnectionKeepAliveStrategy keepAliveStrategy;
    100 
    101     /** The cookie spec registry. */
    102     private CookieSpecRegistry supportedCookieSpecs;
    103 
    104     /** The authentication scheme registry. */
    105     private AuthSchemeRegistry supportedAuthSchemes;
    106 
    107     /** The HTTP processor. */
    108     private BasicHttpProcessor httpProcessor;
    109 
    110     /** The request retry handler. */
    111     private HttpRequestRetryHandler retryHandler;
    112 
    113     /** The redirect handler. */
    114     private RedirectHandler redirectHandler;
    115 
    116     /** The target authentication handler. */
    117     private AuthenticationHandler targetAuthHandler;
    118 
    119     /** The proxy authentication handler. */
    120     private AuthenticationHandler proxyAuthHandler;
    121 
    122     /** The cookie store. */
    123     private CookieStore cookieStore;
    124 
    125     /** The credentials provider. */
    126     private CredentialsProvider credsProvider;
    127 
    128     /** The route planner. */
    129     private HttpRoutePlanner routePlanner;
    130 
    131     /** The user token handler. */
    132     private UserTokenHandler userTokenHandler;
    133 
    134 
    135     /**
    136      * Creates a new HTTP client.
    137      *
    138      * @param conman    the connection manager
    139      * @param params    the parameters
    140      */
    141     protected AbstractHttpClient(
    142             final ClientConnectionManager conman,
    143             final HttpParams params) {
    144         defaultParams        = params;
    145         connManager          = conman;
    146     } // constructor
    147 
    148     protected abstract HttpParams createHttpParams();
    149 
    150 
    151     protected abstract HttpContext createHttpContext();
    152 
    153 
    154     protected abstract HttpRequestExecutor createRequestExecutor();
    155 
    156 
    157     protected abstract ClientConnectionManager createClientConnectionManager();
    158 
    159 
    160     protected abstract AuthSchemeRegistry createAuthSchemeRegistry();
    161 
    162 
    163     protected abstract CookieSpecRegistry createCookieSpecRegistry();
    164 
    165 
    166     protected abstract ConnectionReuseStrategy createConnectionReuseStrategy();
    167 
    168 
    169     protected abstract ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy();
    170 
    171 
    172     protected abstract BasicHttpProcessor createHttpProcessor();
    173 
    174 
    175     protected abstract HttpRequestRetryHandler createHttpRequestRetryHandler();
    176 
    177 
    178     protected abstract RedirectHandler createRedirectHandler();
    179 
    180 
    181     protected abstract AuthenticationHandler createTargetAuthenticationHandler();
    182 
    183 
    184     protected abstract AuthenticationHandler createProxyAuthenticationHandler();
    185 
    186 
    187     protected abstract CookieStore createCookieStore();
    188 
    189 
    190     protected abstract CredentialsProvider createCredentialsProvider();
    191 
    192 
    193     protected abstract HttpRoutePlanner createHttpRoutePlanner();
    194 
    195 
    196     protected abstract UserTokenHandler createUserTokenHandler();
    197 
    198 
    199     // non-javadoc, see interface HttpClient
    200     public synchronized final HttpParams getParams() {
    201         if (defaultParams == null) {
    202             defaultParams = createHttpParams();
    203         }
    204         return defaultParams;
    205     }
    206 
    207 
    208     /**
    209      * Replaces the parameters.
    210      * The implementation here does not update parameters of dependent objects.
    211      *
    212      * @param params    the new default parameters
    213      */
    214     public synchronized void setParams(HttpParams params) {
    215         defaultParams = params;
    216     }
    217 
    218 
    219     public synchronized final ClientConnectionManager getConnectionManager() {
    220         if (connManager == null) {
    221             connManager = createClientConnectionManager();
    222         }
    223         return connManager;
    224     }
    225 
    226 
    227     public synchronized final HttpRequestExecutor getRequestExecutor() {
    228         if (requestExec == null) {
    229             requestExec = createRequestExecutor();
    230         }
    231         return requestExec;
    232     }
    233 
    234 
    235     public synchronized final AuthSchemeRegistry getAuthSchemes() {
    236         if (supportedAuthSchemes == null) {
    237             supportedAuthSchemes = createAuthSchemeRegistry();
    238         }
    239         return supportedAuthSchemes;
    240     }
    241 
    242 
    243     public synchronized void setAuthSchemes(final AuthSchemeRegistry authSchemeRegistry) {
    244         supportedAuthSchemes = authSchemeRegistry;
    245     }
    246 
    247 
    248     public synchronized final CookieSpecRegistry getCookieSpecs() {
    249         if (supportedCookieSpecs == null) {
    250             supportedCookieSpecs = createCookieSpecRegistry();
    251         }
    252         return supportedCookieSpecs;
    253     }
    254 
    255 
    256     public synchronized void setCookieSpecs(final CookieSpecRegistry cookieSpecRegistry) {
    257         supportedCookieSpecs = cookieSpecRegistry;
    258     }
    259 
    260 
    261     public synchronized final ConnectionReuseStrategy getConnectionReuseStrategy() {
    262         if (reuseStrategy == null) {
    263             reuseStrategy = createConnectionReuseStrategy();
    264         }
    265         return reuseStrategy;
    266     }
    267 
    268 
    269     public synchronized void setReuseStrategy(final ConnectionReuseStrategy reuseStrategy) {
    270         this.reuseStrategy = reuseStrategy;
    271     }
    272 
    273 
    274     public synchronized final ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() {
    275         if (keepAliveStrategy == null) {
    276             keepAliveStrategy = createConnectionKeepAliveStrategy();
    277         }
    278         return keepAliveStrategy;
    279     }
    280 
    281 
    282     public synchronized void setKeepAliveStrategy(final ConnectionKeepAliveStrategy keepAliveStrategy) {
    283         this.keepAliveStrategy = keepAliveStrategy;
    284     }
    285 
    286 
    287     public synchronized final HttpRequestRetryHandler getHttpRequestRetryHandler() {
    288         if (retryHandler == null) {
    289             retryHandler = createHttpRequestRetryHandler();
    290         }
    291         return retryHandler;
    292     }
    293 
    294 
    295     public synchronized void setHttpRequestRetryHandler(final HttpRequestRetryHandler retryHandler) {
    296         this.retryHandler = retryHandler;
    297     }
    298 
    299 
    300     public synchronized final RedirectHandler getRedirectHandler() {
    301         if (redirectHandler == null) {
    302             redirectHandler = createRedirectHandler();
    303         }
    304         return redirectHandler;
    305     }
    306 
    307 
    308     public synchronized void setRedirectHandler(final RedirectHandler redirectHandler) {
    309         this.redirectHandler = redirectHandler;
    310     }
    311 
    312 
    313     public synchronized final AuthenticationHandler getTargetAuthenticationHandler() {
    314         if (targetAuthHandler == null) {
    315             targetAuthHandler = createTargetAuthenticationHandler();
    316         }
    317         return targetAuthHandler;
    318     }
    319 
    320 
    321     public synchronized void setTargetAuthenticationHandler(
    322             final AuthenticationHandler targetAuthHandler) {
    323         this.targetAuthHandler = targetAuthHandler;
    324     }
    325 
    326 
    327     public synchronized final AuthenticationHandler getProxyAuthenticationHandler() {
    328         if (proxyAuthHandler == null) {
    329             proxyAuthHandler = createProxyAuthenticationHandler();
    330         }
    331         return proxyAuthHandler;
    332     }
    333 
    334 
    335     public synchronized void setProxyAuthenticationHandler(
    336             final AuthenticationHandler proxyAuthHandler) {
    337         this.proxyAuthHandler = proxyAuthHandler;
    338     }
    339 
    340 
    341     public synchronized final CookieStore getCookieStore() {
    342         if (cookieStore == null) {
    343             cookieStore = createCookieStore();
    344         }
    345         return cookieStore;
    346     }
    347 
    348 
    349     public synchronized void setCookieStore(final CookieStore cookieStore) {
    350         this.cookieStore = cookieStore;
    351     }
    352 
    353 
    354     public synchronized final CredentialsProvider getCredentialsProvider() {
    355         if (credsProvider == null) {
    356             credsProvider = createCredentialsProvider();
    357         }
    358         return credsProvider;
    359     }
    360 
    361 
    362     public synchronized void setCredentialsProvider(final CredentialsProvider credsProvider) {
    363         this.credsProvider = credsProvider;
    364     }
    365 
    366 
    367     public synchronized final HttpRoutePlanner getRoutePlanner() {
    368         if (this.routePlanner == null) {
    369             this.routePlanner = createHttpRoutePlanner();
    370         }
    371         return this.routePlanner;
    372     }
    373 
    374 
    375     public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) {
    376         this.routePlanner = routePlanner;
    377     }
    378 
    379 
    380     public synchronized final UserTokenHandler getUserTokenHandler() {
    381         if (this.userTokenHandler == null) {
    382             this.userTokenHandler = createUserTokenHandler();
    383         }
    384         return this.userTokenHandler;
    385     }
    386 
    387 
    388     public synchronized void setUserTokenHandler(final UserTokenHandler userTokenHandler) {
    389         this.userTokenHandler = userTokenHandler;
    390     }
    391 
    392 
    393     protected synchronized final BasicHttpProcessor getHttpProcessor() {
    394         if (httpProcessor == null) {
    395             httpProcessor = createHttpProcessor();
    396         }
    397         return httpProcessor;
    398     }
    399 
    400 
    401     public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp) {
    402         getHttpProcessor().addInterceptor(itcp);
    403     }
    404 
    405 
    406     public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp, int index) {
    407         getHttpProcessor().addInterceptor(itcp, index);
    408     }
    409 
    410 
    411     public synchronized HttpResponseInterceptor getResponseInterceptor(int index) {
    412         return getHttpProcessor().getResponseInterceptor(index);
    413     }
    414 
    415 
    416     public synchronized int getResponseInterceptorCount() {
    417         return getHttpProcessor().getResponseInterceptorCount();
    418     }
    419 
    420 
    421     public synchronized void clearResponseInterceptors() {
    422         getHttpProcessor().clearResponseInterceptors();
    423     }
    424 
    425 
    426     public void removeResponseInterceptorByClass(Class<? extends HttpResponseInterceptor> clazz) {
    427         getHttpProcessor().removeResponseInterceptorByClass(clazz);
    428     }
    429 
    430 
    431     public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp) {
    432         getHttpProcessor().addInterceptor(itcp);
    433     }
    434 
    435 
    436     public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp, int index) {
    437         getHttpProcessor().addInterceptor(itcp, index);
    438     }
    439 
    440 
    441     public synchronized HttpRequestInterceptor getRequestInterceptor(int index) {
    442         return getHttpProcessor().getRequestInterceptor(index);
    443     }
    444 
    445 
    446     public synchronized int getRequestInterceptorCount() {
    447         return getHttpProcessor().getRequestInterceptorCount();
    448     }
    449 
    450 
    451     public synchronized void clearRequestInterceptors() {
    452         getHttpProcessor().clearRequestInterceptors();
    453     }
    454 
    455 
    456     public void removeRequestInterceptorByClass(Class<? extends HttpRequestInterceptor> clazz) {
    457         getHttpProcessor().removeRequestInterceptorByClass(clazz);
    458     }
    459 
    460 
    461     // non-javadoc, see interface HttpClient
    462     public final HttpResponse execute(HttpUriRequest request)
    463         throws IOException, ClientProtocolException {
    464 
    465         return execute(request, (HttpContext) null);
    466     }
    467 
    468 
    469     /**
    470      * Maps to {@link HttpClient#execute(HttpHost,HttpRequest,HttpContext)
    471      *                           execute(target, request, context)}.
    472      * The target is determined from the URI of the request.
    473      *
    474      * @param request   the request to execute
    475      * @param context   the request-specific execution context,
    476      *                  or <code>null</code> to use a default context
    477      */
    478     public final HttpResponse execute(HttpUriRequest request,
    479                                       HttpContext context)
    480         throws IOException, ClientProtocolException {
    481 
    482         if (request == null) {
    483             throw new IllegalArgumentException
    484                 ("Request must not be null.");
    485         }
    486 
    487         return execute(determineTarget(request), request, context);
    488     }
    489 
    490     private HttpHost determineTarget(HttpUriRequest request) {
    491         // A null target may be acceptable if there is a default target.
    492         // Otherwise, the null target is detected in the director.
    493         HttpHost target = null;
    494 
    495         URI requestURI = request.getURI();
    496         if (requestURI.isAbsolute()) {
    497             target = new HttpHost(
    498                     requestURI.getHost(),
    499                     requestURI.getPort(),
    500                     requestURI.getScheme());
    501         }
    502         return target;
    503     }
    504 
    505     // non-javadoc, see interface HttpClient
    506     public final HttpResponse execute(HttpHost target, HttpRequest request)
    507         throws IOException, ClientProtocolException {
    508 
    509         return execute(target, request, (HttpContext) null);
    510     }
    511 
    512 
    513     // non-javadoc, see interface HttpClient
    514     public final HttpResponse execute(HttpHost target, HttpRequest request,
    515                                       HttpContext context)
    516         throws IOException, ClientProtocolException {
    517 
    518         if (request == null) {
    519             throw new IllegalArgumentException
    520                 ("Request must not be null.");
    521         }
    522         // a null target may be acceptable, this depends on the route planner
    523         // a null context is acceptable, default context created below
    524 
    525         HttpContext execContext = null;
    526         RequestDirector director = null;
    527 
    528         // Initialize the request execution context making copies of
    529         // all shared objects that are potentially threading unsafe.
    530         synchronized (this) {
    531 
    532             HttpContext defaultContext = createHttpContext();
    533             if (context == null) {
    534                 execContext = defaultContext;
    535             } else {
    536                 execContext = new DefaultedHttpContext(context, defaultContext);
    537             }
    538             // Create a director for this request
    539             director = createClientRequestDirector(
    540                     getRequestExecutor(),
    541                     getConnectionManager(),
    542                     getConnectionReuseStrategy(),
    543                     getConnectionKeepAliveStrategy(),
    544                     getRoutePlanner(),
    545                     getHttpProcessor().copy(),
    546                     getHttpRequestRetryHandler(),
    547                     getRedirectHandler(),
    548                     getTargetAuthenticationHandler(),
    549                     getProxyAuthenticationHandler(),
    550                     getUserTokenHandler(),
    551                     determineParams(request));
    552         }
    553 
    554         try {
    555             return director.execute(target, request, execContext);
    556         } catch(HttpException httpException) {
    557             throw new ClientProtocolException(httpException);
    558         }
    559     } // execute
    560 
    561 
    562     protected RequestDirector createClientRequestDirector(
    563             final HttpRequestExecutor requestExec,
    564             final ClientConnectionManager conman,
    565             final ConnectionReuseStrategy reustrat,
    566             final ConnectionKeepAliveStrategy kastrat,
    567             final HttpRoutePlanner rouplan,
    568             final HttpProcessor httpProcessor,
    569             final HttpRequestRetryHandler retryHandler,
    570             final RedirectHandler redirectHandler,
    571             final AuthenticationHandler targetAuthHandler,
    572             final AuthenticationHandler proxyAuthHandler,
    573             final UserTokenHandler stateHandler,
    574             final HttpParams params) {
    575         return new DefaultRequestDirector(
    576                 requestExec,
    577                 conman,
    578                 reustrat,
    579                 kastrat,
    580                 rouplan,
    581                 httpProcessor,
    582                 retryHandler,
    583                 redirectHandler,
    584                 targetAuthHandler,
    585                 proxyAuthHandler,
    586                 stateHandler,
    587                 params);
    588     }
    589 
    590     /**
    591      * Obtains parameters for executing a request.
    592      * The default implementation in this class creates a new
    593      * {@link ClientParamsStack} from the request parameters
    594      * and the client parameters.
    595      * <br/>
    596      * This method is called by the default implementation of
    597      * {@link #execute(HttpHost,HttpRequest,HttpContext)}
    598      * to obtain the parameters for the
    599      * {@link DefaultRequestDirector}.
    600      *
    601      * @param req    the request that will be executed
    602      *
    603      * @return  the parameters to use
    604      */
    605     protected HttpParams determineParams(HttpRequest req) {
    606         return new ClientParamsStack
    607             (null, getParams(), req.getParams(), null);
    608     }
    609 
    610 
    611     // non-javadoc, see interface HttpClient
    612     public <T> T execute(
    613             final HttpUriRequest request,
    614             final ResponseHandler<? extends T> responseHandler)
    615                 throws IOException, ClientProtocolException {
    616         return execute(request, responseHandler, null);
    617     }
    618 
    619 
    620     // non-javadoc, see interface HttpClient
    621     public <T> T execute(
    622             final HttpUriRequest request,
    623             final ResponseHandler<? extends T> responseHandler,
    624             final HttpContext context)
    625                 throws IOException, ClientProtocolException {
    626         HttpHost target = determineTarget(request);
    627         return execute(target, request, responseHandler, context);
    628     }
    629 
    630 
    631     // non-javadoc, see interface HttpClient
    632     public <T> T execute(
    633             final HttpHost target,
    634             final HttpRequest request,
    635             final ResponseHandler<? extends T> responseHandler)
    636                 throws IOException, ClientProtocolException {
    637         return execute(target, request, responseHandler, null);
    638     }
    639 
    640 
    641     // non-javadoc, see interface HttpClient
    642     public <T> T execute(
    643             final HttpHost target,
    644             final HttpRequest request,
    645             final ResponseHandler<? extends T> responseHandler,
    646             final HttpContext context)
    647                 throws IOException, ClientProtocolException {
    648         if (responseHandler == null) {
    649             throw new IllegalArgumentException
    650                 ("Response handler must not be null.");
    651         }
    652 
    653         HttpResponse response = execute(target, request, context);
    654 
    655         T result;
    656         try {
    657             result = responseHandler.handleResponse(response);
    658         } catch (Throwable t) {
    659             HttpEntity entity = response.getEntity();
    660             if (entity != null) {
    661                 try {
    662                     entity.consumeContent();
    663                 } catch (Throwable t2) {
    664                     // Log this exception. The original exception is more
    665                     // important and will be thrown to the caller.
    666                     this.log.warn("Error consuming content after an exception.", t2);
    667                 }
    668             }
    669 
    670             if (t instanceof Error) {
    671                 throw (Error) t;
    672             }
    673 
    674             if (t instanceof RuntimeException) {
    675                 throw (RuntimeException) t;
    676             }
    677 
    678             if (t instanceof IOException) {
    679                 throw (IOException) t;
    680             }
    681 
    682             throw new UndeclaredThrowableException(t);
    683         }
    684 
    685         // Handling the response was successful. Ensure that the content has
    686         // been fully consumed.
    687         HttpEntity entity = response.getEntity();
    688         if (entity != null) {
    689             // Let this exception go to the caller.
    690             entity.consumeContent();
    691         }
    692 
    693         return result;
    694     }
    695 
    696 
    697 } // class AbstractHttpClient
    698