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.IOException;
31  import java.lang.reflect.UndeclaredThrowableException;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  import org.apache.http.ConnectionReuseStrategy;
36  import org.apache.http.HttpException;
37  import org.apache.http.HttpHost;
38  import org.apache.http.HttpRequest;
39  import org.apache.http.HttpRequestInterceptor;
40  import org.apache.http.HttpResponseInterceptor;
41  import org.apache.http.annotation.GuardedBy;
42  import org.apache.http.annotation.ThreadSafe;
43  import org.apache.http.auth.AuthSchemeRegistry;
44  import org.apache.http.client.AuthenticationHandler;
45  import org.apache.http.client.AuthenticationStrategy;
46  import org.apache.http.client.BackoffManager;
47  import org.apache.http.client.ClientProtocolException;
48  import org.apache.http.client.ConnectionBackoffStrategy;
49  import org.apache.http.client.CookieStore;
50  import org.apache.http.client.CredentialsProvider;
51  import org.apache.http.client.HttpClient;
52  import org.apache.http.client.HttpRequestRetryHandler;
53  import org.apache.http.client.RedirectHandler;
54  import org.apache.http.client.RedirectStrategy;
55  import org.apache.http.client.RequestDirector;
56  import org.apache.http.client.UserTokenHandler;
57  import org.apache.http.client.config.RequestConfig;
58  import org.apache.http.client.methods.CloseableHttpResponse;
59  import org.apache.http.client.params.AuthPolicy;
60  import org.apache.http.client.params.ClientPNames;
61  import org.apache.http.client.params.CookiePolicy;
62  import org.apache.http.client.params.HttpClientParamConfig;
63  import org.apache.http.client.protocol.ClientContext;
64  import org.apache.http.conn.ClientConnectionManager;
65  import org.apache.http.conn.ClientConnectionManagerFactory;
66  import org.apache.http.conn.ConnectionKeepAliveStrategy;
67  import org.apache.http.conn.routing.HttpRoute;
68  import org.apache.http.conn.routing.HttpRoutePlanner;
69  import org.apache.http.conn.scheme.SchemeRegistry;
70  import org.apache.http.cookie.CookieSpecRegistry;
71  import org.apache.http.impl.DefaultConnectionReuseStrategy;
72  import org.apache.http.impl.auth.BasicSchemeFactory;
73  import org.apache.http.impl.auth.DigestSchemeFactory;
74  import org.apache.http.impl.auth.KerberosSchemeFactory;
75  import org.apache.http.impl.auth.NTLMSchemeFactory;
76  import org.apache.http.impl.auth.SPNegoSchemeFactory;
77  import org.apache.http.impl.conn.BasicClientConnectionManager;
78  import org.apache.http.impl.conn.DefaultHttpRoutePlanner;
79  import org.apache.http.impl.conn.SchemeRegistryFactory;
80  import org.apache.http.impl.cookie.BestMatchSpecFactory;
81  import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
82  import org.apache.http.impl.cookie.IgnoreSpecFactory;
83  import org.apache.http.impl.cookie.NetscapeDraftSpecFactory;
84  import org.apache.http.impl.cookie.RFC2109SpecFactory;
85  import org.apache.http.impl.cookie.RFC2965SpecFactory;
86  import org.apache.http.params.HttpParams;
87  import org.apache.http.protocol.BasicHttpContext;
88  import org.apache.http.protocol.BasicHttpProcessor;
89  import org.apache.http.protocol.DefaultedHttpContext;
90  import org.apache.http.protocol.HttpContext;
91  import org.apache.http.protocol.HttpProcessor;
92  import org.apache.http.protocol.HttpRequestExecutor;
93  import org.apache.http.protocol.ImmutableHttpProcessor;
94  import org.apache.http.util.Args;
95  
96  /**
97   * Base class for {@link HttpClient} implementations. This class acts as
98   * a facade to a number of special purpose handler or strategy
99   * implementations responsible for handling of a particular aspect of
100  * the HTTP protocol such as redirect or authentication handling or
101  * making decision about connection persistence and keep alive duration.
102  * This enables the users to selectively replace default implementation
103  * of those aspects with custom, application specific ones. This class
104  * also provides factory methods to instantiate those objects:
105  * <ul>
106  *   <li>{@link HttpRequestExecutor}</li> object used to transmit messages
107  *    over HTTP connections. The {@link #createRequestExecutor()} must be
108  *    implemented by concrete super classes to instantiate this object.
109  *   <li>{@link BasicHttpProcessor}</li> object to manage a list of protocol
110  *    interceptors and apply cross-cutting protocol logic to all incoming
111  *    and outgoing HTTP messages. The {@link #createHttpProcessor()} must be
112  *    implemented by concrete super classes to instantiate this object.
113  *   <li>{@link HttpRequestRetryHandler}</li> object used to decide whether
114  *    or not a failed HTTP request is safe to retry automatically.
115  *    The {@link #createHttpRequestRetryHandler()} must be
116  *    implemented by concrete super classes to instantiate this object.
117  *   <li>{@link ClientConnectionManager}</li> object used to manage
118  *    persistent HTTP connections.
119  *   <li>{@link ConnectionReuseStrategy}</li> object used to decide whether
120  *    or not a HTTP connection can be kept alive and re-used for subsequent
121  *    HTTP requests. The {@link #createConnectionReuseStrategy()} must be
122  *    implemented by concrete super classes to instantiate this object.
123  *   <li>{@link ConnectionKeepAliveStrategy}</li> object used to decide how
124  *    long a persistent HTTP connection can be kept alive.
125  *    The {@link #createConnectionKeepAliveStrategy()} must be
126  *    implemented by concrete super classes to instantiate this object.
127  *   <li>{@link CookieSpecRegistry}</li> object used to maintain a list of
128  *    supported cookie specifications.
129  *    The {@link #createCookieSpecRegistry()} must be implemented by concrete
130  *    super classes to instantiate this object.
131  *   <li>{@link CookieStore}</li> object used to maintain a collection of
132  *    cookies. The {@link #createCookieStore()} must be implemented by
133  *    concrete super classes to instantiate this object.
134  *   <li>{@link AuthSchemeRegistry}</li> object used to maintain a list of
135  *    supported authentication schemes.
136  *    The {@link #createAuthSchemeRegistry()} must be implemented by concrete
137  *    super classes to instantiate this object.
138  *   <li>{@link CredentialsProvider}</li> object used to maintain
139  *    a collection user credentials. The {@link #createCredentialsProvider()}
140  *    must be implemented by concrete super classes to instantiate
141  *    this object.
142  *   <li>{@link AuthenticationStrategy}</li> object used to authenticate
143  *    against the target host.
144  *    The {@link #createTargetAuthenticationStrategy()} must be implemented
145  *    by concrete super classes to instantiate this object.
146  *   <li>{@link AuthenticationStrategy}</li> object used to authenticate
147  *    against the proxy host.
148  *    The {@link #createProxyAuthenticationStrategy()} must be implemented
149  *    by concrete super classes to instantiate this object.
150  *   <li>{@link HttpRoutePlanner}</li> object used to calculate a route
151  *    for establishing a connection to the target host. The route
152  *    may involve multiple intermediate hops.
153  *    The {@link #createHttpRoutePlanner()} must be implemented
154  *    by concrete super classes to instantiate this object.
155  *   <li>{@link RedirectStrategy}</li> object used to determine if an HTTP
156  *    request should be redirected to a new location in response to an HTTP
157  *    response received from the target server.
158  *   <li>{@link UserTokenHandler}</li> object used to determine if the
159  *    execution context is user identity specific.
160  *    The {@link #createUserTokenHandler()} must be implemented by
161  *    concrete super classes to instantiate this object.
162  * </ul>
163  * <p>
164  *   This class also maintains a list of protocol interceptors intended
165  *   for processing outgoing requests and incoming responses and provides
166  *   methods for managing those interceptors. New protocol interceptors can be
167  *   introduced to the protocol processor chain or removed from it if needed.
168  *   Internally protocol interceptors are stored in a simple
169  *   {@link java.util.ArrayList}. They are executed in the same natural order
170  *   as they are added to the list.
171  * <p>
172  *   AbstractHttpClient is thread safe. It is recommended that the same
173  *   instance of this class is reused for multiple request executions.
174  *   When an instance of DefaultHttpClient is no longer needed and is about
175  *   to go out of scope the connection manager associated with it must be
176  *   shut down by calling {@link ClientConnectionManager#shutdown()}!
177  *
178  * @since 4.0
179  *
180  * @deprecated (4.3) use {@link HttpClientBuilder}.
181  */
182 @ThreadSafe
183 @Deprecated
184 public abstract class AbstractHttpClient extends CloseableHttpClient {
185 
186     private final Log log = LogFactory.getLog(getClass());
187 
188     /** The parameters. */
189     @GuardedBy("this")
190     private HttpParams defaultParams;
191 
192     /** The request executor. */
193     @GuardedBy("this")
194     private HttpRequestExecutor requestExec;
195 
196     /** The connection manager. */
197     @GuardedBy("this")
198     private ClientConnectionManager connManager;
199 
200     /** The connection re-use strategy. */
201     @GuardedBy("this")
202     private ConnectionReuseStrategy reuseStrategy;
203 
204     /** The connection keep-alive strategy. */
205     @GuardedBy("this")
206     private ConnectionKeepAliveStrategy keepAliveStrategy;
207 
208     /** The cookie spec registry. */
209     @GuardedBy("this")
210     private CookieSpecRegistry supportedCookieSpecs;
211 
212     /** The authentication scheme registry. */
213     @GuardedBy("this")
214     private AuthSchemeRegistry supportedAuthSchemes;
215 
216     /** The HTTP protocol processor and its immutable copy. */
217     @GuardedBy("this")
218     private BasicHttpProcessor mutableProcessor;
219 
220     @GuardedBy("this")
221     private ImmutableHttpProcessor protocolProcessor;
222 
223     /** The request retry handler. */
224     @GuardedBy("this")
225     private HttpRequestRetryHandler retryHandler;
226 
227     /** The redirect handler. */
228     @GuardedBy("this")
229     private RedirectStrategy redirectStrategy;
230 
231     /** The target authentication handler. */
232     @GuardedBy("this")
233     private AuthenticationStrategy targetAuthStrategy;
234 
235     /** The proxy authentication handler. */
236     @GuardedBy("this")
237     private AuthenticationStrategy proxyAuthStrategy;
238 
239     /** The cookie store. */
240     @GuardedBy("this")
241     private CookieStore cookieStore;
242 
243     /** The credentials provider. */
244     @GuardedBy("this")
245     private CredentialsProvider credsProvider;
246 
247     /** The route planner. */
248     @GuardedBy("this")
249     private HttpRoutePlanner routePlanner;
250 
251     /** The user token handler. */
252     @GuardedBy("this")
253     private UserTokenHandler userTokenHandler;
254 
255     /** The connection backoff strategy. */
256     @GuardedBy("this")
257     private ConnectionBackoffStrategy connectionBackoffStrategy;
258 
259     /** The backoff manager. */
260     @GuardedBy("this")
261     private BackoffManager backoffManager;
262 
263     /**
264      * Creates a new HTTP client.
265      *
266      * @param conman    the connection manager
267      * @param params    the parameters
268      */
269     protected AbstractHttpClient(
270             final ClientConnectionManager conman,
271             final HttpParams params) {
272         super();
273         defaultParams        = params;
274         connManager          = conman;
275     } // constructor
276 
277 
278     protected abstract HttpParams createHttpParams();
279 
280 
281     protected abstract BasicHttpProcessor createHttpProcessor();
282 
283 
284     protected HttpContext createHttpContext() {
285         final HttpContext context = new BasicHttpContext();
286         context.setAttribute(
287                 ClientContext.SCHEME_REGISTRY,
288                 getConnectionManager().getSchemeRegistry());
289         context.setAttribute(
290                 ClientContext.AUTHSCHEME_REGISTRY,
291                 getAuthSchemes());
292         context.setAttribute(
293                 ClientContext.COOKIESPEC_REGISTRY,
294                 getCookieSpecs());
295         context.setAttribute(
296                 ClientContext.COOKIE_STORE,
297                 getCookieStore());
298         context.setAttribute(
299                 ClientContext.CREDS_PROVIDER,
300                 getCredentialsProvider());
301         return context;
302     }
303 
304 
305     protected ClientConnectionManager createClientConnectionManager() {
306         final SchemeRegistry registry = SchemeRegistryFactory.createDefault();
307 
308         ClientConnectionManager connManager = null;
309         final HttpParams params = getParams();
310 
311         ClientConnectionManagerFactory factory = null;
312 
313         final String className = (String) params.getParameter(
314                 ClientPNames.CONNECTION_MANAGER_FACTORY_CLASS_NAME);
315         if (className != null) {
316             try {
317                 final Class<?> clazz = Class.forName(className);
318                 factory = (ClientConnectionManagerFactory) clazz.newInstance();
319             } catch (final ClassNotFoundException ex) {
320                 throw new IllegalStateException("Invalid class name: " + className);
321             } catch (final IllegalAccessException ex) {
322                 throw new IllegalAccessError(ex.getMessage());
323             } catch (final InstantiationException ex) {
324                 throw new InstantiationError(ex.getMessage());
325             }
326         }
327         if (factory != null) {
328             connManager = factory.newInstance(params, registry);
329         } else {
330             connManager = new BasicClientConnectionManager(registry);
331         }
332 
333         return connManager;
334     }
335 
336 
337     protected AuthSchemeRegistry createAuthSchemeRegistry() {
338         final AuthSchemeRegistry registry = new AuthSchemeRegistry();
339         registry.register(
340                 AuthPolicy.BASIC,
341                 new BasicSchemeFactory());
342         registry.register(
343                 AuthPolicy.DIGEST,
344                 new DigestSchemeFactory());
345         registry.register(
346                 AuthPolicy.NTLM,
347                 new NTLMSchemeFactory());
348         registry.register(
349                 AuthPolicy.SPNEGO,
350                 new SPNegoSchemeFactory());
351         registry.register(
352                 AuthPolicy.KERBEROS,
353                 new KerberosSchemeFactory());
354         return registry;
355     }
356 
357 
358     protected CookieSpecRegistry createCookieSpecRegistry() {
359         final CookieSpecRegistry registry = new CookieSpecRegistry();
360         registry.register(
361                 CookiePolicy.BEST_MATCH,
362                 new BestMatchSpecFactory());
363         registry.register(
364                 CookiePolicy.BROWSER_COMPATIBILITY,
365                 new BrowserCompatSpecFactory());
366         registry.register(
367                 CookiePolicy.NETSCAPE,
368                 new NetscapeDraftSpecFactory());
369         registry.register(
370                 CookiePolicy.RFC_2109,
371                 new RFC2109SpecFactory());
372         registry.register(
373                 CookiePolicy.RFC_2965,
374                 new RFC2965SpecFactory());
375         registry.register(
376                 CookiePolicy.IGNORE_COOKIES,
377                 new IgnoreSpecFactory());
378         return registry;
379     }
380 
381     protected HttpRequestExecutor createRequestExecutor() {
382         return new HttpRequestExecutor();
383     }
384 
385     protected ConnectionReuseStrategy createConnectionReuseStrategy() {
386         return new DefaultConnectionReuseStrategy();
387     }
388 
389     protected ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy() {
390         return new DefaultConnectionKeepAliveStrategy();
391     }
392 
393     protected HttpRequestRetryHandler createHttpRequestRetryHandler() {
394         return new DefaultHttpRequestRetryHandler();
395     }
396 
397     /**
398      * @deprecated (4.1) do not use
399      */
400     @Deprecated
401     protected RedirectHandler createRedirectHandler() {
402         return new DefaultRedirectHandler();
403     }
404 
405     protected AuthenticationStrategy createTargetAuthenticationStrategy() {
406         return new TargetAuthenticationStrategy();
407     }
408 
409     /**
410      * @deprecated (4.2) do not use
411      */
412     @Deprecated
413     protected AuthenticationHandler createTargetAuthenticationHandler() {
414         return new DefaultTargetAuthenticationHandler();
415     }
416 
417     protected AuthenticationStrategy createProxyAuthenticationStrategy() {
418         return new ProxyAuthenticationStrategy();
419     }
420 
421     /**
422      * @deprecated (4.2) do not use
423      */
424     @Deprecated
425     protected AuthenticationHandler createProxyAuthenticationHandler() {
426         return new DefaultProxyAuthenticationHandler();
427     }
428 
429     protected CookieStore createCookieStore() {
430         return new BasicCookieStore();
431     }
432 
433     protected CredentialsProvider createCredentialsProvider() {
434         return new BasicCredentialsProvider();
435     }
436 
437     protected HttpRoutePlanner createHttpRoutePlanner() {
438         return new DefaultHttpRoutePlanner(getConnectionManager().getSchemeRegistry());
439     }
440 
441     protected UserTokenHandler createUserTokenHandler() {
442         return new DefaultUserTokenHandler();
443     }
444 
445     // non-javadoc, see interface HttpClient
446     public synchronized final HttpParams getParams() {
447         if (defaultParams == null) {
448             defaultParams = createHttpParams();
449         }
450         return defaultParams;
451     }
452 
453     /**
454      * Replaces the parameters.
455      * The implementation here does not update parameters of dependent objects.
456      *
457      * @param params    the new default parameters
458      */
459     public synchronized void setParams(final HttpParams params) {
460         defaultParams = params;
461     }
462 
463 
464     public synchronized final ClientConnectionManager getConnectionManager() {
465         if (connManager == null) {
466             connManager = createClientConnectionManager();
467         }
468         return connManager;
469     }
470 
471 
472     public synchronized final HttpRequestExecutor getRequestExecutor() {
473         if (requestExec == null) {
474             requestExec = createRequestExecutor();
475         }
476         return requestExec;
477     }
478 
479 
480     public synchronized final AuthSchemeRegistry getAuthSchemes() {
481         if (supportedAuthSchemes == null) {
482             supportedAuthSchemes = createAuthSchemeRegistry();
483         }
484         return supportedAuthSchemes;
485     }
486 
487     public synchronized void setAuthSchemes(final AuthSchemeRegistry registry) {
488         supportedAuthSchemes = registry;
489     }
490 
491     public synchronized final ConnectionBackoffStrategy getConnectionBackoffStrategy() {
492         return connectionBackoffStrategy;
493     }
494 
495     public synchronized void setConnectionBackoffStrategy(final ConnectionBackoffStrategy strategy) {
496         connectionBackoffStrategy = strategy;
497     }
498 
499     public synchronized final CookieSpecRegistry getCookieSpecs() {
500         if (supportedCookieSpecs == null) {
501             supportedCookieSpecs = createCookieSpecRegistry();
502         }
503         return supportedCookieSpecs;
504     }
505 
506     public synchronized final BackoffManager getBackoffManager() {
507         return backoffManager;
508     }
509 
510     public synchronized void setBackoffManager(final BackoffManager manager) {
511         backoffManager = manager;
512     }
513 
514     public synchronized void setCookieSpecs(final CookieSpecRegistry registry) {
515         supportedCookieSpecs = registry;
516     }
517 
518     public synchronized final ConnectionReuseStrategy getConnectionReuseStrategy() {
519         if (reuseStrategy == null) {
520             reuseStrategy = createConnectionReuseStrategy();
521         }
522         return reuseStrategy;
523     }
524 
525 
526     public synchronized void setReuseStrategy(final ConnectionReuseStrategy strategy) {
527         this.reuseStrategy = strategy;
528     }
529 
530 
531     public synchronized final ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() {
532         if (keepAliveStrategy == null) {
533             keepAliveStrategy = createConnectionKeepAliveStrategy();
534         }
535         return keepAliveStrategy;
536     }
537 
538 
539     public synchronized void setKeepAliveStrategy(final ConnectionKeepAliveStrategy strategy) {
540         this.keepAliveStrategy = strategy;
541     }
542 
543 
544     public synchronized final HttpRequestRetryHandler getHttpRequestRetryHandler() {
545         if (retryHandler == null) {
546             retryHandler = createHttpRequestRetryHandler();
547         }
548         return retryHandler;
549     }
550 
551     public synchronized void setHttpRequestRetryHandler(final HttpRequestRetryHandler handler) {
552         this.retryHandler = handler;
553     }
554 
555     /**
556      * @deprecated (4.1) do not use
557      */
558     @Deprecated
559     public synchronized final RedirectHandler getRedirectHandler() {
560         return createRedirectHandler();
561     }
562 
563     /**
564      * @deprecated (4.1) do not use
565      */
566     @Deprecated
567     public synchronized void setRedirectHandler(final RedirectHandler handler) {
568         this.redirectStrategy = new DefaultRedirectStrategyAdaptor(handler);
569     }
570 
571     /**
572      * @since 4.1
573      */
574     public synchronized final RedirectStrategy getRedirectStrategy() {
575         if (redirectStrategy == null) {
576             redirectStrategy = new DefaultRedirectStrategy();
577         }
578         return redirectStrategy;
579     }
580 
581     /**
582      * @since 4.1
583      */
584     public synchronized void setRedirectStrategy(final RedirectStrategy strategy) {
585         this.redirectStrategy = strategy;
586     }
587 
588     /**
589      * @deprecated (4.2) do not use
590      */
591     @Deprecated
592     public synchronized final AuthenticationHandler getTargetAuthenticationHandler() {
593         return createTargetAuthenticationHandler();
594     }
595 
596     /**
597      * @deprecated (4.2) do not use
598      */
599     @Deprecated
600     public synchronized void setTargetAuthenticationHandler(final AuthenticationHandler handler) {
601         this.targetAuthStrategy = new AuthenticationStrategyAdaptor(handler);
602     }
603 
604     /**
605      * @since 4.2
606      */
607     public synchronized final AuthenticationStrategy getTargetAuthenticationStrategy() {
608         if (targetAuthStrategy == null) {
609             targetAuthStrategy = createTargetAuthenticationStrategy();
610         }
611         return targetAuthStrategy;
612     }
613 
614     /**
615      * @since 4.2
616      */
617     public synchronized void setTargetAuthenticationStrategy(final AuthenticationStrategy strategy) {
618         this.targetAuthStrategy = strategy;
619     }
620 
621     /**
622      * @deprecated (4.2) do not use
623      */
624     @Deprecated
625     public synchronized final AuthenticationHandler getProxyAuthenticationHandler() {
626         return createProxyAuthenticationHandler();
627     }
628 
629     /**
630      * @deprecated (4.2) do not use
631      */
632     @Deprecated
633     public synchronized void setProxyAuthenticationHandler(final AuthenticationHandler handler) {
634         this.proxyAuthStrategy = new AuthenticationStrategyAdaptor(handler);
635     }
636 
637     /**
638      * @since 4.2
639      */
640     public synchronized final AuthenticationStrategy getProxyAuthenticationStrategy() {
641         if (proxyAuthStrategy == null) {
642             proxyAuthStrategy = createProxyAuthenticationStrategy();
643         }
644         return proxyAuthStrategy;
645     }
646 
647     /**
648      * @since 4.2
649      */
650     public synchronized void setProxyAuthenticationStrategy(final AuthenticationStrategy strategy) {
651         this.proxyAuthStrategy = strategy;
652     }
653 
654     public synchronized final CookieStore getCookieStore() {
655         if (cookieStore == null) {
656             cookieStore = createCookieStore();
657         }
658         return cookieStore;
659     }
660 
661     public synchronized void setCookieStore(final CookieStore cookieStore) {
662         this.cookieStore = cookieStore;
663     }
664 
665     public synchronized final CredentialsProvider getCredentialsProvider() {
666         if (credsProvider == null) {
667             credsProvider = createCredentialsProvider();
668         }
669         return credsProvider;
670     }
671 
672     public synchronized void setCredentialsProvider(final CredentialsProvider credsProvider) {
673         this.credsProvider = credsProvider;
674     }
675 
676     public synchronized final HttpRoutePlanner getRoutePlanner() {
677         if (this.routePlanner == null) {
678             this.routePlanner = createHttpRoutePlanner();
679         }
680         return this.routePlanner;
681     }
682 
683     public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) {
684         this.routePlanner = routePlanner;
685     }
686 
687     public synchronized final UserTokenHandler getUserTokenHandler() {
688         if (this.userTokenHandler == null) {
689             this.userTokenHandler = createUserTokenHandler();
690         }
691         return this.userTokenHandler;
692     }
693 
694     public synchronized void setUserTokenHandler(final UserTokenHandler handler) {
695         this.userTokenHandler = handler;
696     }
697 
698     protected synchronized final BasicHttpProcessor getHttpProcessor() {
699         if (mutableProcessor == null) {
700             mutableProcessor = createHttpProcessor();
701         }
702         return mutableProcessor;
703     }
704 
705     private synchronized final HttpProcessor getProtocolProcessor() {
706         if (protocolProcessor == null) {
707             // Get mutable HTTP processor
708             final BasicHttpProcessor proc = getHttpProcessor();
709             // and create an immutable copy of it
710             final int reqc = proc.getRequestInterceptorCount();
711             final HttpRequestInterceptor[] reqinterceptors = new HttpRequestInterceptor[reqc];
712             for (int i = 0; i < reqc; i++) {
713                 reqinterceptors[i] = proc.getRequestInterceptor(i);
714             }
715             final int resc = proc.getResponseInterceptorCount();
716             final HttpResponseInterceptor[] resinterceptors = new HttpResponseInterceptor[resc];
717             for (int i = 0; i < resc; i++) {
718                 resinterceptors[i] = proc.getResponseInterceptor(i);
719             }
720             protocolProcessor = new ImmutableHttpProcessor(reqinterceptors, resinterceptors);
721         }
722         return protocolProcessor;
723     }
724 
725     public synchronized int getResponseInterceptorCount() {
726         return getHttpProcessor().getResponseInterceptorCount();
727     }
728 
729     public synchronized HttpResponseInterceptor getResponseInterceptor(final int index) {
730         return getHttpProcessor().getResponseInterceptor(index);
731     }
732 
733     public synchronized HttpRequestInterceptor getRequestInterceptor(final int index) {
734         return getHttpProcessor().getRequestInterceptor(index);
735     }
736 
737     public synchronized int getRequestInterceptorCount() {
738         return getHttpProcessor().getRequestInterceptorCount();
739     }
740 
741     public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp) {
742         getHttpProcessor().addInterceptor(itcp);
743         protocolProcessor = null;
744     }
745 
746     public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp, final int index) {
747         getHttpProcessor().addInterceptor(itcp, index);
748         protocolProcessor = null;
749     }
750 
751     public synchronized void clearResponseInterceptors() {
752         getHttpProcessor().clearResponseInterceptors();
753         protocolProcessor = null;
754     }
755 
756     public synchronized void removeResponseInterceptorByClass(final Class<? extends HttpResponseInterceptor> clazz) {
757         getHttpProcessor().removeResponseInterceptorByClass(clazz);
758         protocolProcessor = null;
759     }
760 
761     public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp) {
762         getHttpProcessor().addInterceptor(itcp);
763         protocolProcessor = null;
764     }
765 
766     public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp, final int index) {
767         getHttpProcessor().addInterceptor(itcp, index);
768         protocolProcessor = null;
769     }
770 
771     public synchronized void clearRequestInterceptors() {
772         getHttpProcessor().clearRequestInterceptors();
773         protocolProcessor = null;
774     }
775 
776     public synchronized void removeRequestInterceptorByClass(final Class<? extends HttpRequestInterceptor> clazz) {
777         getHttpProcessor().removeRequestInterceptorByClass(clazz);
778         protocolProcessor = null;
779     }
780 
781     @Override
782     protected final CloseableHttpResponse doExecute(final HttpHost target, final HttpRequest request,
783                                       final HttpContext context)
784         throws IOException, ClientProtocolException {
785 
786         Args.notNull(request, "HTTP request");
787         // a null target may be acceptable, this depends on the route planner
788         // a null context is acceptable, default context created below
789 
790         HttpContext execContext = null;
791         RequestDirector director = null;
792         HttpRoutePlanner routePlanner = null;
793         ConnectionBackoffStrategy connectionBackoffStrategy = null;
794         BackoffManager backoffManager = null;
795 
796         // Initialize the request execution context making copies of
797         // all shared objects that are potentially threading unsafe.
798         synchronized (this) {
799 
800             final HttpContext defaultContext = createHttpContext();
801             if (context == null) {
802                 execContext = defaultContext;
803             } else {
804                 execContext = new DefaultedHttpContext(context, defaultContext);
805             }
806             final HttpParams params = determineParams(request);
807             final RequestConfig config = HttpClientParamConfig.getRequestConfig(params);
808             execContext.setAttribute(ClientContext.REQUEST_CONFIG, config);
809 
810             // Create a director for this request
811             director = createClientRequestDirector(
812                     getRequestExecutor(),
813                     getConnectionManager(),
814                     getConnectionReuseStrategy(),
815                     getConnectionKeepAliveStrategy(),
816                     getRoutePlanner(),
817                     getProtocolProcessor(),
818                     getHttpRequestRetryHandler(),
819                     getRedirectStrategy(),
820                     getTargetAuthenticationStrategy(),
821                     getProxyAuthenticationStrategy(),
822                     getUserTokenHandler(),
823                     params);
824             routePlanner = getRoutePlanner();
825             connectionBackoffStrategy = getConnectionBackoffStrategy();
826             backoffManager = getBackoffManager();
827         }
828 
829         try {
830             if (connectionBackoffStrategy != null && backoffManager != null) {
831                 final HttpHost targetForRoute = (target != null) ? target
832                         : (HttpHost) determineParams(request).getParameter(
833                                 ClientPNames.DEFAULT_HOST);
834                 final HttpRoute route = routePlanner.determineRoute(targetForRoute, request, execContext);
835 
836                 CloseableHttpResponse out;
837                 try {
838                     out = CloseableHttpResponseProxy.newProxy(
839                             director.execute(target, request, execContext));
840                 } catch (final RuntimeException re) {
841                     if (connectionBackoffStrategy.shouldBackoff(re)) {
842                         backoffManager.backOff(route);
843                     }
844                     throw re;
845                 } catch (final Exception e) {
846                     if (connectionBackoffStrategy.shouldBackoff(e)) {
847                         backoffManager.backOff(route);
848                     }
849                     if (e instanceof HttpException) {
850                         throw (HttpException)e;
851                     }
852                     if (e instanceof IOException) {
853                         throw (IOException)e;
854                     }
855                     throw new UndeclaredThrowableException(e);
856                 }
857                 if (connectionBackoffStrategy.shouldBackoff(out)) {
858                     backoffManager.backOff(route);
859                 } else {
860                     backoffManager.probe(route);
861                 }
862                 return out;
863             } else {
864                 return CloseableHttpResponseProxy.newProxy(
865                         director.execute(target, request, execContext));
866             }
867         } catch(final HttpException httpException) {
868             throw new ClientProtocolException(httpException);
869         }
870     }
871 
872     /**
873      * @deprecated (4.1) do not use
874      */
875     @Deprecated
876     protected RequestDirector createClientRequestDirector(
877             final HttpRequestExecutor requestExec,
878             final ClientConnectionManager conman,
879             final ConnectionReuseStrategy reustrat,
880             final ConnectionKeepAliveStrategy kastrat,
881             final HttpRoutePlanner rouplan,
882             final HttpProcessor httpProcessor,
883             final HttpRequestRetryHandler retryHandler,
884             final RedirectHandler redirectHandler,
885             final AuthenticationHandler targetAuthHandler,
886             final AuthenticationHandler proxyAuthHandler,
887             final UserTokenHandler userTokenHandler,
888             final HttpParams params) {
889         return new DefaultRequestDirector(
890                 requestExec,
891                 conman,
892                 reustrat,
893                 kastrat,
894                 rouplan,
895                 httpProcessor,
896                 retryHandler,
897                 redirectHandler,
898                 targetAuthHandler,
899                 proxyAuthHandler,
900                 userTokenHandler,
901                 params);
902     }
903 
904     /**
905      * @deprecated (4.2) do not use
906      */
907     @Deprecated
908     protected RequestDirector createClientRequestDirector(
909             final HttpRequestExecutor requestExec,
910             final ClientConnectionManager conman,
911             final ConnectionReuseStrategy reustrat,
912             final ConnectionKeepAliveStrategy kastrat,
913             final HttpRoutePlanner rouplan,
914             final HttpProcessor httpProcessor,
915             final HttpRequestRetryHandler retryHandler,
916             final RedirectStrategy redirectStrategy,
917             final AuthenticationHandler targetAuthHandler,
918             final AuthenticationHandler proxyAuthHandler,
919             final UserTokenHandler userTokenHandler,
920             final HttpParams params) {
921         return new DefaultRequestDirector(
922                 log,
923                 requestExec,
924                 conman,
925                 reustrat,
926                 kastrat,
927                 rouplan,
928                 httpProcessor,
929                 retryHandler,
930                 redirectStrategy,
931                 targetAuthHandler,
932                 proxyAuthHandler,
933                 userTokenHandler,
934                 params);
935     }
936 
937 
938     /**
939      * @since 4.2
940      */
941     protected RequestDirector createClientRequestDirector(
942             final HttpRequestExecutor requestExec,
943             final ClientConnectionManager conman,
944             final ConnectionReuseStrategy reustrat,
945             final ConnectionKeepAliveStrategy kastrat,
946             final HttpRoutePlanner rouplan,
947             final HttpProcessor httpProcessor,
948             final HttpRequestRetryHandler retryHandler,
949             final RedirectStrategy redirectStrategy,
950             final AuthenticationStrategy targetAuthStrategy,
951             final AuthenticationStrategy proxyAuthStrategy,
952             final UserTokenHandler userTokenHandler,
953             final HttpParams params) {
954         return new DefaultRequestDirector(
955                 log,
956                 requestExec,
957                 conman,
958                 reustrat,
959                 kastrat,
960                 rouplan,
961                 httpProcessor,
962                 retryHandler,
963                 redirectStrategy,
964                 targetAuthStrategy,
965                 proxyAuthStrategy,
966                 userTokenHandler,
967                 params);
968     }
969 
970     /**
971      * Obtains parameters for executing a request.
972      * The default implementation in this class creates a new
973      * {@link ClientParamsStack} from the request parameters
974      * and the client parameters.
975      * <br/>
976      * This method is called by the default implementation of
977      * {@link #execute(HttpHost,HttpRequest,HttpContext)}
978      * to obtain the parameters for the
979      * {@link DefaultRequestDirector}.
980      *
981      * @param req    the request that will be executed
982      *
983      * @return  the parameters to use
984      */
985     protected HttpParams determineParams(final HttpRequest req) {
986         return new ClientParamsStack
987             (null, getParams(), req.getParams(), null);
988     }
989 
990 
991     public void close() {
992         getConnectionManager().shutdown();
993     }
994 
995 }