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