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