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     public synchronized final HttpParams getParams() {
465         if (defaultParams == null) {
466             defaultParams = createHttpParams();
467         }
468         return defaultParams;
469     }
470 
471     /**
472      * Replaces the parameters.
473      * The implementation here does not update parameters of dependent objects.
474      *
475      * @param params    the new default parameters
476      */
477     public synchronized void setParams(final HttpParams params) {
478         defaultParams = params;
479     }
480 
481 
482     public synchronized final ClientConnectionManager getConnectionManager() {
483         if (connManager == null) {
484             connManager = createClientConnectionManager();
485         }
486         return connManager;
487     }
488 
489 
490     public synchronized final HttpRequestExecutor getRequestExecutor() {
491         if (requestExec == null) {
492             requestExec = createRequestExecutor();
493         }
494         return requestExec;
495     }
496 
497 
498     public synchronized final AuthSchemeRegistry getAuthSchemes() {
499         if (supportedAuthSchemes == null) {
500             supportedAuthSchemes = createAuthSchemeRegistry();
501         }
502         return supportedAuthSchemes;
503     }
504 
505     public synchronized void setAuthSchemes(final AuthSchemeRegistry registry) {
506         supportedAuthSchemes = registry;
507     }
508 
509     public synchronized final ConnectionBackoffStrategy getConnectionBackoffStrategy() {
510         return connectionBackoffStrategy;
511     }
512 
513     public synchronized void setConnectionBackoffStrategy(final ConnectionBackoffStrategy strategy) {
514         connectionBackoffStrategy = strategy;
515     }
516 
517     public synchronized final CookieSpecRegistry getCookieSpecs() {
518         if (supportedCookieSpecs == null) {
519             supportedCookieSpecs = createCookieSpecRegistry();
520         }
521         return supportedCookieSpecs;
522     }
523 
524     public synchronized final BackoffManager getBackoffManager() {
525         return backoffManager;
526     }
527 
528     public synchronized void setBackoffManager(final BackoffManager manager) {
529         backoffManager = manager;
530     }
531 
532     public synchronized void setCookieSpecs(final CookieSpecRegistry registry) {
533         supportedCookieSpecs = registry;
534     }
535 
536     public synchronized final ConnectionReuseStrategy getConnectionReuseStrategy() {
537         if (reuseStrategy == null) {
538             reuseStrategy = createConnectionReuseStrategy();
539         }
540         return reuseStrategy;
541     }
542 
543 
544     public synchronized void setReuseStrategy(final ConnectionReuseStrategy strategy) {
545         this.reuseStrategy = strategy;
546     }
547 
548 
549     public synchronized final ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() {
550         if (keepAliveStrategy == null) {
551             keepAliveStrategy = createConnectionKeepAliveStrategy();
552         }
553         return keepAliveStrategy;
554     }
555 
556 
557     public synchronized void setKeepAliveStrategy(final ConnectionKeepAliveStrategy strategy) {
558         this.keepAliveStrategy = strategy;
559     }
560 
561 
562     public synchronized final HttpRequestRetryHandler getHttpRequestRetryHandler() {
563         if (retryHandler == null) {
564             retryHandler = createHttpRequestRetryHandler();
565         }
566         return retryHandler;
567     }
568 
569     public synchronized void setHttpRequestRetryHandler(final HttpRequestRetryHandler handler) {
570         this.retryHandler = handler;
571     }
572 
573     /**
574      * @deprecated (4.1) do not use
575      */
576     @Deprecated
577     public synchronized final RedirectHandler getRedirectHandler() {
578         return createRedirectHandler();
579     }
580 
581     /**
582      * @deprecated (4.1) do not use
583      */
584     @Deprecated
585     public synchronized void setRedirectHandler(final RedirectHandler handler) {
586         this.redirectStrategy = new DefaultRedirectStrategyAdaptor(handler);
587     }
588 
589     /**
590      * @since 4.1
591      */
592     public synchronized final RedirectStrategy getRedirectStrategy() {
593         if (redirectStrategy == null) {
594             redirectStrategy = new DefaultRedirectStrategy();
595         }
596         return redirectStrategy;
597     }
598 
599     /**
600      * @since 4.1
601      */
602     public synchronized void setRedirectStrategy(final RedirectStrategy strategy) {
603         this.redirectStrategy = strategy;
604     }
605 
606     /**
607      * @deprecated (4.2) do not use
608      */
609     @Deprecated
610     public synchronized final AuthenticationHandler getTargetAuthenticationHandler() {
611         return createTargetAuthenticationHandler();
612     }
613 
614     /**
615      * @deprecated (4.2) do not use
616      */
617     @Deprecated
618     public synchronized void setTargetAuthenticationHandler(final AuthenticationHandler handler) {
619         this.targetAuthStrategy = new AuthenticationStrategyAdaptor(handler);
620     }
621 
622     /**
623      * @since 4.2
624      */
625     public synchronized final AuthenticationStrategy getTargetAuthenticationStrategy() {
626         if (targetAuthStrategy == null) {
627             targetAuthStrategy = createTargetAuthenticationStrategy();
628         }
629         return targetAuthStrategy;
630     }
631 
632     /**
633      * @since 4.2
634      */
635     public synchronized void setTargetAuthenticationStrategy(final AuthenticationStrategy strategy) {
636         this.targetAuthStrategy = strategy;
637     }
638 
639     /**
640      * @deprecated (4.2) do not use
641      */
642     @Deprecated
643     public synchronized final AuthenticationHandler getProxyAuthenticationHandler() {
644         return createProxyAuthenticationHandler();
645     }
646 
647     /**
648      * @deprecated (4.2) do not use
649      */
650     @Deprecated
651     public synchronized void setProxyAuthenticationHandler(final AuthenticationHandler handler) {
652         this.proxyAuthStrategy = new AuthenticationStrategyAdaptor(handler);
653     }
654 
655     /**
656      * @since 4.2
657      */
658     public synchronized final AuthenticationStrategy getProxyAuthenticationStrategy() {
659         if (proxyAuthStrategy == null) {
660             proxyAuthStrategy = createProxyAuthenticationStrategy();
661         }
662         return proxyAuthStrategy;
663     }
664 
665     /**
666      * @since 4.2
667      */
668     public synchronized void setProxyAuthenticationStrategy(final AuthenticationStrategy strategy) {
669         this.proxyAuthStrategy = strategy;
670     }
671 
672     public synchronized final CookieStore getCookieStore() {
673         if (cookieStore == null) {
674             cookieStore = createCookieStore();
675         }
676         return cookieStore;
677     }
678 
679     public synchronized void setCookieStore(final CookieStore cookieStore) {
680         this.cookieStore = cookieStore;
681     }
682 
683     public synchronized final CredentialsProvider getCredentialsProvider() {
684         if (credsProvider == null) {
685             credsProvider = createCredentialsProvider();
686         }
687         return credsProvider;
688     }
689 
690     public synchronized void setCredentialsProvider(final CredentialsProvider credsProvider) {
691         this.credsProvider = credsProvider;
692     }
693 
694     public synchronized final HttpRoutePlanner getRoutePlanner() {
695         if (this.routePlanner == null) {
696             this.routePlanner = createHttpRoutePlanner();
697         }
698         return this.routePlanner;
699     }
700 
701     public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) {
702         this.routePlanner = routePlanner;
703     }
704 
705     public synchronized final UserTokenHandler getUserTokenHandler() {
706         if (this.userTokenHandler == null) {
707             this.userTokenHandler = createUserTokenHandler();
708         }
709         return this.userTokenHandler;
710     }
711 
712     public synchronized void setUserTokenHandler(final UserTokenHandler handler) {
713         this.userTokenHandler = handler;
714     }
715 
716     protected synchronized final BasicHttpProcessor getHttpProcessor() {
717         if (mutableProcessor == null) {
718             mutableProcessor = createHttpProcessor();
719         }
720         return mutableProcessor;
721     }
722 
723     private synchronized HttpProcessor getProtocolProcessor() {
724         if (protocolProcessor == null) {
725             // Get mutable HTTP processor
726             final BasicHttpProcessor proc = getHttpProcessor();
727             // and create an immutable copy of it
728             final int reqc = proc.getRequestInterceptorCount();
729             final HttpRequestInterceptor[] reqinterceptors = new HttpRequestInterceptor[reqc];
730             for (int i = 0; i < reqc; i++) {
731                 reqinterceptors[i] = proc.getRequestInterceptor(i);
732             }
733             final int resc = proc.getResponseInterceptorCount();
734             final HttpResponseInterceptor[] resinterceptors = new HttpResponseInterceptor[resc];
735             for (int i = 0; i < resc; i++) {
736                 resinterceptors[i] = proc.getResponseInterceptor(i);
737             }
738             protocolProcessor = new ImmutableHttpProcessor(reqinterceptors, resinterceptors);
739         }
740         return protocolProcessor;
741     }
742 
743     public synchronized int getResponseInterceptorCount() {
744         return getHttpProcessor().getResponseInterceptorCount();
745     }
746 
747     public synchronized HttpResponseInterceptor getResponseInterceptor(final int index) {
748         return getHttpProcessor().getResponseInterceptor(index);
749     }
750 
751     public synchronized HttpRequestInterceptor getRequestInterceptor(final int index) {
752         return getHttpProcessor().getRequestInterceptor(index);
753     }
754 
755     public synchronized int getRequestInterceptorCount() {
756         return getHttpProcessor().getRequestInterceptorCount();
757     }
758 
759     public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp) {
760         getHttpProcessor().addInterceptor(itcp);
761         protocolProcessor = null;
762     }
763 
764     public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp, final int index) {
765         getHttpProcessor().addInterceptor(itcp, index);
766         protocolProcessor = null;
767     }
768 
769     public synchronized void clearResponseInterceptors() {
770         getHttpProcessor().clearResponseInterceptors();
771         protocolProcessor = null;
772     }
773 
774     public synchronized void removeResponseInterceptorByClass(final Class<? extends HttpResponseInterceptor> clazz) {
775         getHttpProcessor().removeResponseInterceptorByClass(clazz);
776         protocolProcessor = null;
777     }
778 
779     public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp) {
780         getHttpProcessor().addInterceptor(itcp);
781         protocolProcessor = null;
782     }
783 
784     public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp, final int index) {
785         getHttpProcessor().addInterceptor(itcp, index);
786         protocolProcessor = null;
787     }
788 
789     public synchronized void clearRequestInterceptors() {
790         getHttpProcessor().clearRequestInterceptors();
791         protocolProcessor = null;
792     }
793 
794     public synchronized void removeRequestInterceptorByClass(final Class<? extends HttpRequestInterceptor> clazz) {
795         getHttpProcessor().removeRequestInterceptorByClass(clazz);
796         protocolProcessor = null;
797     }
798 
799     @Override
800     protected final CloseableHttpResponse doExecute(final HttpHost target, final HttpRequest request,
801                                       final HttpContext context)
802         throws IOException, ClientProtocolException {
803 
804         Args.notNull(request, "HTTP request");
805         // a null target may be acceptable, this depends on the route planner
806         // a null context is acceptable, default context created below
807 
808         HttpContext execContext = null;
809         RequestDirector director = null;
810         HttpRoutePlanner routePlanner = null;
811         ConnectionBackoffStrategy connectionBackoffStrategy = null;
812         BackoffManager backoffManager = null;
813 
814         // Initialize the request execution context making copies of
815         // all shared objects that are potentially threading unsafe.
816         synchronized (this) {
817 
818             final HttpContext defaultContext = createHttpContext();
819             if (context == null) {
820                 execContext = defaultContext;
821             } else {
822                 execContext = new DefaultedHttpContext(context, defaultContext);
823             }
824             final HttpParams params = determineParams(request);
825             final RequestConfig config = HttpClientParamConfig.getRequestConfig(params);
826             execContext.setAttribute(ClientContext.REQUEST_CONFIG, config);
827 
828             // Create a director for this request
829             director = createClientRequestDirector(
830                     getRequestExecutor(),
831                     getConnectionManager(),
832                     getConnectionReuseStrategy(),
833                     getConnectionKeepAliveStrategy(),
834                     getRoutePlanner(),
835                     getProtocolProcessor(),
836                     getHttpRequestRetryHandler(),
837                     getRedirectStrategy(),
838                     getTargetAuthenticationStrategy(),
839                     getProxyAuthenticationStrategy(),
840                     getUserTokenHandler(),
841                     params);
842             routePlanner = getRoutePlanner();
843             connectionBackoffStrategy = getConnectionBackoffStrategy();
844             backoffManager = getBackoffManager();
845         }
846 
847         try {
848             if (connectionBackoffStrategy != null && backoffManager != null) {
849                 final HttpHost targetForRoute = (target != null) ? target
850                         : (HttpHost) determineParams(request).getParameter(
851                                 ClientPNames.DEFAULT_HOST);
852                 final HttpRoute route = routePlanner.determineRoute(targetForRoute, request, execContext);
853 
854                 final CloseableHttpResponse out;
855                 try {
856                     out = CloseableHttpResponseProxy.newProxy(
857                             director.execute(target, request, execContext));
858                 } catch (final RuntimeException re) {
859                     if (connectionBackoffStrategy.shouldBackoff(re)) {
860                         backoffManager.backOff(route);
861                     }
862                     throw re;
863                 } catch (final Exception e) {
864                     if (connectionBackoffStrategy.shouldBackoff(e)) {
865                         backoffManager.backOff(route);
866                     }
867                     if (e instanceof HttpException) {
868                         throw (HttpException)e;
869                     }
870                     if (e instanceof IOException) {
871                         throw (IOException)e;
872                     }
873                     throw new UndeclaredThrowableException(e);
874                 }
875                 if (connectionBackoffStrategy.shouldBackoff(out)) {
876                     backoffManager.backOff(route);
877                 } else {
878                     backoffManager.probe(route);
879                 }
880                 return out;
881             } else {
882                 return CloseableHttpResponseProxy.newProxy(
883                         director.execute(target, request, execContext));
884             }
885         } catch(final HttpException httpException) {
886             throw new ClientProtocolException(httpException);
887         }
888     }
889 
890     /**
891      * @deprecated (4.1) do not use
892      */
893     @Deprecated
894     protected RequestDirector createClientRequestDirector(
895             final HttpRequestExecutor requestExec,
896             final ClientConnectionManager conman,
897             final ConnectionReuseStrategy reustrat,
898             final ConnectionKeepAliveStrategy kastrat,
899             final HttpRoutePlanner rouplan,
900             final HttpProcessor httpProcessor,
901             final HttpRequestRetryHandler retryHandler,
902             final RedirectHandler redirectHandler,
903             final AuthenticationHandler targetAuthHandler,
904             final AuthenticationHandler proxyAuthHandler,
905             final UserTokenHandler userTokenHandler,
906             final HttpParams params) {
907         return new DefaultRequestDirector(
908                 requestExec,
909                 conman,
910                 reustrat,
911                 kastrat,
912                 rouplan,
913                 httpProcessor,
914                 retryHandler,
915                 redirectHandler,
916                 targetAuthHandler,
917                 proxyAuthHandler,
918                 userTokenHandler,
919                 params);
920     }
921 
922     /**
923      * @deprecated (4.2) do not use
924      */
925     @Deprecated
926     protected RequestDirector createClientRequestDirector(
927             final HttpRequestExecutor requestExec,
928             final ClientConnectionManager conman,
929             final ConnectionReuseStrategy reustrat,
930             final ConnectionKeepAliveStrategy kastrat,
931             final HttpRoutePlanner rouplan,
932             final HttpProcessor httpProcessor,
933             final HttpRequestRetryHandler retryHandler,
934             final RedirectStrategy redirectStrategy,
935             final AuthenticationHandler targetAuthHandler,
936             final AuthenticationHandler proxyAuthHandler,
937             final UserTokenHandler userTokenHandler,
938             final HttpParams params) {
939         return new DefaultRequestDirector(
940                 log,
941                 requestExec,
942                 conman,
943                 reustrat,
944                 kastrat,
945                 rouplan,
946                 httpProcessor,
947                 retryHandler,
948                 redirectStrategy,
949                 targetAuthHandler,
950                 proxyAuthHandler,
951                 userTokenHandler,
952                 params);
953     }
954 
955 
956     /**
957      * @since 4.2
958      */
959     protected RequestDirector createClientRequestDirector(
960             final HttpRequestExecutor requestExec,
961             final ClientConnectionManager conman,
962             final ConnectionReuseStrategy reustrat,
963             final ConnectionKeepAliveStrategy kastrat,
964             final HttpRoutePlanner rouplan,
965             final HttpProcessor httpProcessor,
966             final HttpRequestRetryHandler retryHandler,
967             final RedirectStrategy redirectStrategy,
968             final AuthenticationStrategy targetAuthStrategy,
969             final AuthenticationStrategy proxyAuthStrategy,
970             final UserTokenHandler userTokenHandler,
971             final HttpParams params) {
972         return new DefaultRequestDirector(
973                 log,
974                 requestExec,
975                 conman,
976                 reustrat,
977                 kastrat,
978                 rouplan,
979                 httpProcessor,
980                 retryHandler,
981                 redirectStrategy,
982                 targetAuthStrategy,
983                 proxyAuthStrategy,
984                 userTokenHandler,
985                 params);
986     }
987 
988     /**
989      * Obtains parameters for executing a request.
990      * The default implementation in this class creates a new
991      * {@link ClientParamsStack} from the request parameters
992      * and the client parameters.
993      * <p>
994      * This method is called by the default implementation of
995      * {@link #execute(HttpHost,HttpRequest,HttpContext)}
996      * to obtain the parameters for the
997      * {@link DefaultRequestDirector}.
998      * </p>
999      *
1000      * @param req    the request that will be executed
1001      *
1002      * @return  the parameters to use
1003      */
1004     protected HttpParams determineParams(final HttpRequest req) {
1005         return new ClientParamsStack
1006             (null, getParams(), req.getParams(), null);
1007     }
1008 
1009 
1010     public void close() {
1011         getConnectionManager().shutdown();
1012     }
1013 
1014 }