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