1 /*
2  * Copyright 2010-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */

15 package com.amazonaws;
16
17 import com.amazonaws.annotation.NotThreadSafe;
18 import com.amazonaws.http.IdleConnectionReaper;
19 import com.amazonaws.http.SystemPropertyTlsKeyManagersProvider;
20 import com.amazonaws.http.TlsKeyManagersProvider;
21 import com.amazonaws.retry.PredefinedRetryPolicies;
22 import com.amazonaws.retry.RetryMode;
23 import com.amazonaws.retry.RetryPolicy;
24 import com.amazonaws.util.StringUtils;
25 import com.amazonaws.util.ValidationUtils;
26 import com.amazonaws.util.VersionInfoUtils;
27 import java.net.InetAddress;
28 import java.net.MalformedURLException;
29 import java.net.URL;
30 import java.security.SecureRandom;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.concurrent.atomic.AtomicReference;
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39
40 /**
41  * Client configuration options such as proxy settings, user agent string, max retry attempts, etc.
42  *
43  * @see PredefinedClientConfigurations
44  */

45 @NotThreadSafe
46 public class ClientConfiguration {
47     private static final Log log = LogFactory.getLog(ClientConfiguration.class);
48
49     /** The default timeout for creating new connections. */
50     public static final int DEFAULT_CONNECTION_TIMEOUT = 10 * 1000;
51
52     /** The default timeout for reading from a connected socket. */
53     public static final int DEFAULT_SOCKET_TIMEOUT = 50 * 1000;
54
55     /**
56      * The default timeout for a request. This is disabled by default.
57      */

58     public static final int DEFAULT_REQUEST_TIMEOUT = 0;
59
60     /**
61      * The default timeout for a request. This is disabled by default.
62      */

63     public static final int DEFAULT_CLIENT_EXECUTION_TIMEOUT = 0;
64
65     /**
66      * The default on whether to disable {@code Socket} proxies.
67      */

68     public static final boolean DEFAULT_DISABLE_SOCKET_PROXY = false;
69
70     /** The default max connection pool size. */
71     public static final int DEFAULT_MAX_CONNECTIONS = 50;
72
73     /**
74      * The default on whether to utilize the USE_EXPECT_CONTINUE handshake for operations. Currently
75      * only honored for PUT operations.
76      */

77     public static final boolean DEFAULT_USE_EXPECT_CONTINUE = true;
78
79     /** The default HTTP user agent header for AWS Java SDK clients. */
80     public static final String DEFAULT_USER_AGENT = VersionInfoUtils.getUserAgent();
81
82     /**
83      * Default request retry policy, including the maximum retry count of 3, the default retry
84      * condition and the default back-off strategy.
85      *
86      * @see PredefinedRetryPolicies#DEFAULT
87      * @see PredefinedRetryPolicies#DYNAMODB_DEFAULT
88      */

89     public static final RetryPolicy DEFAULT_RETRY_POLICY = PredefinedRetryPolicies.DEFAULT;
90
91     /**
92      * The default on whether to use the {@link IdleConnectionReaper} to manage stale connections
93      *
94      * @see IdleConnectionReaper
95      */

96     public static final boolean DEFAULT_USE_REAPER = true;
97
98     /**
99      * The default on whether to use gzip decompression.
100      */

101     public static final boolean DEFAULT_USE_GZIP = false;
102
103     /**
104      * The default expiration time (in milliseconds) for a connection in the connection pool.
105      */

106     public static final long DEFAULT_CONNECTION_TTL = -1;
107
108     /**
109      * The default maximum idle time (in milliseconds) for a connection in the connection pool.
110      */

111     public static final long DEFAULT_CONNECTION_MAX_IDLE_MILLIS = 60 * 1000;
112
113     /**
114      * The default time a connection can be idle in the connection pool before it must be validated that it's still open.
115      */

116     public static final int DEFAULT_VALIDATE_AFTER_INACTIVITY_MILLIS = 5 * 1000;
117
118     /**
119      * The default on whether to use TCP KeepAlive.
120      */

121     public static final boolean DEFAULT_TCP_KEEP_ALIVE = false;
122
123     /**
124      * The default on whether to throttle retries.
125      */

126     public static final boolean DEFAULT_THROTTLE_RETRIES = true;
127
128     /**
129      * The default on whether to cache response metadata.
130      */

131     public static final boolean DEFAULT_CACHE_RESPONSE_METADATA = true;
132
133     /**
134      * The default response metadata cache size.
135      */

136     public static final int DEFAULT_RESPONSE_METADATA_CACHE_SIZE = 50;
137
138     public static final int DEFAULT_MAX_CONSECUTIVE_RETRIES_BEFORE_THROTTLING = 100;
139
140
141     /** A prefix to the HTTP user agent header passed with all HTTP requests.  */
142     private String userAgentPrefix = DEFAULT_USER_AGENT;
143
144     /** A suffix to the HTTP user agent header. */
145     private String userAgentSuffix;
146
147     /**
148      * The maximum number of times that a retryable failed request (ex: a 5xx response from a
149      * service) will be retried. Or -1 if the user has not explicitly set this value, in which case
150      * the configured RetryPolicy will be used to control the retry count.
151      */

152     private int maxErrorRetry = -1;
153
154     /** The retry policy upon failed requests. **/
155     private RetryPolicy retryPolicy = DEFAULT_RETRY_POLICY;
156
157     /** Optionally specifies the local address to bind to */
158     private InetAddress localAddress;
159
160     /**
161      * The protocol to use when connecting to Amazon Web Services.
162      * <p>
163      * The default configuration is to use HTTPS for all requests for increased security.
164      */

165     private Protocol protocol = Protocol.HTTPS;
166
167     /**
168      * The protocol to use when connecting to an HTTP proxy.
169      * <p>
170      * The default configuration is to use {@link Protocol#HTTP}.
171      */

172     private Protocol proxyProtocol = Protocol.HTTP;
173
174     /** Optionally specifies the proxy host to connect through. */
175     private String proxyHost = null;
176
177     /** Optionally specifies the port on the proxy host to connect through. */
178     private int proxyPort = -1;
179
180     /** Optionally specifies the user name to use when connecting through a proxy. */
181     private String proxyUsername = null;
182
183     /** Optionally specifies the password to use when connecting through a proxy. */
184     private String proxyPassword = null;
185
186     /** Optional Windows domain name for configuring NTLM proxy support. */
187     private String proxyDomain = null;
188
189     /** Optional Windows workstation name for configuring NTLM proxy support. */
190     private String proxyWorkstation = null;
191
192     /** Optional specifies the hosts that should be accessed without going through the proxy. */
193     private String nonProxyHosts = null;
194
195     /** Specifies the proxy authentication methods that should be used, in priority order. */
196     private List<ProxyAuthenticationMethod> proxyAuthenticationMethods = null;
197
198     /**
199      * Controls whether {@link java.net.Socket}s created by the client should
200      * use the default {@link java.net.ProxySelector} when connecting to the
201      * remote host to find an appropriate proxy or connect directly to the
202      * host.
203      * <p />
204      * Note this property is only guaranteed to be honored when using the
205      * default connection factories.
206      */

207     private boolean disableSocketProxy = DEFAULT_DISABLE_SOCKET_PROXY;
208
209     /**
210      * Whether to pre-emptively authenticate against a proxy server using basic authentication
211      */

212     private boolean preemptiveBasicProxyAuth;
213
214     /** The maximum number of open HTTP connections. */
215     private int maxConnections = DEFAULT_MAX_CONNECTIONS;
216
217     /**
218      * The amount of time to wait (in milliseconds) for data to be transferred over an established,
219      * open connection before the connection is timed out. A value of 0 means infinity, and is not
220      * recommended.
221      */

222     private int socketTimeout = DEFAULT_SOCKET_TIMEOUT;
223
224     /**
225      * The amount of time to wait (in milliseconds) when initially establishing a connection before
226      * giving up and timing out. A value of 0 means infinity, and is not recommended.
227      */

228     private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
229
230     /**
231      * The amount of time to wait (in milliseconds) for a request to complete before giving up and
232      * timing out. A value of 0 means infinity. Consider setting this if a harder guarantee is
233      * required on the maximum amount of time a request will take for non-streaming operations, and
234      * are willing to spin up a background thread to enforce it.
235      */

236     private int requestTimeout = DEFAULT_REQUEST_TIMEOUT;
237
238     private int clientExecutionTimeout = DEFAULT_CLIENT_EXECUTION_TIMEOUT;
239
240     private boolean throttleRetries = DEFAULT_THROTTLE_RETRIES;
241
242     /**
243      * Optional size hint (in bytes) for the low level TCP send buffer. This is an advanced option
244      * for advanced users who want to tune low level TCP parameters to try and squeeze out more
245      * performance.
246      */

247     private int socketSendBufferSizeHint = 0;
248
249     /**
250      * Optional size hint (in bytes) for the low level TCP receive buffer. This is an advanced
251      * option for advanced users who want to tune low level TCP parameters to try and squeeze out
252      * more performance.
253      */

254     private int socketReceiveBufferSizeHint = 0;
255
256     /**
257      * Optional whether to use the {@link IdleConnectionReaper} to manage stale connections. A
258      * reason for not running the {@link IdleConnectionReaper} can be if running in an environment
259      * where the modifyThread and modifyThreadGroup permissions are not allowed.
260      */

261     private boolean useReaper = DEFAULT_USE_REAPER;
262
263     /**
264      * Optional whether to use gzip decompression when receiving HTTP responses.
265      */

266     private boolean useGzip = DEFAULT_USE_GZIP;
267
268     /**
269      * Optional override to control which signature algorithm should be used to sign requests to the
270      * service. If not explicitly set, the client will determine the algorithm to use by inspecting
271      * a configuration file baked in to the SDK.
272      */

273     private String signerOverride;
274
275     /**
276      * Optional expiration time for a connection in the connection pool. When a connection is
277      * retrieved from the connection pool, this parameter is checked to see if the connection can be
278      * reused.
279      */

280     private long connectionTTL = DEFAULT_CONNECTION_TTL;
281
282     /**
283      * The maximum idle time for a connection in the connection pool.
284      */

285     private long connectionMaxIdleMillis = DEFAULT_CONNECTION_MAX_IDLE_MILLIS;
286
287     private int validateAfterInactivityMillis = DEFAULT_VALIDATE_AFTER_INACTIVITY_MILLIS;
288
289     /**
290      * Optional override to enable support for TCP KeepAlive (not to be confused with HTTP
291      * KeepAlive). TCP KeepAlive can be used to detect misbehaving routers or down servers through
292      * the use of special, empty-data keep alive packets.
293      * <p>
294      * Actual TCP KeepAlive values (timeout, number of packets, etc) are configured via the
295      * operating system (sysctl on Linux, and Registry values on Windows).
296      */

297     private boolean tcpKeepAlive = DEFAULT_TCP_KEEP_ALIVE;
298
299     /**
300      * Whether or not to cache response metadata.
301      * <p>
302      * Response metadata is typically used for troubleshooting issues with AWS support staff when
303      * services aren't acting as expected.
304      * </p>
305      * <p>
306      * While this feature is useful for debugging it adds overhead and disabling it may
307      * be desired in high throughput applications.
308      * </p>
309      */

310     private boolean cacheResponseMetadata = DEFAULT_CACHE_RESPONSE_METADATA;
311
312     /**
313      * Size of the response metadata cache, if it is enabled.
314      * <p>
315      * Response metadata is typically used for troubleshooting issues with AWS support staff when
316      * services aren't acting as expected.
317      */

318     private int responseMetadataCacheSize = DEFAULT_RESPONSE_METADATA_CACHE_SIZE;
319
320     /**
321      * The DNS Resolver to resolve IP addresses of Amazon Web Services.
322      */

323     private DnsResolver dnsResolver = new SystemDefaultDnsResolver();
324
325     /**
326      * An instance of {@link SecureRandom} configured by the user; or the JDK default will be used
327      * if it is set to null or not explicitly configured.
328      */

329     private SecureRandom secureRandom;
330
331     /**
332      * Headers to be added to all requests
333      */

334     private Map<String, String> headers = new HashMap<String, String>();
335
336     /**
337      * Optional override to enable/disable support for HTTP/1.1 handshake utilizing EXPECT:
338      * 100-Continue. The default value is true.
339      * <p>
340      * The detail of HTTP Expect Continue is defined at
341      * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3"> Use of the 100
342      * (Continue) Status</a>. Setting this as false will reduce latency when you want to send small
343      * size of payload. It is highly recommended to use the default value if you want to transfer a
344      * large amount of data to the server, such as uploading a big file to S3 bucket.
345      */

346     private boolean useExpectContinue = DEFAULT_USE_EXPECT_CONTINUE;
347
348     /**
349      * The maximum number of throttled retries if the initial request
350      * fails.
351      */

352     private int maxConsecutiveRetriesBeforeThrottling = DEFAULT_MAX_CONSECUTIVE_RETRIES_BEFORE_THROTTLING;
353
354     /**
355      * Can be used to specify custom specific Apache HTTP client configurations.
356      */

357     private final ApacheHttpClientConfig apacheHttpClientConfig;
358
359     /**
360      * Configuration option to disable the host prefix injection.
361      *
362      * The hostPrefix template is specified in the service model and is used by the SDK to modify the endpoint
363      * the request is sent to. Host prefix injection is enabled by default. This option can be set to disable the behavior.
364      */

365     private boolean disableHostPrefixInjection;
366
367     private final AtomicReference<URLHolder> httpProxyHolder = new AtomicReference<URLHolder>();
368
369     private final AtomicReference<URLHolder> httpsProxyHolder = new AtomicReference<URLHolder>();
370
371     private TlsKeyManagersProvider tlsKeyManagersProvider;
372     private RetryMode retryMode;
373
374     public ClientConfiguration() {
375         apacheHttpClientConfig = new ApacheHttpClientConfig();
376     }
377
378     public ClientConfiguration(ClientConfiguration other) {
379         this.connectionTimeout = other.getConnectionTimeout();
380         this.maxConnections = other.getMaxConnections();
381         this.maxErrorRetry = other.getMaxErrorRetry();
382         this.retryPolicy = other.getRetryPolicy();
383         this.throttleRetries = other.useThrottledRetries();
384         this.localAddress = other.getLocalAddress();
385         this.protocol = other.getProtocol();
386         this.proxyProtocol = other.getProxyProtocol();
387         this.proxyDomain = other.getProxyDomain();
388         this.proxyHost = other.getProxyHost();
389         this.proxyPassword = other.getProxyPassword();
390         this.proxyPort = other.getProxyPort();
391         this.proxyUsername = other.getProxyUsername();
392         this.proxyWorkstation = other.getProxyWorkstation();
393         this.nonProxyHosts = other.getNonProxyHosts();
394         this.disableSocketProxy = other.disableSocketProxy();
395         this.proxyAuthenticationMethods = other.getProxyAuthenticationMethods();
396         this.preemptiveBasicProxyAuth = other.isPreemptiveBasicProxyAuth();
397         this.socketTimeout = other.getSocketTimeout();
398         this.requestTimeout = other.getRequestTimeout();
399         this.clientExecutionTimeout = other.getClientExecutionTimeout();
400         this.userAgentPrefix = other.getUserAgentPrefix();
401         this.userAgentSuffix = other.getUserAgentSuffix();
402         this.useReaper = other.useReaper();
403         this.useGzip = other.useGzip();
404         this.socketSendBufferSizeHint = other.getSocketBufferSizeHints()[0];
405         this.socketReceiveBufferSizeHint = other.getSocketBufferSizeHints()[1];
406         this.signerOverride = other.getSignerOverride();
407         this.responseMetadataCacheSize = other.getResponseMetadataCacheSize();
408         this.dnsResolver = other.getDnsResolver();
409         this.useExpectContinue = other.isUseExpectContinue();
410         this.apacheHttpClientConfig = new ApacheHttpClientConfig(other.getApacheHttpClientConfig());
411         this.cacheResponseMetadata = other.getCacheResponseMetadata();
412         this.connectionTTL = other.getConnectionTTL();
413         this.connectionMaxIdleMillis = other.getConnectionMaxIdleMillis();
414         this.validateAfterInactivityMillis = other.getValidateAfterInactivityMillis();
415         this.tcpKeepAlive = other.useTcpKeepAlive();
416         this.secureRandom = other.getSecureRandom();
417         this.headers.clear();
418         this.headers.putAll(other.getHeaders());
419         this.maxConsecutiveRetriesBeforeThrottling = other.getMaxConsecutiveRetriesBeforeThrottling();
420         this.disableHostPrefixInjection = other.disableHostPrefixInjection;
421         this.httpProxyHolder.set(other.httpProxyHolder.get());
422         this.httpsProxyHolder.set(other.httpsProxyHolder.get());
423         this.tlsKeyManagersProvider = other.tlsKeyManagersProvider;
424         this.retryMode = other.retryMode;
425     }
426
427     /**
428      * Returns the protocol (HTTP or HTTPS) to use when connecting to Amazon Web Services.
429      * <p>
430      * The default configuration is to use HTTPS for all requests for increased security.
431      * <p>
432      * Individual clients can also override this setting by explicitly including the protocol as
433      * part of the endpoint URL when calling {@link AmazonWebServiceClient#setEndpoint(String)}.
434      *
435      * @return The protocol to use when connecting to Amazon Web Services.
436      */

437     public Protocol getProtocol() {
438         return protocol;
439     }
440
441     /**
442      * Sets the protocol (i.e. HTTP or HTTPS) to use when connecting to Amazon Web Services.
443      * <p>
444      * The default configuration is to use HTTPS for all requests for increased security.
445      * <p>
446      * Individual clients can also override this setting by explicitly including the protocol as
447      * part of the endpoint URL when calling {@link AmazonWebServiceClient#setEndpoint(String)}.
448      *
449      * @param protocol
450      *            The protocol to use when connecting to Amazon Web Services.
451      */

452     public void setProtocol(Protocol protocol) {
453         this.protocol = protocol;
454     }
455
456     /**
457      * Sets the protocol (i.e. HTTP or HTTPS) to use when connecting to Amazon Web Services, and
458      * returns the updated ClientConfiguration object so that additional calls may be chained
459      * together.
460      * <p>
461      * The default configuration is to use HTTPS for all requests for increased security.
462      * <p>
463      * Individual clients can also override this setting by explicitly including the protocol as
464      * part of the endpoint URL when calling {@link AmazonWebServiceClient#setEndpoint(String)}.
465      *
466      * @param protocol
467      *            The protocol to use when connecting to Amazon Web Services.
468      * @return The updated ClientConfiguration object with the new max HTTP connections setting.
469      */

470     public ClientConfiguration withProtocol(Protocol protocol) {
471         setProtocol(protocol);
472         return this;
473     }
474
475     /**
476      * Returns the maximum number of allowed open HTTP connections.
477      *
478      * @return The maximum number of allowed open HTTP connections.
479      */

480     public int getMaxConnections() {
481         return maxConnections;
482     }
483
484     /**
485      * Sets the maximum number of allowed open HTTP connections.
486      *
487      * @param maxConnections
488      *            The maximum number of allowed open HTTP connections.
489      */

490     public void setMaxConnections(int maxConnections) {
491         this.maxConnections = maxConnections;
492     }
493
494     /**
495      * Sets the maximum number of allowed open HTTP connections and returns the updated
496      * ClientConfiguration object.
497      *
498      * @param maxConnections
499      *            The maximum number of allowed open HTTP connections.
500      * @return The updated ClientConfiguration object with the new max HTTP connections setting.
501      */

502     public ClientConfiguration withMaxConnections(int maxConnections) {
503         setMaxConnections(maxConnections);
504         return this;
505     }
506
507     /**
508      * @deprecated Replaced by {@link #getUserAgentPrefix()} and {@link #getUserAgentSuffix()}
509      * @return The user agent string to use when sending requests.
510      */

511     @Deprecated
512     public String getUserAgent() {
513         return getUserAgentPrefix();
514     }
515
516     /**
517      * @deprecated Replaced by {@link #setUserAgentPrefix(String)} and {@link #setUserAgentSuffix(String)}
518      * @param userAgent
519      *            The user agent string to use when sending requests.
520      */

521     @Deprecated
522     public void setUserAgent(String userAgent) {
523         setUserAgentPrefix(userAgent);
524     }
525
526     /**
527      * @deprecated Replaced by {@link #withUserAgentPrefix(String)} and {@link #withUserAgentSuffix(String)}
528      * @param userAgent
529      *            The user agent string to use when sending requests.
530      * @return The updated ClientConfiguration object.
531      */

532     @Deprecated
533     public ClientConfiguration withUserAgent(String userAgent) {
534         return withUserAgentPrefix(userAgent);
535     }
536
537     /**
538      * Returns the HTTP user agent header prefix to send with all requests.
539      *
540      * @return The user agent string prefix to use when sending requests.
541      */

542     public String getUserAgentPrefix() {
543         return userAgentPrefix;
544     }
545
546     /**
547      * Sets the HTTP user agent prefix to send with all requests.
548      *
549      * @param prefix
550      *            The string to prefix to user agent to use when sending requests.
551      */

552     public void setUserAgentPrefix(String prefix) {
553         this.userAgentPrefix = prefix;
554     }
555
556     /**
557      * Sets the HTTP user agent prefix header used in requests and returns the updated ClientConfiguration
558      * object.
559      *
560      * @param prefix
561      *            The string to prefix to user agent to use when sending requests.
562      * @return The updated ClientConfiguration object.
563      */

564     public ClientConfiguration withUserAgentPrefix(String prefix) {
565         setUserAgentPrefix(prefix);
566         return this;
567     }
568
569     /**
570      * Returns the HTTP user agent header suffix to add to the end of the user agent header on all requests.
571      *
572      * @return The user agent string suffix to use when sending requests.
573      */

574     public String getUserAgentSuffix() {
575         return userAgentSuffix;
576     }
577
578     /**
579      * Sets the HTTP user agent suffix to send with all requests.
580      *
581      * @param suffix
582      *            The string to suffix to user agent to use when sending requests.
583      */

584     public void setUserAgentSuffix(String suffix) {
585         this.userAgentSuffix = suffix;
586     }
587
588     /**
589      * Sets the HTTP user agent suffix header used in requests and returns the updated ClientConfiguration
590      * object.
591      *
592      * @param suffix
593      *            The string to suffix to user agent to use when sending requests.
594      * @return The updated ClientConfiguration object.
595      */

596     public ClientConfiguration withUserAgentSuffix(String suffix) {
597         setUserAgentSuffix(suffix);
598         return this;
599     }
600
601     /**
602      * Returns the optional local address the client will bind to.
603      *
604      * @return The local address the client will bind to.
605      */

606     public InetAddress getLocalAddress() {
607         return localAddress;
608     }
609
610     /**
611      * Sets the optional local address the client will bind to.
612      *
613      * @param localAddress
614      *            The local address the client will bind to.
615      */

616     public void setLocalAddress(InetAddress localAddress) {
617         this.localAddress = localAddress;
618     }
619
620     /**
621      * Sets the optional local address the client will bind to and returns the updated
622      * ClientConfiguration object.
623      *
624      * @param localAddress
625      *            The local address the client will bind to.
626      * @return The updated ClientConfiguration object.
627      */

628     public ClientConfiguration withLocalAddress(InetAddress localAddress) {
629         setLocalAddress(localAddress);
630         return this;
631     }
632
633     /**
634      * Returns the value for the given system property.
635      */

636     private String getSystemProperty(String property) {
637         return System.getProperty(property);
638     }
639
640     /**
641      * Returns the value for the given environment variable.
642      */

643     private String getEnvironmentVariable(String environmentVariable) {
644         String value = StringUtils.trim(System.getenv(environmentVariable));
645         return StringUtils.hasValue(value) ? value : null;
646     }
647
648     /**
649      * Returns the value for the given environment variable if its set, otherwise returns
650      * the lowercase version of variable.
651      */

652     private String getEnvironmentVariableCaseInsensitive(String environmentVariable) {
653         String result = getEnvironmentVariable(environmentVariable);
654         return result != null ? result : getEnvironmentVariable(environmentVariable.toLowerCase());
655     }
656
657     /**
658      * @return The {@link Protocol} to use for connecting to the proxy.
659      */

660     public Protocol getProxyProtocol() {
661         return proxyProtocol;
662     }
663
664     /**
665      * Set the {@link Protocol} to use for connecting to the proxy.
666      *
667      * @param proxyProtocol The protocol.
668      * @return The updated ClientConfiguration object.
669      */

670     public ClientConfiguration withProxyProtocol(Protocol proxyProtocol) {
671         this.proxyProtocol = proxyProtocol == null ? Protocol.HTTP : proxyProtocol;
672         return this;
673     }
674
675     /**
676      * Set the {@link Protocol} to use for connecting to the proxy.
677      *
678      * @param proxyProtocol The protocol.
679      */

680     public void setProxyProtocol(Protocol proxyProtocol) {
681         withProxyProtocol(proxyProtocol);
682     }
683
684     /**
685      * Returns the Java system property for proxy host depending on
686      * {@link #getProtocol()}: i.e. if protocol is https, returns
687      * the value of the system property https.proxyHost, otherwise
688      * returns value of http.proxyHost.
689      */

690     private String getProxyHostProperty() {
691         return getProtocol() == Protocol.HTTPS
692                 ? getSystemProperty("https.proxyHost")
693                 : getSystemProperty("http.proxyHost");
694     }
695
696     /**
697      * Returns the environment variable for proxy host depending on
698      * {@link #getProtocol()}: i.e. if protocol is https, returns
699      * the host in the value of the environment variable HTTPS_PROXY/https_proxy,
700      * otherwise, returns the host in the value of the environment
701      * variable HTTP_PROXY/http_proxy.
702      */

703     private String getProxyHostEnvironment() {
704         URL httpProxy = getHttpProxyEnvironmentVariable();
705         if (httpProxy != null) {
706             return httpProxy.getHost();
707         }
708         return null;
709     }
710
711     /**
712      * Returns the optional proxy host the client will connect
713      * through.  Returns either the proxyHost set on this object, or
714      * if not provided, checks the value of the Java system property
715      * for proxy host according to {@link #getProtocol()}: i.e. if
716      * protocol is https, returns the value of the system property
717      * https.proxyHost, otherwise returns value of http.proxyHost.
718      * If neither are set, checks the value of the environment variable
719      * according to {@link #getProtocol()}: i.e. if protocol is https,
720      * returns the host in the value of the HTTPS_PROXY/https_proxy
721      * environment variable, otherwise returns the host in the value
722      * of the HTTP_PROXY/http_proxy environment variable.
723      *
724      * @return The proxy host the client will connect through.
725      */

726     public String getProxyHost() {
727         if (proxyHost != null) {
728             return proxyHost;
729         } else if (getProxyHostProperty() != null) {
730             return getProxyHostProperty();
731         } else {
732             return getProxyHostEnvironment();
733         }
734     }
735
736     /**
737      * Sets the optional proxy host the client will connect through.
738      *
739      * @param proxyHost
740      *            The proxy host the client will connect through.
741      */

742     public void setProxyHost(String proxyHost) {
743         this.proxyHost = proxyHost;
744     }
745
746     /**
747      * Sets the optional proxy host the client will connect through and returns the updated
748      * ClientConfiguration object.
749      *
750      * @param proxyHost
751      *            The proxy host the client will connect through.
752      * @return The updated ClientConfiguration object.
753      */

754     public ClientConfiguration withProxyHost(String proxyHost) {
755         setProxyHost(proxyHost);
756         return this;
757     }
758
759     /**
760      * Returns the Java system property for proxy port depending on
761      * {@link #getProtocol()}: i.e. if protocol is https, returns
762      * the value of the system property https.proxyPort, otherwise
763      * returns value of http.proxyPort.  Defaults to {@link this.proxyPort}
764      * if the system property is not set with a valid port number.
765      */

766     private int getProxyPortProperty() {
767         try {
768             return getProtocol() == Protocol.HTTPS
769                     ? Integer.parseInt(getSystemProperty("https.proxyPort"))
770                     : Integer.parseInt(getSystemProperty("http.proxyPort"));
771         } catch (NumberFormatException e) {
772             return proxyPort;
773         }
774     }
775
776     /**
777      * Returns the environment variable for proxy port depending on
778      * {@link #getProtocol()}: i.e. if protocol is https, returns
779      * the port in the value of the environment variable HTTPS_PROXY/https_proxy,
780      * otherwise, returns the port in the value of the environment
781      * variable HTTP_PROXY/http_proxy.
782      */

783     private int getProxyPortEnvironment() {
784         URL httpProxy = getHttpProxyEnvironmentVariable();
785         if (httpProxy != null) {
786             return httpProxy.getPort();
787         }
788         return proxyPort;
789     }
790
791     /**
792      * Returns the optional proxy port the client will connect
793      * through.  Returns either the proxyPort set on this object, or
794      * if not provided, checks the value of the Java system property
795      * for proxy port according to {@link #getProtocol()}: i.e. if
796      * protocol is https, returns the value of the system property
797      * https.proxyPort, otherwise returns value of http.proxyPort.
798      * If neither are set, checks the value of the environment variable
799      * according to {@link #getProtocol()}: i.e. if protocol is https,
800      * returns the port in the value of the HTTPS_PROXY/https_proxy
801      * environment variable, otherwise returns the port in the value
802      * of the HTTP_PROXY/http_proxy environment variable.
803      *
804      * @return The proxy port the client will connect through.
805      */

806     public int getProxyPort() {
807         if (proxyPort >= 0) {
808             return proxyPort;
809         } else if (getProxyPortProperty() >= 0) {
810             return getProxyPortProperty();
811         } else {
812             return getProxyPortEnvironment();
813         }
814     }
815
816     /**
817      * Sets the optional proxy port the client will connect through.
818      *
819      * @param proxyPort
820      *            The proxy port the client will connect through.
821      */

822     public void setProxyPort(int proxyPort) {
823         this.proxyPort = proxyPort;
824     }
825
826     /**
827      * Sets the optional proxy port the client will connect through and returns the updated
828      * ClientConfiguration object.
829      *
830      * @param proxyPort
831      *            The proxy port the client will connect through.
832      * @return The updated ClientConfiguration object.
833      */

834     public ClientConfiguration withProxyPort(int proxyPort) {
835         setProxyPort(proxyPort);
836         return this;
837     }
838
839     /**
840      * Set whether to disable proxies at the socket level.
841      *
842      * @param disableSocketProxy Whether to disable proxies at the socket level.
843      *
844      * @return The updated ClientConfiguration object.
845      */

846     public ClientConfiguration withDisableSocketProxy(boolean disableSocketProxy) {
847         this.disableSocketProxy = disableSocketProxy;
848         return this;
849     }
850
851     /**
852      * Set whether to disable proxies at the socket level.
853      *
854      * @param disableSocketProxy Whether to disable proxies at the socket level.
855      */

856     public void setDisableSocketProxy(boolean disableSocketProxy) {
857         withDisableSocketProxy(disableSocketProxy);
858     }
859
860     /**
861      * @return Whether to disable proxies at the socket level.
862      */

863     public boolean disableSocketProxy() {
864         return disableSocketProxy;
865     }
866
867     /**
868      * Returns the Java system property for proxy user name depending on
869      * {@link #getProtocol()}: i.e. if protocol is https, returns
870      * the value of the system property https.proxyUser, otherwise
871      * returns value of http.proxyUser.
872      */

873     private String getProxyUsernameProperty() {
874         return (getProtocol() == Protocol.HTTPS)
875                 ? getSystemProperty("https.proxyUser")
876                 : getSystemProperty("http.proxyUser");
877     }
878
879     /**
880      * Returns the environment variable for proxy host depending on
881      * {@link #getProtocol()}: i.e. if protocol is https, returns
882      * the user name in the value of the environment variable
883      * HTTPS_PROXY/https_proxy, otherwise, returns the user name in
884      * the value of the environment variable HTTP_PROXY/http_proxy.
885      */

886     private String getProxyUsernameEnvironment() {
887         URL httpProxy = getHttpProxyEnvironmentVariable();
888         if (httpProxy != null) {
889             try {
890                 return httpProxy.getUserInfo().split(":", 2)[0];
891             } catch (Exception ignored) {
892             }
893         }
894         return null;
895     }
896
897     /**
898      * Returns the optional proxy user name to use if connecting
899      * through a proxy.  Returns either the proxyUsername set on this
900      * object, or if not provided, checks the value of the Java system
901      * property for proxy user name according to {@link #getProtocol()}:
902      * i.e. if protocol is https, returns the value of the system
903      * property https.proxyUser, otherwise returns value of
904      * http.proxyUser. If neither are set, checks the value of the
905      * environment variable according to {@link #getProtocol()}: i.e.
906      * if protocol is https, returns the user name in the value of the
907      * HTTPS_PROXY/https_proxy environment variable, otherwise returns
908      * the user name in the value of the HTTP_PROXY/http_proxy environment
909      * variable.
910      *
911      * @return The optional proxy user name the configured client will use if connecting through a
912      *         proxy.
913      */

914     public String getProxyUsername() {
915         if (proxyUsername != null) {
916             return proxyUsername;
917         } else if (getProxyUsernameProperty() != null) {
918             return getProxyUsernameProperty();
919         } else {
920             return getProxyUsernameEnvironment();
921         }
922     }
923
924     /**
925      * Sets the optional proxy user name to use if connecting through a proxy.
926      *
927      * @param proxyUsername
928      *            The proxy user name to use if connecting through a proxy.
929      */

930     public void setProxyUsername(String proxyUsername) {
931         this.proxyUsername = proxyUsername;
932     }
933
934     /**
935      * Sets the optional proxy user name and returns the updated ClientConfiguration object.
936      *
937      * @param proxyUsername
938      *            The proxy user name to use if connecting through a proxy.
939      * @return The updated ClientConfiguration object.
940      */

941     public ClientConfiguration withProxyUsername(String proxyUsername) {
942         setProxyUsername(proxyUsername);
943         return this;
944     }
945
946     /**
947      * Returns the Java system property for proxy password depending on
948      * {@link #getProtocol()}: i.e. if protocol is https, returns
949      * the value of the system property https.proxyPassword, otherwise
950      * returns value of http.proxyPassword.
951      */

952     private String getProxyPasswordProperty() {
953         return (getProtocol() == Protocol.HTTPS)
954                 ? getSystemProperty("https.proxyPassword")
955                 : getSystemProperty("http.proxyPassword");
956     }
957
958     /**
959      * Returns the environment variable for proxy host depending on
960      * {@link #getProtocol()}: i.e. if protocol is https, returns
961      * the password in the value of the environment variable HTTPS_PROXY/https_proxy,
962      * otherwise, returns the password in the value of the environment
963      * variable HTTP_PROXY/http_proxy.
964      */

965     private String getProxyPasswordEnvironment() {
966         URL httpProxy = getHttpProxyEnvironmentVariable();
967         if (httpProxy != null) {
968             try {
969                 return httpProxy.getUserInfo().split(":", 2)[1];
970             } catch (Exception ignored) {
971             }
972         }
973         return null;
974     }
975
976     /**
977      * Returns the optional proxy password to use if connecting
978      * through a proxy.  Returns either the proxyPassword set on this
979      * object, or if not provided, checks the value of the Java system
980      * property for proxy password according to {@link #getProtocol()}:
981      * i.e. if protocol is https, returns the value of the system
982      * property https.proxyPassword, otherwise returns value of
983      * http.proxyPassword. If neither are set, checks the value of the
984      * environment variable according to {@link #getProtocol()}: i.e. if
985      * protocol is https, returns the password in the value of the
986      * HTTPS_PROXY/https_proxy environment variable, otherwise returns
987      * the password in the value of the HTTP_PROXY/http_proxy environment
988      * variable.
989      *
990      * @return The password to use when connecting through a proxy.
991      */

992     public String getProxyPassword() {
993         if (proxyPassword != null) {
994             return proxyPassword;
995         } else if (getProxyPasswordProperty() != null) {
996             return getProxyPasswordProperty();
997         } else {
998             return getProxyPasswordEnvironment();
999         }
1000     }
1001
1002     /**
1003      * Sets the optional proxy password to use when connecting through a proxy.
1004      *
1005      * @param proxyPassword
1006      *            The password to use when connecting through a proxy.
1007      */

1008     public void setProxyPassword(String proxyPassword) {
1009         this.proxyPassword = proxyPassword;
1010     }
1011
1012     /**
1013      * Sets the optional proxy password to use when connecting through a proxy, and returns the
1014      * updated ClientConfiguration object.
1015      *
1016      * @param proxyPassword
1017      *            The password to use when connecting through a proxy.
1018      * @return The updated ClientConfiguration object.
1019      */

1020     public ClientConfiguration withProxyPassword(String proxyPassword) {
1021         setProxyPassword(proxyPassword);
1022         return this;
1023     }
1024
1025     /**
1026      * Returns the optional Windows domain name for configuring an NTLM proxy. If you aren't using a
1027      * Windows NTLM proxy, you do not need to set this field.
1028      *
1029      * @return The optional Windows domain name for configuring an NTLM proxy.
1030      */

1031     public String getProxyDomain() {
1032         return proxyDomain;
1033     }
1034
1035     /**
1036      * Sets the optional Windows domain name for configuration an NTLM proxy. If you aren't using a
1037      * Windows NTLM proxy, you do not need to set this field.
1038      *
1039      * @param proxyDomain
1040      *            The optional Windows domain name for configuring an NTLM proxy.
1041      */

1042     public void setProxyDomain(String proxyDomain) {
1043         this.proxyDomain = proxyDomain;
1044     }
1045
1046     /**
1047      * Sets the optional Windows domain name for configuration an NTLM proxy and returns a reference
1048      * to this updated ClientConfiguration object so that additional method calls can be chained
1049      * together. If you aren't using a Windows NTLM proxy, you do not need to set this field.
1050      *
1051      * @param proxyDomain
1052      *            The optional Windows domain name for configuring an NTLM proxy.
1053      * @return The updated ClientConfiguration object.
1054      */

1055     public ClientConfiguration withProxyDomain(String proxyDomain) {
1056         setProxyDomain(proxyDomain);
1057         return this;
1058     }
1059
1060     /**
1061      * Returns the optional Windows workstation name for configuring NTLM proxy support. If you
1062      * aren't using a Windows NTLM proxy, you do not need to set this field.
1063      *
1064      * @return The optional Windows workstation name for configuring NTLM proxy support.
1065      */

1066     public String getProxyWorkstation() {
1067         return proxyWorkstation;
1068     }
1069
1070     /**
1071      * Sets the optional Windows workstation name for configuring NTLM proxy support. If you aren't
1072      * using a Windows NTLM proxy, you do not need to set this field.
1073      *
1074      * @param proxyWorkstation
1075      *            The optional Windows workstation name for configuring NTLM proxy support.
1076      */

1077     public void setProxyWorkstation(String proxyWorkstation) {
1078         this.proxyWorkstation = proxyWorkstation;
1079     }
1080
1081     /**
1082      * Sets the optional Windows workstation name for configuring NTLM proxy support, and returns
1083      * the updated ClientConfiguration object so that additional method calls can be chained
1084      * together. If you aren't using a Windows NTLM proxy, you do not need to set this field.
1085      *
1086      * @param proxyWorkstation
1087      *            The optional Windows workstation name for configuring NTLM proxy support.
1088      * @return The updated ClientConfiguration object.
1089      */

1090     public ClientConfiguration withProxyWorkstation(String proxyWorkstation) {
1091         setProxyWorkstation(proxyWorkstation);
1092         return this;
1093     }
1094
1095     /**
1096      * Returns the Java system property for nonProxyHosts. We still honor this property even
1097      * {@link #getProtocol()} is https, see http://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html.
1098      *
1099      * This method expects the property to be set as pipe separated list.
1100      */

1101     private String getNonProxyHostsProperty() {
1102         return getSystemProperty("http.nonProxyHosts");
1103     }
1104
1105     /**
1106      * Returns the value of the environment variable NO_PROXY/no_proxy. This method expects
1107      * the environment variable to be set as a comma separated list, so this method
1108      * converts the comma separated list to pipe separated list to be used internally.
1109      */

1110     private String getNonProxyHostsEnvironment() {
1111         String nonProxyHosts = getEnvironmentVariableCaseInsensitive("NO_PROXY");
1112         if (nonProxyHosts != null) {
1113             nonProxyHosts = nonProxyHosts.replace(",""|");
1114         }
1115
1116         return nonProxyHosts;
1117     }
1118
1119     /**
1120      * Returns the optional hosts the client will access without going
1121      * through the proxy. Returns either the nonProxyHosts set on this
1122      * object, or if not provided, returns the value of the Java system property
1123      * http.nonProxyHosts. We still honor this property even when
1124      * {@link #getProtocol()} is https, see http://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html.
1125      * This property is expected to be set as a pipe separated list. If neither are set,
1126      * returns the value of the environment variable NO_PROXY/no_proxy. This environment
1127      * variable is expected to be set as a comma separated list.
1128      *
1129      * @return The hosts the client will connect through bypassing the proxy.
1130      */

1131     public String getNonProxyHosts() {
1132         if (nonProxyHosts != null) {
1133             return nonProxyHosts;
1134         } else if (getNonProxyHostsProperty() != null) {
1135             return getNonProxyHostsProperty();
1136         } else {
1137             return getNonProxyHostsEnvironment();
1138         }
1139     }
1140
1141     /**
1142      * Set the optional hosts the client will access without going
1143      * through the proxy.
1144      *
1145      * @param nonProxyHosts
1146      *            The hosts the client will access without going through the proxy.
1147      */

1148     public void setNonProxyHosts(String nonProxyHosts) {
1149         this.nonProxyHosts = nonProxyHosts;
1150     }
1151
1152     /**
1153      * Set the optional hosts the client will access without going
1154      * through the proxy.
1155      *
1156      * @param nonProxyHosts
1157      *            The hosts the client will access without going through the proxy.
1158      * @return The updated ClientConfiguration object.
1159      */

1160     public ClientConfiguration withNonProxyHosts(String nonProxyHosts) {
1161         setNonProxyHosts(nonProxyHosts);
1162         return this;
1163     }
1164
1165     /**
1166      * Returns the list of authentication methods that should be used when authenticating against an HTTP proxy, in the order they
1167      * should be attempted.
1168      *
1169      * @return An unmodifiable view of the proxy authentication methods that should be attempted, in order.
1170      */

1171     public List<ProxyAuthenticationMethod> getProxyAuthenticationMethods() {
1172         return this.proxyAuthenticationMethods;
1173     }
1174
1175     /**
1176      * Configure the list of authentication methods that should be used when authenticating against an HTTP proxy, in the order
1177      * they should be attempted. Any methods not included in this list will not be attempted. If one authentication method fails,
1178      * the next method will be attempted, until a working method is found (or all methods have been attempted).
1179      *
1180      * <p>Setting this value to null indicates using the default behavior, which is to try all authentication methods in an
1181      * unspecified order.</p>
1182      *
1183      * @param proxyAuthenticationMethods The proxy authentication methods to be attempted, in the order they should be attempted.
1184      */

1185     public void setProxyAuthenticationMethods(List<ProxyAuthenticationMethod> proxyAuthenticationMethods) {
1186         if(proxyAuthenticationMethods == null) {
1187             this.proxyAuthenticationMethods = null;
1188         } else {
1189             ValidationUtils.assertNotEmpty(proxyAuthenticationMethods, "proxyAuthenticationMethods");
1190             this.proxyAuthenticationMethods =
1191                     Collections.unmodifiableList(new ArrayList<ProxyAuthenticationMethod>(proxyAuthenticationMethods));
1192         }
1193     }
1194
1195     /**
1196      * Configure the list of authentication methods that should be used when authenticating against an HTTP proxy, in the order
1197      * they should be attempted. Any methods not included in this list will not be attempted. If one authentication method fails,
1198      * the next method will be attempted, until a working method is found (or all methods have been attempted).
1199      *
1200      * <p>Setting this value to null indicates using the default behavior, which is to try all authentication methods in an
1201      * unspecified order.</p>
1202      *
1203      * @param proxyAuthenticationMethods The proxy authentication methods to be attempted, in the order they should be attempted.
1204      * @return The updated ClientConfiguration object.
1205      */

1206     public ClientConfiguration withProxyAuthenticationMethods(List<ProxyAuthenticationMethod> proxyAuthenticationMethods) {
1207         setProxyAuthenticationMethods(proxyAuthenticationMethods);
1208         return this;
1209     }
1210
1211     /**
1212      * Returns the retry policy upon failed requests.
1213      *
1214      * @return The retry policy upon failed requests.
1215      */

1216     public RetryPolicy getRetryPolicy() {
1217         return retryPolicy;
1218     }
1219
1220     /**
1221      * Sets the retry policy upon failed requests. User could specify whether the RetryPolicy should
1222      * honor maxErrorRetry set by {@link #setMaxErrorRetry(int)}.
1223      *
1224      * @param retryPolicy
1225      *            The retry policy upon failed requests.
1226      */

1227     public void setRetryPolicy(RetryPolicy retryPolicy) {
1228         this.retryPolicy = retryPolicy;
1229     }
1230
1231     /**
1232      * Sets the retry policy upon failed requests, and returns the updated ClientConfiguration
1233      * object. User could specify whether the RetryPolicy should honor maxErrorRetry set by
1234      * {@link #setMaxErrorRetry(int)}
1235      *
1236      * @param retryPolicy
1237      *            The retry policy upon failed requests.
1238      */

1239     public ClientConfiguration withRetryPolicy(RetryPolicy retryPolicy) {
1240         setRetryPolicy(retryPolicy);
1241         return this;
1242     }
1243
1244     /**
1245      * Returns the maximum number of retry attempts for failed retryable requests (ex: 5xx error
1246      * responses from a service). This method returns -1 before a maxErrorRetry value is explicitly
1247      * set by {@link #setMaxErrorRetry(int)}, in which case the configured RetryPolicy will be used
1248      * to control the retry count.
1249      *
1250      * @return The maximum number of retry attempts for failed retryable requests, or -1 if
1251      *         maxErrorRetry has not been set by {@link #setMaxErrorRetry(int)}.
1252      */

1253     public int getMaxErrorRetry() {
1254         return maxErrorRetry;
1255     }
1256
1257     /**
1258      * Sets the maximum number of retry attempts for failed retryable requests (ex: 5xx error
1259      * responses from services).
1260      *
1261      * @param maxErrorRetry
1262      *            The maximum number of retry attempts for failed retryable requests. This value
1263      *            should not be negative.
1264      */

1265     public void setMaxErrorRetry(int maxErrorRetry) {
1266         if (maxErrorRetry < 0) {
1267             throw new IllegalArgumentException("maxErrorRetry should be non-negative");
1268         }
1269         this.maxErrorRetry = maxErrorRetry;
1270     }
1271
1272     /**
1273      * Sets the maximum number of retry attempts for failed retryable requests (ex: 5xx error
1274      * responses from services), and returns the updated ClientConfiguration object.
1275      *
1276      * @param maxErrorRetry
1277      *            The maximum number of retry attempts for failed retryable requests. This value
1278      *            should not be negative.
1279      * @return The updated ClientConfiguration object.
1280      */

1281     public ClientConfiguration withMaxErrorRetry(int maxErrorRetry) {
1282         setMaxErrorRetry(maxErrorRetry);
1283         return this;
1284     }
1285
1286     /**
1287      * Sets the RetryMode to use
1288      *
1289      * @param retryMode the retryMode
1290      * @return The updated ClientConfiguration object.
1291      */

1292     public ClientConfiguration withRetryMode(RetryMode retryMode) {
1293         setRetryMode(retryMode);
1294         return this;
1295     }
1296
1297     /**
1298      * Sets the RetryMode to use
1299      *
1300      * @param retryMode the retryMode
1301      */

1302     public void setRetryMode(RetryMode retryMode) {
1303         this.retryMode = retryMode;
1304     }
1305
1306     /**
1307      * @return the retryMode
1308      */

1309     public RetryMode getRetryMode() {
1310         return retryMode;
1311     }
1312
1313     /**
1314      * Returns the amount of time to wait (in milliseconds) for data to be transferred over an
1315      * established, open connection before the connection times out and is closed. A value of 0
1316      * means infinity, and isn't recommended.
1317      *
1318      * @return The amount of time to wait (in milliseconds) for data to be transferred over an
1319      *         established, open connection before the connection times out and is closed.
1320      */

1321     public int getSocketTimeout() {
1322         return socketTimeout;
1323     }
1324
1325     /**
1326      * Sets the amount of time to wait (in milliseconds) for data to be transferred over an
1327      * established, open connection before the connection times out and is closed. A value of 0
1328      * means infinity, and isn't recommended.
1329      *
1330      * @param socketTimeout
1331      *            The amount of time to wait (in milliseconds) for data to be transferred over an
1332      *            established, open connection before the connection times out and is closed.
1333      */

1334     public void setSocketTimeout(int socketTimeout) {
1335         this.socketTimeout = socketTimeout;
1336     }
1337
1338     /**
1339      * Sets the amount of time to wait (in milliseconds) for data to be transferred over an
1340      * established, open connection before the connection times out and is closed, and returns the
1341      * updated ClientConfiguration object so that additional method calls may be chained together.
1342      *
1343      * @param socketTimeout
1344      *            The amount of time to wait (in milliseconds) for data to be transferred over an
1345      *            established, open connection before the connection times out and is closed.
1346      * @return The updated ClientConfiguration object.
1347      */

1348     public ClientConfiguration withSocketTimeout(int socketTimeout) {
1349         setSocketTimeout(socketTimeout);
1350         return this;
1351     }
1352
1353     /**
1354      * Returns the amount of time to wait (in milliseconds) when initially establishing a connection
1355      * before giving up and timing out. A value of 0 means infinity, and is not recommended.
1356      *
1357      * @return The amount of time to wait (in milliseconds) when initially establishing a connection
1358      *         before giving up and timing out.
1359      */

1360     public int getConnectionTimeout() {
1361         return connectionTimeout;
1362     }
1363
1364     /**
1365      * Sets the amount of time to wait (in milliseconds) when initially establishing a connection
1366      * before giving up and timing out. A value of 0 means infinity, and is not recommended.
1367      *
1368      * @param connectionTimeout
1369      *            The amount of time to wait (in milliseconds) when initially establishing a
1370      *            connection before giving up and timing out.
1371      */

1372     public void setConnectionTimeout(int connectionTimeout) {
1373         this.connectionTimeout = connectionTimeout;
1374     }
1375
1376     /**
1377      * Sets the amount of time to wait (in milliseconds) when initially establishing a connection
1378      * before giving up and timing out, and returns the updated ClientConfiguration object so that
1379      * additional method calls may be chained together.
1380      *
1381      * @param connectionTimeout
1382      *            the amount of time to wait (in milliseconds) when initially establishing a
1383      *            connection before giving up and timing out.
1384      * @return The updated ClientConfiguration object.
1385      */

1386     public ClientConfiguration withConnectionTimeout(int connectionTimeout) {
1387         setConnectionTimeout(connectionTimeout);
1388         return this;
1389     }
1390
1391     /**
1392      * Returns the amount of time to wait (in milliseconds) for the request to complete before
1393      * giving up and timing out. A non-positive value disables this feature.
1394      * <p>
1395      * This feature requires buffering the entire response (for non-streaming APIs) into memory to
1396      * enforce a hard timeout when reading the response. For APIs that return large responses this
1397      * could be expensive.
1398      * <p>
1399      * <p>
1400      * The request timeout feature doesn't have strict guarantees on how quickly a request is
1401      * aborted when the timeout is breached. The typical case aborts the request within a few
1402      * milliseconds but there may occasionally be requests that don't get aborted until several
1403      * seconds after the timer has been breached. Because of this, the request timeout feature
1404      * should not be used when absolute precision is needed.
1405      * </p>
1406      * <b>Note:</b> This feature is not compatible with Java 1.6.
1407      * </p>
1408      *
1409      * @return The amount of time to wait (in milliseconds) for the request to complete before
1410      *         giving up and timing out.
1411      * @see {@link ClientConfiguration#setClientExecutionTimeout(int)} to enforce a timeout across
1412      *      all retries
1413      */

1414     public int getRequestTimeout() {
1415         return requestTimeout;
1416     }
1417
1418     /**
1419      * Sets the amount of time to wait (in milliseconds) for the request to complete before giving
1420      * up and timing out. A non-positive value disables this feature.
1421      * <p>
1422      * This feature requires buffering the entire response (for non-streaming APIs) into memory to
1423      * enforce a hard timeout when reading the response. For APIs that return large responses this
1424      * could be expensive.
1425      * <p>
1426      * <p>
1427      * The request timeout feature doesn't have strict guarantees on how quickly a request is
1428      * aborted when the timeout is breached. The typical case aborts the request within a few
1429      * milliseconds but there may occasionally be requests that don't get aborted until several
1430      * seconds after the timer has been breached. Because of this, the request timeout feature
1431      * should not be used when absolute precision is needed.
1432      * </p>
1433      * <p>
1434      * <b>Note:</b> This feature is not compatible with Java 1.6.
1435      * </p>
1436      *
1437      * @param requestTimeout
1438      *            The amount of time to wait (in milliseconds) for the request to complete before
1439      *            giving up and timing out.
1440      * @see {@link ClientConfiguration#setClientExecutionTimeout(int)} to enforce a timeout across
1441      *      all retries
1442      */

1443     public void setRequestTimeout(int requestTimeout) {
1444         this.requestTimeout = requestTimeout;
1445     }
1446
1447     /**
1448      * Sets the amount of time to wait (in milliseconds) for the request to complete before giving
1449      * up and timing out. A non-positive value disables this feature. Returns the updated
1450      * ClientConfiguration object so that additional method calls may be chained together.
1451      * <p>
1452      * This feature requires buffering the entire response (for non-streaming APIs) into memory to
1453      * enforce a hard timeout when reading the response. For APIs that return large responses this
1454      * could be expensive.
1455      * <p>
1456      * <p>
1457      * The request timeout feature doesn't have strict guarantees on how quickly a request is
1458      * aborted when the timeout is breached. The typical case aborts the request within a few
1459      * milliseconds but there may occasionally be requests that don't get aborted until several
1460      * seconds after the timer has been breached. Because of this, the request timeout feature
1461      * should not be used when absolute precision is needed.
1462      * </p>
1463      * <p>
1464      * <b>Note:</b> This feature is not compatible with Java 1.6.
1465      * </p>
1466      *
1467      * @param requestTimeout
1468      *            The amount of time to wait (in milliseconds) for the request to complete before
1469      *            giving up and timing out.
1470      * @return The updated ClientConfiguration object.
1471      * @see {@link ClientConfiguration#setClientExecutionTimeout(int)} to enforce a timeout across
1472      *      all retries
1473      */

1474     public ClientConfiguration withRequestTimeout(int requestTimeout) {
1475         setRequestTimeout(requestTimeout);
1476         return this;
1477     }
1478
1479     /**
1480      * Returns the amount of time (in milliseconds) to allow the client to complete the execution of
1481      * an API call. This timeout covers the entire client execution except for marshalling. This
1482      * includes request handler execution, all HTTP request including retries, unmarshalling, etc.
1483      * <p>
1484      * This feature requires buffering the entire response (for non-streaming APIs) into memory to
1485      * enforce a hard timeout when reading the response. For APIs that return large responses this
1486      * could be expensive.
1487      * <p>
1488      * <p>
1489      * The client execution timeout feature doesn't have strict guarantees on how quickly a request
1490      * is aborted when the timeout is breached. The typical case aborts the request within a few
1491      * milliseconds but there may occasionally be requests that don't get aborted until several
1492      * seconds after the timer has been breached. Because of this, the client execution timeout
1493      * feature should not be used when absolute precision is needed.
1494      * </p>
1495      * <p>
1496      * This may be used together with {@link ClientConfiguration#setRequestTimeout(int)} to enforce
1497      * both a timeout on each individual HTTP request (i.e. each retry) and the total time spent on
1498      * all requests across retries (i.e. the 'client execution' time). A non-positive value disables
1499      * this feature.
1500      * </p>
1501      * <p>
1502      * <b>Note:</b> This feature is not compatible with Java 1.6.
1503      * </p>
1504      *
1505      * @return The amount of time (in milliseconds) to allow the client to complete the execution of
1506      *         an API call.
1507      * @see {@link ClientConfiguration#setRequestTimeout(int)} to enforce a timeout per HTTP request
1508      */

1509     public int getClientExecutionTimeout() {
1510         return this.clientExecutionTimeout;
1511     }
1512
1513     /**
1514      * Sets the amount of time (in milliseconds) to allow the client to complete the execution of
1515      * an API call. This timeout covers the entire client execution except for marshalling. This
1516      * includes request handler execution, all HTTP request including retries, unmarshalling, etc.
1517      * <p>
1518      * This feature requires buffering the entire response (for non-streaming APIs) into memory to
1519      * enforce a hard timeout when reading the response. For APIs that return large responses this
1520      * could be expensive.
1521      * <p>
1522      * <p>
1523      * The client execution timeout feature doesn't have strict guarantees on how quickly a request
1524      * is aborted when the timeout is breached. The typical case aborts the request within a few
1525      * milliseconds but there may occasionally be requests that don't get aborted until several
1526      * seconds after the timer has been breached. Because of this, the client execution timeout
1527      * feature should not be used when absolute precision is needed.
1528      * </p>
1529      * <p>
1530      * This may be used together with {@link ClientConfiguration#setRequestTimeout(int)} to enforce
1531      * both a timeout on each individual HTTP request (i.e. each retry) and the total time spent on
1532      * all requests across retries (i.e. the 'client execution' time). A non-positive value disables
1533      * this feature.
1534      * </p>
1535      * <p>
1536      * <b>Note:</b> This feature is not compatible with Java 1.6.
1537      * </p>
1538      *
1539      * @param clientExecutionTimeout
1540      *            The amount of time (in milliseconds) to allow the client to complete the execution
1541      *            of an API call. A value of '0' disables this feature.
1542      * @see {@link ClientConfiguration#setRequestTimeout(int)} to enforce a timeout per HTTP request
1543      */

1544     public void setClientExecutionTimeout(int clientExecutionTimeout) {
1545         this.clientExecutionTimeout = clientExecutionTimeout;
1546     }
1547
1548     /**
1549      * Sets the amount of time (in milliseconds) to allow the client to complete the execution of
1550      * an API call. This timeout covers the entire client execution except for marshalling. This
1551      * includes request handler execution, all HTTP request including retries, unmarshalling, etc.
1552      * <p>
1553      * This feature requires buffering the entire response (for non-streaming APIs) into memory to
1554      * enforce a hard timeout when reading the response. For APIs that return large responses this
1555      * could be expensive.
1556      * <p>
1557      * <p>
1558      * The client execution timeout feature doesn't have strict guarantees on how quickly a request
1559      * is aborted when the timeout is breached. The typical case aborts the request within a few
1560      * milliseconds but there may occasionally be requests that don't get aborted until several
1561      * seconds after the timer has been breached. Because of this, the client execution timeout
1562      * feature should not be used when absolute precision is needed.
1563      * </p>
1564      * <p>
1565      * This may be used together with {@link ClientConfiguration#setRequestTimeout(int)} to enforce
1566      * both a timeout on each individual HTTP request (i.e. each retry) and the total time spent on
1567      * all requests across retries (i.e. the 'client execution' time). A non-positive value disables
1568      * this feature.
1569      * </p>
1570      * <p>
1571      * <b>Note:</b> This feature is not compatible with Java 1.6.
1572      * </p>
1573      *
1574      * @param clientExecutionTimeout
1575      *            The amount of time (in milliseconds) to allow the client to complete the execution
1576      *            of an API call. A value of '0' disables this feature.
1577      * @return The updated ClientConfiguration object for method chaining
1578      * @see {@link ClientConfiguration#setRequestTimeout(int)} to enforce a timeout per HTTP request
1579      */

1580     public ClientConfiguration withClientExecutionTimeout(int clientExecutionTimeout) {
1581         setClientExecutionTimeout(clientExecutionTimeout);
1582         return this;
1583     }
1584
1585     /**
1586      * Checks if the {@link IdleConnectionReaper} is to be started
1587      *
1588      * @return if the {@link IdleConnectionReaper} is to be started
1589      */

1590     public boolean useReaper() {
1591         return useReaper;
1592     }
1593
1594     /**
1595      * Sets whether the {@link IdleConnectionReaper} is to be started as a daemon thread
1596      *
1597      * @param use
1598      *            whether the {@link IdleConnectionReaper} is to be started as a daemon thread
1599      * @see IdleConnectionReaper
1600      */

1601     public void setUseReaper(boolean use) {
1602         this.useReaper = use;
1603     }
1604
1605     /**
1606      * Sets whether the {@link IdleConnectionReaper} is to be started as a daemon thread
1607      *
1608      * @param use
1609      *            the {@link IdleConnectionReaper} is to be started as a daemon thread
1610      * @return The updated ClientConfiguration object.
1611      */

1612     public ClientConfiguration withReaper(boolean use) {
1613         setUseReaper(use);
1614         return this;
1615     }
1616
1617     /**
1618      * Returns whether retry throttling will be used.
1619      * <p>
1620      * Retry throttling is a feature which intelligently throttles retry attempts when a
1621      * large percentage of requests are failing and retries are unsuccessful, particularly
1622      * in scenarios of degraded service health.  In these situations the client will drain its
1623      * internal retry capacity and slowly roll off from retry attempts until requests begin
1624      * to succeed again.  At that point the retry capacity pool will begin to refill and
1625      * retries will once again be permitted.
1626      * </p>
1627      * <p>
1628      * In situations where retries have been throttled this feature will effectively result in
1629      * fail-fast behavior from the client.  Because retries are circumvented exceptions will
1630      * be immediately returned to the caller if the initial request is unsuccessful.  This
1631      * will result in a greater number of exceptions being returned up front but prevents
1632      * requests being tied up attempting subsequent retries which are also likely to fail.
1633      * </p>
1634      *
1635      * @return true if retry throttling will be used
1636      */

1637     public boolean useThrottledRetries() {
1638         return throttleRetries || getSystemProperty(
1639                 SDKGlobalConfiguration.RETRY_THROTTLING_SYSTEM_PROPERTY) != null;
1640     }
1641
1642     /**
1643      * Sets whether throttled retries should be used
1644      * <p>
1645      * Retry throttling is a feature which intelligently throttles retry attempts when a
1646      * large percentage of requests are failing and retries are unsuccessful, particularly
1647      * in scenarios of degraded service health.  In these situations the client will drain its
1648      * internal retry capacity and slowly roll off from retry attempts until requests begin
1649      * to succeed again.  At that point the retry capacity pool will begin to refill and
1650      * retries will once again be permitted.
1651      * </p>
1652      * <p>
1653      * In situations where retries have been throttled this feature will effectively result in
1654      * fail-fast behavior from the client.  Because retries are circumvented exceptions will
1655      * be immediately returned to the caller if the initial request is unsuccessful.  This
1656      * will result in a greater number of exceptions being returned up front but prevents
1657      * requests being tied up attempting subsequent retries which are also likely to fail.
1658      * </p>
1659      *
1660      * @param use
1661      *            true if throttled retries should be used
1662      */

1663     public void setUseThrottleRetries(boolean use) { this.throttleRetries = use; }
1664
1665     /**
1666      * Sets whether throttled retries should be used
1667      * <p>
1668      * Retry throttling is a feature which intelligently throttles retry attempts when a
1669      * large percentage of requests are failing and retries are unsuccessful, particularly
1670      * in scenarios of degraded service health.  In these situations the client will drain its
1671      * internal retry capacity and slowly roll off from retry attempts until requests begin
1672      * to succeed again.  At that point the retry capacity pool will begin to refill and
1673      * retries will once again be permitted.
1674      * </p>
1675      * <p>
1676      * In situations where retries have been throttled this feature will effectively result in
1677      * fail-fast behavior from the client.  Because retries are circumvented exceptions will
1678      * be immediately returned to the caller if the initial request is unsuccessful.  This
1679      * will result in a greater number of exceptions being returned up front but prevents
1680      * requests being tied up attempting subsequent retries which are also likely to fail.
1681      * </p>
1682
1683      * @param use
1684      *            true if throttled retries should be used
1685      * @return The updated ClientConfiguration object.
1686      */

1687     public ClientConfiguration withThrottledRetries(boolean use) {
1688         setUseThrottleRetries(use);
1689         return this;
1690     }
1691
1692     /**
1693      * Set the maximum number of consecutive failed retries that the client will permit before
1694      * throttling all subsequent retries of failed requests.
1695      * <p>
1696      * Note: This does not guarantee that each failed request will be retried up to this many times.
1697      * Depending on the configured {@link RetryPolicy} and the number of past failed and successful
1698      * requests, the actual number of retries attempted may be less.
1699      * <p>
1700      * This has a default value of {@link #DEFAULT_MAX_CONSECUTIVE_RETRIES_BEFORE_THROTTLING}.
1701      *
1702      * @param maxConsecutiveRetriesBeforeThrottling The maximum number of consecutive retries.
1703      */

1704     public void setMaxConsecutiveRetriesBeforeThrottling(int maxConsecutiveRetriesBeforeThrottling) {
1705         this.maxConsecutiveRetriesBeforeThrottling = ValidationUtils.assertIsPositive(maxConsecutiveRetriesBeforeThrottling,
1706                 "maxConsecutiveRetriesBeforeThrottling");
1707     }
1708     /**
1709      * Set the maximum number of consecutive failed retries that the client will permit before
1710      * throttling all subsequent retries of failed requests.
1711      * <p>
1712      * Note: This does not guarantee that each failed request will be retried up to this many times.
1713      * Depending on the configured {@link RetryPolicy} and the number of past failed and successful
1714      * requests, the actual number of retries attempted may be less.
1715      * <p>
1716      * This has a default value of {@link #DEFAULT_MAX_CONSECUTIVE_RETRIES_BEFORE_THROTTLING}.
1717      *
1718      * @param maxConsecutiveRetriesBeforeThrottling The maximum number of consecutive retries.
1719      *
1720      * @return This object for chaining.
1721      */

1722     public ClientConfiguration withMaxConsecutiveRetriesBeforeThrottling(int maxConsecutiveRetriesBeforeThrottling) {
1723         setMaxConsecutiveRetriesBeforeThrottling(maxConsecutiveRetriesBeforeThrottling);
1724         return this;
1725     }
1726
1727     /**
1728      * @return Set the maximum number of consecutive failed retries that the client will permit
1729      * before throttling all subsequent retries of failed requests.
1730      */

1731     public int getMaxConsecutiveRetriesBeforeThrottling() {
1732         return maxConsecutiveRetriesBeforeThrottling;
1733     }
1734
1735     /**
1736      * Checks if gzip decompression is used when receiving HTTP responses.
1737      *
1738      * @return if gzip decompression is used
1739      */

1740     public boolean useGzip() {
1741         return useGzip;
1742     }
1743
1744     /**
1745      * Sets whether gzip decompression should be used when receiving HTTP responses.
1746      *
1747      * <p>
1748      * <b>Note</b>
1749      * useGzip should only be enabled if the HTTP response is gzipped
1750      *
1751      * @param use
1752      *            whether gzip decompression should be used
1753      */

1754     public void setUseGzip(boolean use) {
1755         this.useGzip = use;
1756     }
1757
1758     /**
1759      * Sets whether gzip decompression should be used when receiving HTTP responses.
1760      *
1761      * <p>
1762      * <b>Note</b>
1763      * useGzip should only be enabled if the HTTP response is gzipped
1764      *
1765      * @param use
1766      *            whether gzip decompression should be used
1767      * @return The updated ClientConfiguration object.
1768      */

1769     public ClientConfiguration withGzip(boolean use) {
1770         setUseGzip(use);
1771         return this;
1772     }
1773
1774     /**
1775      * Returns the optional size hints (in bytes) for the low level TCP send and receive buffers.
1776      * This is an advanced option for advanced users who want to tune low level TCP parameters to
1777      * try and squeeze out more performance.
1778      * <p>
1779      * The optimal TCP buffer sizes for a particular application are highly dependent on network
1780      * configuration and operating system configuration and capabilities. For example, most modern
1781      * operating systems provide auto-tuning functionality for TCP buffer sizes, which can have a
1782      * big impact on performance for TCP connections that are held open long enough for the
1783      * auto-tuning to optimize buffer sizes.
1784      * <p>
1785      * Large buffer sizes (ex: 2MB) will allow the operating system to buffer more data in memory
1786      * without requiring the remote server to acknowledge receipt of that information, so can be
1787      * particularly useful when the network has high latency.
1788      * <p>
1789      * This is only a <b>hint</b>, and the operating system may choose not to honor it. When using
1790      * this option, users should <b>always</b> check the operating system's configured limits and
1791      * defaults. Most OS's have a maximum TCP buffer size limit configured, and won't let you go
1792      * beyond that limit unless you explicitly raise the max TCP buffer size limit.
1793      * <p>
1794      * There are many resources available online to help with configuring TCP buffer sizes and
1795      * operating system specific TCP settings, including:
1796      * <ul>
1797      * <li>http://onlamp.com/pub/a/onlamp/2005/11/17/tcp_tuning.html</li>
1798      * <li>http://fasterdata.es.net/TCP-tuning/</li>
1799      * </ul>
1800      *
1801      * @return A two element array containing first the TCP send buffer size hint and then the TCP
1802      *         receive buffer size hint.
1803      */

1804     public int[] getSocketBufferSizeHints() {
1805         return new int[] { socketSendBufferSizeHint, socketReceiveBufferSizeHint };
1806     }
1807
1808     /**
1809      * Sets the optional size hints (in bytes) for the low level TCP send and receive buffers. This
1810      * is an advanced option for advanced users who want to tune low level TCP parameters to try and
1811      * squeeze out more performance.
1812      * <p>
1813      * The optimal TCP buffer sizes for a particular application are highly dependent on network
1814      * configuration and operating system configuration and capabilities. For example, most modern
1815      * operating systems provide auto-tuning functionality for TCP buffer sizes, which can have a
1816      * big impact on performance for TCP connections that are held open long enough for the
1817      * auto-tuning to optimize buffer sizes.
1818      * <p>
1819      * Large buffer sizes (ex: 2MB) will allow the operating system to buffer more data in memory
1820      * without requiring the remote server to acknowledge receipt of that information, so can be
1821      * particularly useful when the network has high latency.
1822      * <p>
1823      * This is only a <b>hint</b>, and the operating system may choose not to honor it. When using
1824      * this option, users should <b>always</b> check the operating system's configured limits and
1825      * defaults. Most OS's have a maximum TCP buffer size limit configured, and won't let you go
1826      * beyond that limit unless you explicitly raise the max TCP buffer size limit.
1827      * <p>
1828      * There are many resources available online to help with configuring TCP buffer sizes and
1829      * operating system specific TCP settings, including:
1830      * <ul>
1831      * <li>http://onlamp.com/pub/a/onlamp/2005/11/17/tcp_tuning.html</li>
1832      * <li>http://fasterdata.es.net/TCP-tuning/</li>
1833      * </ul>
1834      *
1835      * @param socketSendBufferSizeHint
1836      *            The size hint (in bytes) for the low level TCP send buffer.
1837      * @param socketReceiveBufferSizeHint
1838      *            The size hint (in bytes) for the low level TCP receive buffer.
1839      */

1840     public void setSocketBufferSizeHints(int socketSendBufferSizeHint, int socketReceiveBufferSizeHint) {
1841         this.socketSendBufferSizeHint = socketSendBufferSizeHint;
1842         this.socketReceiveBufferSizeHint = socketReceiveBufferSizeHint;
1843     }
1844
1845     /**
1846      * Sets the optional size hints (in bytes) for the low level TCP send and receive buffers, and
1847      * returns the updated ClientConfiguration object so that additional method calls may be chained
1848      * together.
1849      * <p>
1850      * This is an advanced option for advanced users who want to tune low level TCP parameters to
1851      * try and squeeze out more performance.
1852      * <p>
1853      * The optimal TCP buffer sizes for a particular application are highly dependent on network
1854      * configuration and operating system configuration and capabilities. For example, most modern
1855      * operating systems provide auto-tuning functionality for TCP buffer sizes, which can have a
1856      * big impact on performance for TCP connections that are held open long enough for the
1857      * auto-tuning to optimize buffer sizes.
1858      * <p>
1859      * Large buffer sizes (ex: 2MB) will allow the operating system to buffer more data in memory
1860      * without requiring the remote server to acknowledge receipt of that information, so can be
1861      * particularly useful when the network has high latency.
1862      * <p>
1863      * This is only a <b>hint</b>, and the operating system may choose not to honor it. When using
1864      * this option, users should <b>always</b> check the operating system's configured limits and
1865      * defaults. Most OS's have a maximum TCP buffer size limit configured, and won't let you go
1866      * beyond that limit unless you explicitly raise the max TCP buffer size limit.
1867      * <p>
1868      * There are many resources available online to help with configuring TCP buffer sizes and
1869      * operating system specific TCP settings, including:
1870      * <ul>
1871      * <li>http://onlamp.com/pub/a/onlamp/2005/11/17/tcp_tuning.html</li>
1872      * <li>http://fasterdata.es.net/TCP-tuning/</li>
1873      * </ul>
1874      *
1875      * @param socketSendBufferSizeHint
1876      *            The size hint (in bytes) for the low level TCP send buffer.
1877      * @param socketReceiveBufferSizeHint
1878      *            The size hint (in bytes) for the low level TCP receive buffer.
1879      * @return The updated ClientConfiguration object.
1880      */

1881     public ClientConfiguration withSocketBufferSizeHints(int socketSendBufferSizeHint,
1882                                                          int socketReceiveBufferSizeHint) {
1883         setSocketBufferSizeHints(socketSendBufferSizeHint, socketReceiveBufferSizeHint);
1884         return this;
1885     }
1886
1887     /**
1888      * Returns the name of the signature algorithm to use for signing requests made by this client.
1889      * If not set or explicitly set to null, the client will choose a signature algorithm to use
1890      * based on a configuration file of supported signature algorithms for the service and region.
1891      * <p>
1892      * Most users do not need to concern themselves with which signature algorithm is being used, as
1893      * the defaults will be sufficient. This setting exists only so advanced users can opt in to
1894      * newer signature protocols which have not yet been made the default for a particular
1895      * service/region.
1896      * <p>
1897      * Not all services support all signature algorithms, and configuring an unsupported signature
1898      * algorithm will lead to authentication failures. Use me at your own risk, and only after
1899      * consulting the documentation for the service to ensure it actually does supports your chosen
1900      * algorithm.
1901      * <p>
1902      * If non-null, the name returned from this method is used to look up a {@code Signer} class
1903      * implementing the chosen algorithm by the {@code com.amazonaws.auth.SignerFactory} class.
1904      *
1905      * @return The signature algorithm to use for this client, or null to use the default.
1906      */

1907     public String getSignerOverride() {
1908         return signerOverride;
1909     }
1910
1911     /**
1912      * Sets the name of the signature algorithm to use for signing requests made by this client. If
1913      * not set or explicitly set to null, the client will choose a signature algorithm to use based
1914      * on a configuration file of supported signature algorithms for the service and region.
1915      * <p>
1916      * Most users do not need to concern themselves with which signature algorithm is being used, as
1917      * the defaults will be sufficient. This setting exists only so advanced users can opt in to
1918      * newer signature protocols which have not yet been made the default for a particular
1919      * service/region.
1920      * <p>
1921      * Not all services support all signature algorithms, and configuring an unsupported signature
1922      * algorithm will lead to authentication failures. Use me at your own risk, and only after
1923      * consulting the documentation for the service to ensure it actually does supports your chosen
1924      * algorithm.
1925      * <p>
1926      * If non-null, the name returned from this method is used to look up a {@code Signer} class
1927      * implementing the chosen algorithm by the {@code com.amazonaws.auth.SignerFactory} class.
1928      *
1929      * @param value
1930      *            The signature algorithm to use for this client, or null to use the default.
1931      */

1932     public void setSignerOverride(final String value) {
1933         signerOverride = value;
1934     }
1935
1936     /**
1937      * Sets the name of the signature algorithm to use for signing requests made by this client. If
1938      * not set or explicitly set to null, the client will choose a signature algorithm to use based
1939      * on a configuration file of supported signature algorithms for the service and region.
1940      * <p>
1941      * Most users do not need to concern themselves with which signature algorithm is being used, as
1942      * the defaults will be sufficient. This setting exists only so advanced users can opt in to
1943      * newer signature protocols which have not yet been made the default for a particular
1944      * service/region.
1945      * <p>
1946      * Not all services support all signature algorithms, and configuring an unsupported signature
1947      * algorithm will lead to authentication failures. Use me at your own risk, and only after
1948      * consulting the documentation for the service to ensure it actually does supports your chosen
1949      * algorithm.
1950      * <p>
1951      * If non-null, the name returned from this method is used to look up a {@code Signer} class
1952      * implementing the chosen algorithm by the {@code com.amazonaws.auth.SignerFactory} class.
1953      *
1954      * @param value
1955      *            The signature algorithm to use for this client, or null to use the default.
1956      * @return The updated ClientConfiguration object.
1957      */

1958     public ClientConfiguration withSignerOverride(final String value) {
1959         setSignerOverride(value);
1960         return this;
1961     }
1962
1963     /**
1964      * Returns whether to attempt to authenticate preemptively against proxy servers using basic
1965      * authentication
1966      *
1967      * @return Whether to authenticate preemptively against proxy server.
1968      */

1969     public boolean isPreemptiveBasicProxyAuth() {
1970         return preemptiveBasicProxyAuth;
1971     }
1972
1973     /**
1974      * Sets whether to attempt to authenticate preemptively against proxy servers using basic
1975      * authentication
1976      *
1977      * @param preemptiveBasicProxyAuth
1978      *            Whether to authenticate preemptively against proxy server.
1979      */

1980     public void setPreemptiveBasicProxyAuth(Boolean preemptiveBasicProxyAuth) {
1981         this.preemptiveBasicProxyAuth = preemptiveBasicProxyAuth;
1982     }
1983
1984     /**
1985      * Sets whether to attempt to authenticate preemptively against proxy servers using basic
1986      * authentication, and returns the updated ClientConfiguration object so that additional method
1987      * calls may be chained together.
1988      *
1989      * @param preemptiveBasicProxyAuth
1990      *            Whether to authenticate preemptively against proxy server.
1991      * @return The updated ClientConfiguration object.
1992      */

1993     public ClientConfiguration withPreemptiveBasicProxyAuth(boolean preemptiveBasicProxyAuth) {
1994         setPreemptiveBasicProxyAuth(preemptiveBasicProxyAuth);
1995         return this;
1996     }
1997
1998     /**
1999      * Returns the expiration time (in milliseconds) for a connection in the connection pool. When
2000      * retrieving a connection from the pool to make a request, the total time that the connection
2001      * has been open is compared against this value. Connections which have been open for longer are
2002      * discarded, and if needed a new connection is created.
2003      * <p>
2004      * Tuning this setting down (together with an appropriately-low setting for Java's DNS cache
2005      * TTL) ensures that your application will quickly rotate over to new IP addresses when the
2006      * service begins announcing them through DNS, at the cost of having to re-establish new
2007      * connections more frequently.
2008      *
2009      * @return the connection TTL, in milliseconds
2010      */

2011     public long getConnectionTTL() {
2012         return connectionTTL;
2013     }
2014
2015     /**
2016      * Sets the expiration time (in milliseconds) for a connection in the connection pool. When
2017      * retrieving a connection from the pool to make a request, the total time that the connection
2018      * has been open is compared against this value. Connections which have been open for longer are
2019      * discarded, and if needed a new connection is created.
2020      * <p>
2021      * Tuning this setting down (together with an appropriately-low setting for Java's DNS cache
2022      * TTL) ensures that your application will quickly rotate over to new IP addresses when the
2023      * service begins announcing them through DNS, at the cost of having to re-establish new
2024      * connections more frequently.
2025      * <p>
2026      * By default, it is set to {@code -1], i.e. connections do not expire.
2027      *
2028      * @param connectionTTL
2029      *            the connection TTL, in milliseconds
2030      */

2031     public void setConnectionTTL(long connectionTTL) {
2032         this.connectionTTL = connectionTTL;
2033     }
2034
2035     /**
2036      * Sets the expiration time (in milliseconds) for a connection in the connection pool. When
2037      * retrieving a connection from the pool to make a request, the total time that the connection
2038      * has been open is compared against this value. Connections which have been open for longer are
2039      * discarded, and if needed a new connection is created.
2040      * <p>
2041      * Tuning this setting down (together with an appropriately-low setting for Java's DNS cache
2042      * TTL) ensures that your application will quickly rotate over to new IP addresses when the
2043      * service begins announcing them through DNS, at the cost of having to re-establish new
2044      * connections more frequently.
2045      * <p>
2046      * By default, it is set to {@code -1}, i.e. connections do not expire.
2047      *
2048      * @param connectionTTL
2049      *            the connection TTL, in milliseconds
2050      * @return the updated ClientConfiguration object
2051      */

2052     public ClientConfiguration withConnectionTTL(long connectionTTL) {
2053         setConnectionTTL(connectionTTL);
2054         return this;
2055     }
2056
2057     /**
2058      * Returns the maximum amount of time that an idle connection may sit in the connection pool and
2059      * still be eligible for reuse. When retrieving a connection from the pool to make a request,
2060      * the amount of time the connection has been idle is compared against this value. Connections
2061      * which have been idle for longer are discarded, and if needed a new connection is created.
2062      * <p>
2063      * Tuning this setting down reduces the likelihood of a race condition (wherein you begin
2064      * sending a request down a connection which appears to be healthy, but before it arrives the
2065      * service decides the connection has been idle for too long and closes it) at the cost of
2066      * having to re-establish new connections more frequently.
2067      *
2068      * @return the connection maximum idle time, in milliseconds
2069      */

2070     public long getConnectionMaxIdleMillis() {
2071         return connectionMaxIdleMillis;
2072     }
2073
2074     /**
2075      * Sets the maximum amount of time that an idle connection may sit in the connection pool and
2076      * still be eligible for reuse. When retrieving a connection from the pool to make a request,
2077      * the amount of time the connection has been idle is compared against this value. Connections
2078      * which have been idle for longer are discarded, and if needed a new connection is created.
2079      * <p>
2080      * Tuning this setting down reduces the likelihood of a race condition (wherein you begin
2081      * sending a request down a connection which appears to be healthy, but before it arrives the
2082      * service decides the connection has been idle for too long and closes it) at the cost of
2083      * having to re-establish new connections more frequently.
2084      * <p>
2085      * By default, it is set to one minute (60000ms).
2086      *
2087      * @param connectionMaxIdleMillis
2088      *            the connection maximum idle time, in milliseconds
2089      */

2090     public void setConnectionMaxIdleMillis(long connectionMaxIdleMillis) {
2091         this.connectionMaxIdleMillis = connectionMaxIdleMillis;
2092     }
2093
2094     /**
2095      * Sets the maximum amount of time that an idle connection may sit in the connection pool and
2096      * still be eligible for reuse. When retrieving a connection from the pool to make a request,
2097      * the amount of time the connection has been idle is compared against this value. Connections
2098      * which have been idle for longer are discarded, and if needed a new connection is created.
2099      * <p>
2100      * Tuning this setting down reduces the likelihood of a race condition (wherein you begin
2101      * sending a request down a connection which appears to be healthy, but before it arrives the
2102      * service decides the connection has been idle for too long and closes it) at the cost of
2103      * having to re-establish new connections more frequently.
2104      * <p>
2105      * By default, it is set to one minute (60000ms).
2106      *
2107      * @param connectionMaxIdleMillis
2108      *            the connection maximum idle time, in milliseconds
2109      * @return the updated ClientConfiguration object
2110      */

2111     public ClientConfiguration withConnectionMaxIdleMillis(long connectionMaxIdleMillis) {
2112
2113         setConnectionMaxIdleMillis(connectionMaxIdleMillis);
2114         return this;
2115     }
2116
2117     /**
2118      * Returns the amount of time (in milliseconds) that a connection can be idle in the connection pool before it must be
2119      * validated to ensure it's still open. This "stale connection check" adds a small bit of overhead to validate the
2120      * connection. Setting this value to larger values may increase the likelihood that the connection is not usable, potentially
2121      * resulting in a {@link org.apache.http.NoHttpResponseException}. Lowering this setting increases the overhead when leasing
2122      * connections from the connection pool. It is recommended to tune this setting based on how long a service allows a
2123      * connection to be idle before closing.
2124      *
2125      * <p>A non positive value disables validation of connections.</p>
2126      *
2127      * <p>The default value is {@value #DEFAULT_VALIDATE_AFTER_INACTIVITY_MILLIS} milliseconds.</p>
2128      */

2129     public int getValidateAfterInactivityMillis() {
2130         return validateAfterInactivityMillis;
2131     }
2132
2133     /**
2134      * Sets the amount of time (in milliseconds) that a connection can be idle in the connection pool before it must be validated
2135      * to ensure it's still open. This "stale connection check" adds a small bit of overhead to validate the connection. Setting
2136      * this value to larger values may increase the likelihood that the connection is not usable, potentially resulting in a
2137      * {@link org.apache.http.NoHttpResponseException}. Lowering this setting increases the overhead when leasing connections
2138      * from the connection pool. It is recommended to tune this setting based on how long a service allows a connection to be
2139      * idle before closing.
2140      *
2141      * <p>A non positive value disables validation of connections.</p>
2142      *
2143      * <p>The default value is {@value #DEFAULT_VALIDATE_AFTER_INACTIVITY_MILLIS} milliseconds.</p>
2144      *
2145      * @param validateAfterInactivityMillis The allowed time, in milliseconds, a connection can be idle before it must be
2146      *                                      re-validated.
2147      */

2148     public void setValidateAfterInactivityMillis(int validateAfterInactivityMillis) {
2149         this.validateAfterInactivityMillis = validateAfterInactivityMillis;
2150     }
2151
2152     /**
2153      * Sets the amount of time (in milliseconds) that a connection can be idle in the connection pool before it must be validated
2154      * to ensure it's still open. This "stale connection check" adds a small bit of overhead to validate the connection. Setting
2155      * this value to larger values may increase the likelihood that the connection is not usable, potentially resulting in a
2156      * {@link org.apache.http.NoHttpResponseException}. Lowering this setting increases the overhead when leasing connections
2157      * from the connection pool. It is recommended to tune this setting based on how long a service allows a connection to be
2158      * idle before closing.
2159      *
2160      * <p>A non positive value disables validation of connections.</p>
2161      *
2162      * <p>The default value is {@value #DEFAULT_VALIDATE_AFTER_INACTIVITY_MILLIS} milliseconds.</p>
2163      *
2164      * @param validateAfterInactivityMillis The allowed time, in milliseconds, a connection can be idle before it must be
2165      *                                      re-validated.
2166      * @return The updated {@link ClientConfiguration} object.
2167      */

2168     public ClientConfiguration withValidateAfterInactivityMillis(int validateAfterInactivityMillis) {
2169         setValidateAfterInactivityMillis(validateAfterInactivityMillis);
2170         return this;
2171     }
2172
2173     /**
2174      * Returns whether or not TCP KeepAlive support is enabled.
2175      */

2176     public boolean useTcpKeepAlive() {
2177         return tcpKeepAlive;
2178     }
2179
2180     /**
2181      * Sets whether or not to enable TCP KeepAlive support at the socket level.
2182      */

2183     public void setUseTcpKeepAlive(final boolean use) {
2184         this.tcpKeepAlive = use;
2185     }
2186
2187     /**
2188      * Sets whether or not to enable TCP KeepAlive support at the socket level.
2189      *
2190      * @return The updated ClientConfiguration object.
2191      */

2192     public ClientConfiguration withTcpKeepAlive(final boolean use) {
2193         setUseTcpKeepAlive(use);
2194         return this;
2195     }
2196
2197     /**
2198      * Returns the DnsResolver for resolving AWS IP addresses.
2199      * Returns the {@link SystemDefaultDnsResolver} by default if not
2200      * explicitly configured by the user.
2201      */

2202     public DnsResolver getDnsResolver() {
2203         return dnsResolver;
2204     }
2205
2206     /**
2207      * Sets the DNS Resolver that should be used to for resolving AWS IP addresses.
2208      */

2209     public void setDnsResolver(final DnsResolver resolver) {
2210         if (resolver == null) {
2211             throw new IllegalArgumentException("resolver cannot be null");
2212         }
2213         this.dnsResolver = resolver;
2214     }
2215
2216     /**
2217      * Sets the DNS Resolver that should be used to for resolving AWS IP addresses.
2218      *
2219      * @return The updated ClientConfiguration object.
2220      */

2221     public ClientConfiguration withDnsResolver(final DnsResolver resolver) {
2222         setDnsResolver(resolver);
2223         return this;
2224     }
2225
2226     /**
2227      * Returns whether or not to cache response metadata.
2228      * <p>
2229      * Response metadata is typically used for troubleshooting issues with AWS support staff when
2230      * services aren't acting as expected.
2231      * </p>
2232      * <p>
2233      * While this feature is useful for debugging it adds overhead and disabling it may
2234      * be desired in high throughput applications.
2235      * </p>
2236      *
2237      * @return true if response metadata will be cached
2238      */

2239     public boolean getCacheResponseMetadata() { return cacheResponseMetadata; }
2240
2241     /**
2242      * Sets whether or not to cache response metadata.
2243      * <p>
2244      * Response metadata is typically used for troubleshooting issues with AWS support staff when
2245      * services aren't acting as expected.
2246      * </p>
2247      * <p>
2248      * While this feature is useful for debugging it adds overhead and disabling it may
2249      * be desired in high throughput applications.
2250      * </p>
2251      *
2252      * @param shouldCache true if response metadata should be cached
2253      */

2254     public void setCacheResponseMetadata(boolean shouldCache) {
2255         this.cacheResponseMetadata = shouldCache;
2256     }
2257
2258     /**
2259      * Sets whether or not to cache response metadata.
2260      * <p>
2261      * Response metadata is typically used for troubleshooting issues with AWS support staff when
2262      * services aren't acting as expected.
2263      * </p>
2264      * <p>
2265      * While this feature is useful for debugging it adds overhead and disabling it may
2266      * be desired in high throughput applications.
2267      * </p>
2268      *
2269      * @param shouldCache true if response metadata should be cached
2270      * @return The updated ClientConfiguration object.
2271      */

2272     public ClientConfiguration withCacheResponseMetadata(final boolean shouldCache) {
2273         setCacheResponseMetadata(shouldCache);
2274         return this;
2275     }
2276
2277     /**
2278      * Returns the response metadata cache size.
2279      */

2280     public int getResponseMetadataCacheSize() {
2281         return responseMetadataCacheSize;
2282     }
2283
2284     /**
2285      * Sets the response metadata cache size. By default, it is set to
2286      * {@value #DEFAULT_RESPONSE_METADATA_CACHE_SIZE}.
2287      *
2288      * @param responseMetadataCacheSize
2289      *            maximum cache size.
2290      */

2291     public void setResponseMetadataCacheSize(int responseMetadataCacheSize) {
2292         this.responseMetadataCacheSize = responseMetadataCacheSize;
2293     }
2294
2295     /**
2296      * Sets the response metadata cache size. By default, it is set to
2297      * {@value #DEFAULT_RESPONSE_METADATA_CACHE_SIZE}.
2298      *
2299      * @param responseMetadataCacheSize
2300      *            maximum cache size.
2301      * @return The updated ClientConfiguration object.
2302      */

2303     public ClientConfiguration withResponseMetadataCacheSize(int responseMetadataCacheSize) {
2304         setResponseMetadataCacheSize(responseMetadataCacheSize);
2305         return this;
2306     }
2307
2308     /**
2309      * Returns a non-null object that can be used to specify Apache HTTP client specific custom
2310      * configurations.
2311      */

2312     public ApacheHttpClientConfig getApacheHttpClientConfig() {
2313         return apacheHttpClientConfig;
2314     }
2315
2316     /**
2317      * Returns the instance of {@link SecureRandom} configured by the user; or the JDK default if it
2318      * is null.
2319      *
2320      * @return a non-null instance of SecureRandom.
2321      */

2322     public SecureRandom getSecureRandom() {
2323         if (secureRandom == null)
2324             secureRandom = new SecureRandom();
2325         return secureRandom;
2326     }
2327
2328     /**
2329      * Sets an instance of {@link SecureRandom} to be used by the SDK.
2330      */

2331     public void setSecureRandom(SecureRandom secureRandom) {
2332         this.secureRandom = secureRandom;
2333     }
2334
2335     /**
2336      * Fluent API for {@link #setSecureRandom(SecureRandom)}.
2337      */

2338     public ClientConfiguration withSecureRandom(SecureRandom secureRandom) {
2339         setSecureRandom(secureRandom);
2340         return this;
2341     }
2342
2343     /**
2344      * Returns the use expect continue flag
2345      */

2346     public boolean isUseExpectContinue() {
2347         return useExpectContinue;
2348     }
2349
2350     /**
2351      * Sets if use expect continue should be enabled. By default, it is set to
2352      * {@value #DEFAULT_USE_EXPECT_CONTINUE}.
2353      *
2354      * @param useExpectContinue
2355      *            use expect continue HTTP/1.1 header.
2356      */

2357     public void setUseExpectContinue(boolean useExpectContinue) {
2358         this.useExpectContinue = useExpectContinue;
2359     }
2360
2361     /**
2362      * Sets if use expect continue should be enabled. By default, it is set to
2363      * {@value #DEFAULT_USE_EXPECT_CONTINUE}.
2364      *
2365      * @param useExpectContinue
2366      *            use expect continue HTTP/1.1 header.
2367      * @return The updated ClientConfiguration object.
2368      */

2369     public ClientConfiguration withUseExpectContinue(boolean useExpectContinue) {
2370         setUseExpectContinue(useExpectContinue);
2371
2372         return this;
2373     }
2374
2375     /**
2376      * Adds a header to be added on all requests and returns the {@link ClientConfiguration} object
2377      *
2378      * @param name
2379      *            the name of the header
2380      * @param value
2381      *            the value of the header
2382      *
2383      * @return The updated ClientConfiguration object.
2384      */

2385     public ClientConfiguration withHeader(String name, String value) {
2386         addHeader(name, value);
2387         return this;
2388     }
2389
2390     /**
2391      * Adds a header to be added on all requests
2392      *
2393      * @param name
2394      *            the name of the header
2395      * @param value
2396      *            the value of the header
2397      */

2398     public void addHeader(String name, String value) {
2399         headers.put(name, value);
2400     }
2401
2402     /**
2403      * Returns headers to be added to all requests
2404      *
2405      * @return headers to be added to all requests
2406      */

2407     public Map<String, String> getHeaders() {
2408         return Collections.unmodifiableMap(headers);
2409     }
2410
2411     /**
2412      * Returns the boolean value to indicate if the host prefix injection is disabled or not.
2413      *
2414      * The hostPrefix template is specified in the service model and is used by the SDK to modify the endpoint
2415      * the request is sent to. Host prefix injection is enabled by default. This option can be set to disable the behavior.
2416      */

2417     public boolean isDisableHostPrefixInjection() {
2418         return disableHostPrefixInjection;
2419     }
2420
2421     /**
2422      * Sets the configuration option to disable the host prefix injection.
2423      *
2424      * The hostPrefix template is specified in the service model and is used by the SDK to modify the endpoint
2425      * the request is sent to. Host prefix injection is enabled by default. This option can be set to disable the behavior.
2426      */

2427     public void setDisableHostPrefixInjection(boolean disableHostPrefixInjection) {
2428         this.disableHostPrefixInjection = disableHostPrefixInjection;
2429     }
2430
2431     /**
2432      * Sets the configuration option to disable the host prefix injection.
2433      *
2434      * The hostPrefix template is specified in the service model and is used by the SDK to modify the endpoint
2435      * the request is sent to. Host prefix injection is enabled by default. This option can be set to disable the behavior.
2436      */

2437     public ClientConfiguration withDisableHostPrefixInjection(boolean disableHostPrefixInjection) {
2438         setDisableHostPrefixInjection(disableHostPrefixInjection);
2439         return this;
2440     }
2441
2442     /**
2443      * @return {@link TlsKeyManagersProvider} that will provide the {@link javax.net.ssl.KeyManager}s to use when
2444      * constructing the client's SSL context.
2445      * <p>
2446      * The default is {@link SystemPropertyTlsKeyManagersProvider}.
2447      */

2448     public TlsKeyManagersProvider getTlsKeyManagersProvider() {
2449         return tlsKeyManagersProvider;
2450     }
2451
2452     /**
2453      * Sets {@link TlsKeyManagersProvider} that will provide the {@link javax.net.ssl.KeyManager}s to use when
2454      * constructing the client's SSL context.
2455      * <p>
2456      * The default is {@link SystemPropertyTlsKeyManagersProvider}.
2457      */

2458     public ClientConfiguration withTlsKeyManagersProvider(TlsKeyManagersProvider tlsKeyManagersProvider) {
2459         this.tlsKeyManagersProvider = tlsKeyManagersProvider;
2460         return this;
2461     }
2462
2463     /**
2464      * Sets {@link TlsKeyManagersProvider} that will provide the {@link javax.net.ssl.KeyManager}s to use when
2465      * constructing the client's SSL context.
2466      * <p>
2467      * The default used by the client will be {@link SystemPropertyTlsKeyManagersProvider}. Set an instance {@link
2468      * com.amazonaws.http.NoneTlsKeyManagersProvider} or another instance of {@link TlsKeyManagersProvider} to override
2469      * it.
2470      */

2471     public void setTlsKeyManagersProvider(TlsKeyManagersProvider tlsKeyManagersProvider) {
2472         withTlsKeyManagersProvider(tlsKeyManagersProvider);
2473     }
2474
2475     private URL getHttpProxyEnvironmentVariable() {
2476         if (getProtocol() == Protocol.HTTP) {
2477             return getUrlEnvVar(httpProxyHolder, "HTTP_PROXY");
2478         }
2479         return getUrlEnvVar(httpsProxyHolder, "HTTPS_PROXY");
2480     }
2481
2482     private URL getUrlEnvVar(AtomicReference<URLHolder> cache, String name) {
2483         if (cache.get() == null) {
2484             URLHolder holder = new URLHolder();
2485             String value = getEnvironmentVariableCaseInsensitive(name);
2486             if (value != null) {
2487                 try {
2488                     holder.url = new URL(value);
2489                 } catch (MalformedURLException e) {
2490                     if (log.isWarnEnabled()) {
2491                         log.warn(String.format("Unable to parse %s environment variable value '%s' as URL. It is " +
2492                                 "malformed.", name, value), e);
2493                     }
2494                 }
2495             }
2496             cache.compareAndSet(null, holder);
2497         }
2498         return cache.get().url;
2499     }
2500
2501     static class URLHolder {
2502         private URL url;
2503     }
2504 }
2505