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 static com.amazonaws.SDKGlobalConfiguration.PROFILING_SYSTEM_PROPERTY;
18
19 import com.amazonaws.annotation.SdkInternalApi;
20 import com.amazonaws.annotation.SdkProtectedApi;
21 import com.amazonaws.auth.AWSCredentialsProvider;
22 import com.amazonaws.auth.EndpointPrefixAwareSigner;
23 import com.amazonaws.auth.RegionAwareSigner;
24 import com.amazonaws.auth.RegionFromEndpointResolverAwareSigner;
25 import com.amazonaws.auth.Signer;
26 import com.amazonaws.auth.SignerFactory;
27 import com.amazonaws.client.AwsSyncClientParams;
28 import com.amazonaws.client.builder.AwsClientBuilder;
29 import com.amazonaws.handlers.RequestHandler;
30 import com.amazonaws.handlers.RequestHandler2;
31 import com.amazonaws.http.AmazonHttpClient;
32 import com.amazonaws.http.ExecutionContext;
33 import com.amazonaws.internal.DefaultServiceEndpointBuilder;
34 import com.amazonaws.internal.auth.DefaultSignerProvider;
35 import com.amazonaws.internal.auth.SignerProvider;
36 import com.amazonaws.internal.auth.SignerProviderContext;
37 import com.amazonaws.log.CommonsLogFactory;
38 import com.amazonaws.metrics.AwsSdkMetrics;
39 import com.amazonaws.metrics.RequestMetricCollector;
40 import com.amazonaws.monitoring.CsmConfiguration;
41 import com.amazonaws.monitoring.CsmConfigurationProvider;
42 import com.amazonaws.monitoring.DefaultCsmConfigurationProviderChain;
43 import com.amazonaws.monitoring.MonitoringListener;
44 import com.amazonaws.monitoring.internal.AgentMonitoringListener;
45 import com.amazonaws.monitoring.internal.ClientSideMonitoringRequestHandler;
46 import com.amazonaws.regions.EndpointToRegion;
47 import com.amazonaws.regions.MetadataSupportedRegionFromEndpointProvider;
48 import com.amazonaws.regions.Region;
49 import com.amazonaws.regions.Regions;
50 import com.amazonaws.util.AWSRequestMetrics;
51 import com.amazonaws.util.AWSRequestMetrics.Field;
52 import com.amazonaws.util.Classes;
53 import com.amazonaws.util.RuntimeHttpUtils;
54 import com.amazonaws.util.StringUtils;
55 import java.net.URI;
56 import java.util.Collection;
57 import java.util.Collections;
58 import java.util.List;
59 import java.util.concurrent.CopyOnWriteArrayList;
60 import org.apache.commons.logging.Log;
61 import org.apache.commons.logging.LogFactory;
62
63 /**
64  * Abstract base class for Amazon Web Service Java clients.
65  * <p>
66  * Responsible for basic client capabilities that are the same across all AWS
67  * SDK Java clients (ex: setting the client endpoint).
68  */

69 public abstract class AmazonWebServiceClient {
70
71     /**
72      * @deprecated No longer used.
73      */

74     @Deprecated
75     public static final boolean LOGGING_AWS_REQUEST_METRIC = true;
76
77     private static final String AMAZON = "Amazon";
78     private static final String AWS = "AWS";
79     private static final String DEFAULT_CLIENT_ID = "";
80
81     private static final Log log =
82         LogFactory.getLog(AmazonWebServiceClient.class);
83
84     static {
85         // Configures the internal logging of the signers and core
86         // classes to use Jakarta Commons Logging to stay consistent with the
87         // rest of the library.
88         boolean success = com.amazonaws.log.InternalLogFactory.configureFactory(
89                             new CommonsLogFactory());
90         if (log.isDebugEnabled())
91             log.debug("Internal logging successfully configured to commons logger: "
92                     + success);
93     }
94
95     /**
96      * Flag indicating whether a client is mutable or not. Legacy clients built via the constructors
97      * are mutable. Clients built with the fluent builders are immutable.
98      */

99     private volatile boolean isImmutable = false;
100
101     /**
102      * The service endpoint to which this client will send requests.
103      * <p>
104      * Subclass should only read but not assign to this field, at least not
105      * without synchronization on the enclosing object for thread-safety
106      * reason. If this value is changed to effectively override the endpoint, then the 'isEndpointOverridden' property
107      * should also be set to 'true' within the same synchronized block of code.
108      */

109     protected volatile URI endpoint;
110
111     /**
112      * A boolean flag that indicates whether the endpoint has been overridden either on construction or later mutated
113      * due to a call to setEndpoint(). If the endpoint property is updated directly then the method doing that update
114      * also has the responsibility to update this flag as part of an atomic threadsafe operation.
115      */

116     protected volatile boolean isEndpointOverridden = false;
117
118     /**
119      * Used to explicitly override the internal signer region computed by the
120      * default implementation. This field is typically null.
121      */

122     private volatile String signerRegionOverride;
123
124     /** The client configuration */
125     protected ClientConfiguration clientConfiguration;
126
127     /** Low level client for sending requests to AWS services. */
128     protected AmazonHttpClient client;
129
130     /** Optional request handlers for additional request processing. */
131     protected final List<RequestHandler2> requestHandler2s;
132
133     /** Optional offset (in seconds) to use when signing requests */
134     protected int timeOffset;
135
136     private volatile SignerProvider signerProvider;
137
138     private final CsmConfiguration csmConfiguration;
139
140     /**
141      * The cached service abbreviation for this service, used for identifying
142      * service endpoints by region, identifying the necessary signer, etc.
143      * Thread safe so it's backward compatible.
144      */

145     private volatile String serviceName;
146
147     /**
148      * The service name in region metadata, i.e. the prefix of endpoint.
149      */

150     private volatile String endpointPrefix;
151
152     /**
153      * Region used to sign requests.
154      */

155     private volatile String signingRegion;
156
157     private Collection<MonitoringListener> monitoringListeners;
158
159     private AgentMonitoringListener agentMonitoringListener;
160
161     /**
162      * Constructs a new AmazonWebServiceClient object using the specified
163      * configuration.
164      *
165      * @param clientConfiguration
166      *            The client configuration for this client.
167      */

168     public AmazonWebServiceClient(ClientConfiguration clientConfiguration) {
169         this(clientConfiguration, null);
170     }
171
172     /**
173      * Constructs a new AmazonWebServiceClient object using the specified
174      * configuration and request metric collector.
175      *
176      * @param clientConfiguration
177      *            The client configuration for this client.
178      * @param requestMetricCollector
179      *            optional request metric collector to be used at the http
180      *            client level; can be null.
181      */

182     public AmazonWebServiceClient(ClientConfiguration clientConfiguration,
183             RequestMetricCollector requestMetricCollector) {
184         this(clientConfiguration, requestMetricCollector, false);
185     }
186
187     @SdkProtectedApi
188     protected AmazonWebServiceClient(final ClientConfiguration clientConfiguration,
189                                      final RequestMetricCollector requestMetricCollector,
190                                      boolean disableStrictHostNameVerification) {
191         this(new AwsSyncClientParams() {
192             @Override
193             public AWSCredentialsProvider getCredentialsProvider() {
194                 return null;
195             }
196
197             @Override
198             public ClientConfiguration getClientConfiguration() {
199                 return clientConfiguration;
200             }
201
202             @Override
203             public RequestMetricCollector getRequestMetricCollector() {
204                 return requestMetricCollector;
205             }
206
207             @Override
208             public List<RequestHandler2> getRequestHandlers() {
209                 return new CopyOnWriteArrayList<RequestHandler2>();
210             }
211
212             @Override
213             public CsmConfigurationProvider getClientSideMonitoringConfigurationProvider() {
214                 return DefaultCsmConfigurationProviderChain.getInstance();
215             }
216
217             @Override
218             public MonitoringListener getMonitoringListener() {
219                 return null;
220             }
221         }, !disableStrictHostNameVerification);
222     }
223
224     protected AmazonWebServiceClient(AwsSyncClientParams clientParams) {
225         this(clientParams, null);
226     }
227
228     private AmazonWebServiceClient(AwsSyncClientParams clientParams, Boolean useStrictHostNameVerification) {
229         this.clientConfiguration = clientParams.getClientConfiguration();
230         this.requestHandler2s = clientParams.getRequestHandlers();
231         this.monitoringListeners = new CopyOnWriteArrayList<MonitoringListener>();
232
233         useStrictHostNameVerification = useStrictHostNameVerification != null ? useStrictHostNameVerification
234                                                                               : useStrictHostNameVerification();
235
236         this.client = new AmazonHttpClient(clientConfiguration,
237                                            clientParams.getRequestMetricCollector(),
238                                            !useStrictHostNameVerification,
239                                            calculateCRC32FromCompressedData());
240         this.csmConfiguration = getCsmConfiguration(clientParams.getClientSideMonitoringConfigurationProvider());
241
242         if (isCsmEnabled()) {
243             agentMonitoringListener = new AgentMonitoringListener(csmConfiguration.getHost(), csmConfiguration.getPort());
244             monitoringListeners.add(agentMonitoringListener);
245         }
246
247         if (clientParams.getMonitoringListener() != null) {
248             monitoringListeners.add(clientParams.getMonitoringListener());
249         }
250
251         if (shouldGenerateClientSideMonitoringEvents()) {
252             requestHandler2s.add(new ClientSideMonitoringRequestHandler(getClientId(), monitoringListeners));
253         }
254     }
255
256     /**
257      * Returns the signer.
258      * <p>
259      * Note, however, the signer configured for S3 is incomplete at this stage
260      * as the information on the S3 bucket and key is not yet known.
261      */

262     @Deprecated
263     protected Signer getSigner() {
264         return signerProvider.getSigner(SignerProviderContext.builder().build());
265     }
266
267     /**
268      * Returns a flag that indicates whether the endpoint for this client has been overridden or not.
269      * @return true if the configured endpoint is an override; false if not.
270      */

271     @SdkProtectedApi
272     protected boolean isEndpointOverridden() {
273         return this.isEndpointOverridden;
274     }
275
276     /**
277      * @return Current SignerProvider instance.
278      */

279     @SdkProtectedApi
280     protected SignerProvider getSignerProvider() {
281         return signerProvider;
282     }
283
284     /**
285      * Overrides the default endpoint for this client. Callers can use this
286      * method to control which AWS region they want to work with.
287      * <p>
288      * <b>This method is not threadsafe. Endpoints should be configured when the
289      * client is created and before any service requests are made. Changing it
290      * afterwards creates inevitable race conditions for any service requests in
291      * transit.</b>
292      * <p>
293      * Callers can pass in just the endpoint (ex: "ec2.amazonaws.com") or a full
294      * URL, including the protocol (ex: "https://ec2.amazonaws.com"). If the
295      * protocol is not specified here, the default protocol from this client's
296      * {@link ClientConfiguration} will be used, which by default is HTTPS.
297      * <p>
298      * For more information on using AWS regions with the AWS SDK for Java, and
299      * a complete list of all available endpoints for all AWS services, see:
300      * <a href="https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-region-selection.html#region-selection-choose-endpoint">
301      * https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-region-selection.html#region-selection-choose-endpoint</a>
302      *
303      * @param endpoint
304      *            The endpoint (ex: "ec2.amazonaws.com") or a full URL,
305      *            including the protocol (ex: "https://ec2.amazonaws.com") of
306      *            the region specific AWS endpoint this client will communicate
307      *            with.
308      * @throws IllegalArgumentException
309      *             If any problems are detected with the specified endpoint.
310      *
311      * @deprecated use {@link AwsClientBuilder#setEndpointConfiguration(AwsClientBuilder.EndpointConfiguration)} for example:
312      * {@code builder.setEndpointConfiguration(new EndpointConfiguration(endpoint, signingRegion));}
313      */

314     @Deprecated
315     public void setEndpoint(String endpoint) throws IllegalArgumentException {
316         checkMutability();
317         URI uri = toURI(endpoint);
318         Signer signer = computeSignerByURI(uri, signerRegionOverride, false);
319         synchronized (this) {
320             this.isEndpointOverridden = true;
321             this.endpoint = uri;
322             this.signerProvider = createSignerProvider(signer);
323             this.signingRegion = EndpointToRegion.guessRegionNameForEndpoint(endpoint, getEndpointPrefix());
324         }
325     }
326
327     /** Returns the endpoint as a URI. */
328     private URI toURI(String endpoint) throws IllegalArgumentException {
329         return RuntimeHttpUtils.toUri(endpoint, clientConfiguration);
330     }
331
332     /**
333      * Allows specifying the endpoint along with signing information (service name and signing region). This method will
334      * overwrite any information set previously by any set/with/configure Region/Endpoint methods.
335      * <p>
336      * Overrides the default endpoint for this client
337      * ("http://dynamodb.us-east-1.amazonaws.com/") and explicitly provides an
338      * AWS region ID and AWS service name to use when the client calculates a
339      * signature for requests. In almost all cases, this region ID and service
340      * name are automatically determined from the endpoint, and callers should
341      * use the simpler one-argument form of setEndpoint instead of this method.
342      * <p>
343      * Callers can pass in just the endpoint (ex:
344      * "dynamodb.us-east-1.amazonaws.com/") or a full URL, including the
345      * protocol (ex: "http://dynamodb.us-east-1.amazonaws.com/"). If the
346      * protocol is not specified here, the default protocol from this client's
347      * {@link ClientConfiguration} will be used, which by default is HTTPS.
348      * <p>
349      * For more information on using AWS regions with the AWS SDK for Java, and
350      * a complete list of all available endpoints for all AWS services, see: <a
351      * href=
352      * "http://developer.amazonwebservices.com/connect/entry.jspa?externalID=3912"
353      * > http://developer.amazonwebservices.com/connect/entry.jspa?externalID=
354      * 3912</a>
355      *
356      * @param endpoint
357      *            The endpoint (ex: "dynamodb.us-east-1.amazonaws.com/") or a
358      *            full URL, including the protocol (ex:
359      *            "http://dynamodb.us-east-1.amazonaws.com/") of the region
360      *            specific AWS endpoint this client will communicate with.
361      * @param serviceName
362      *            This parameter is ignored.
363      * @param regionId
364      *            The ID of the region in which this service resides AND the
365      *            overriding region for signing purposes.
366      *
367      * @throws IllegalArgumentException
368      *             If any problems are detected with the specified endpoint.
369      * @deprecated Please use the client builders instead. The
370      * {@link AwsClientBuilder#withEndpointConfiguration(AwsClientBuilder.EndpointConfiguration)} method on the builder allows
371      * setting both endpoint and signing region. See
372      * <a href="http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/creating-clients.html">Creating Service Clients</a>
373      * for more information.
374      */

375     @Deprecated
376     public void setEndpoint(String endpoint, String serviceName, String regionId) {
377         URI uri = toURI(endpoint);
378         Signer signer = computeSignerByServiceRegion(serviceName, regionId,
379                                                      regionId, true);
380         synchronized (this) {
381             setServiceNameIntern(serviceName);
382             this.signerProvider = createSignerProvider(signer);
383             this.isEndpointOverridden = true;
384             this.endpoint = uri;
385             this.signerRegionOverride = regionId;
386             this.signingRegion = regionId;
387         }
388     }
389
390     /**
391      * Returns the signer based on the given URI and the current AWS client
392      * configuration. Currently only the SQS client can have different region on
393      * a per request basis. For other AWS clients, the region remains the same
394      * on a per AWS client level.
395      * <p>
396      * Note, however, the signer returned for S3 is incomplete at this stage as
397      * the information on the S3 bucket and key is not yet known.
398      */

399     public Signer getSignerByURI(URI uri) {
400         return computeSignerByURI(uri, signerRegionOverride, true);
401     }
402
403     /**
404      * Returns the signer for the given uri and the current client
405      * configuration.
406      * <p>
407      * Note, however, the signer returned for S3 is incomplete at this stage as
408      * the information on the S3 bucket and key is not yet known.
409      *
410      * @param signerRegionOverride
411      *            the overriding signer region; or null if there is none.
412      * @param isRegionIdAsSignerParam
413      *            true if the "regionId" is used to configure the signer if
414      *            applicable; false if this method is called for the purpose of
415      *            purely setting the communication end point of this AWS client,
416      *            and therefore the "regionId" parameter will not be used
417      *            directly for configuring the signer.
418      */

419     private Signer computeSignerByURI(URI uri, String signerRegionOverride,
420             boolean isRegionIdAsSignerParam) {
421         if (uri == null) {
422             throw new IllegalArgumentException(
423                     "Endpoint is not set. Use setEndpoint to set an endpoint before performing any request.");
424         }
425         if (uri.getHost() == null) {
426             throw new IllegalArgumentException("Endpoint does not contain a valid host name: " + uri);
427         }
428         String service = getServiceNameIntern();
429         String region = EndpointToRegion.guessRegionNameForEndpointWithDefault(uri.getHost(), getEndpointPrefix(), "us-east-1");
430         return computeSignerByServiceRegion(
431                 service, region, signerRegionOverride, isRegionIdAsSignerParam);
432     }
433
434     /**
435      * Returns the signer for the given service name, region id, and the current
436      * client configuration.
437      * <p>
438      * Note, however, the signer returned for S3 is incomplete at this stage as
439      * the information on the S3 bucket and key is not yet known.
440      *
441      * @param regionId
442      *            the region for sending AWS requests
443      * @param signerRegionOverride
444      *            the overriding signer region; or null if there is none.
445      * @param isRegionIdAsSignerParam
446      *            true if the "regionId" is used to configure the signer if
447      *            applicable; false if this method is called for the purpose of
448      *            purely setting the communication end point of this AWS client,
449      *            and therefore the "regionId" parameter will not be used
450      *            directly for configuring the signer.
451      */

452     private Signer computeSignerByServiceRegion(
453             String serviceName, String regionId,
454             String signerRegionOverride,
455             boolean isRegionIdAsSignerParam) {
456         String signerType = clientConfiguration.getSignerOverride();
457         Signer signer = signerType == null
458              ? SignerFactory.getSigner(serviceName, regionId)
459              : SignerFactory.getSignerByTypeAndService(signerType, serviceName)
460              ;
461
462         if (signer instanceof RegionAwareSigner) {
463              // Overrides the default region computed
464              RegionAwareSigner regionAwareSigner = (RegionAwareSigner)signer;
465             // (signerRegionOverride != null) means that it is likely to be AWS
466             // internal dev work, as "signerRegionOverride" is typically null
467              // when used in the external release
468              if (signerRegionOverride != null)
469                  regionAwareSigner.setRegionName(signerRegionOverride);
470              else if (regionId != null && isRegionIdAsSignerParam)
471                  regionAwareSigner.setRegionName(regionId);
472          }
473
474          if (signer instanceof EndpointPrefixAwareSigner) {
475              EndpointPrefixAwareSigner endpointPrefixAwareSigner = (EndpointPrefixAwareSigner) signer;
476              /*
477               * This will be used to compute the region name required for signing
478               * if signerRegionOverride is not provided
479               */

480              endpointPrefixAwareSigner.setEndpointPrefix(endpointPrefix);
481          }
482
483          if (signer instanceof RegionFromEndpointResolverAwareSigner) {
484              // Allow the signer to assess the endpoints.json file for regions
485              RegionFromEndpointResolverAwareSigner awareSigner = (RegionFromEndpointResolverAwareSigner) signer;
486              awareSigner.setRegionFromEndpointResolver(new MetadataSupportedRegionFromEndpointProvider());
487          }
488
489          return signer;
490     }
491
492     /**
493      * An alternative to {@link AmazonWebServiceClient#setEndpoint(String)}, sets the regional
494      * endpoint for this client's service calls. Callers can use this method to control which AWS
495      * region they want to work with.
496      * <p>
497      * <b>This method is not threadsafe. A region should be configured when the client is created
498      * and before any service requests are made. Changing it afterwards creates inevitable race
499      * conditions for any service requests in transit or retrying.</b>
500      * <p>
501      * By default, all service endpoints in all regions use the https protocol. To use http instead,
502      * specify it in the {@link ClientConfiguration} supplied at construction.
503      *
504      * @param region
505      *            The region this client will communicate with. See
506      *            {@link Region#getRegion(com.amazonaws.regions.Regions)} for accessing a given
507      *            region.
508      * @throws java.lang.IllegalArgumentException
509      *             If the given region is null, or if this service isn't available in the given
510      *             region. See {@link Region#isServiceSupported(String)}
511      * @see Region#getRegion(com.amazonaws.regions.Regions)
512      * @see Region#createClient(Class, com.amazonaws.auth.AWSCredentialsProvider,
513      *      ClientConfiguration)
514      * @deprecated use {@link AwsClientBuilder#setRegion(String)}
515      */

516     @Deprecated
517     public void setRegion(Region region) throws IllegalArgumentException {
518         checkMutability();
519         if (region == null) {
520             throw new IllegalArgumentException("No region provided");
521         }
522         final String serviceNameForEndpoint = getEndpointPrefix();
523         final String serviceNameForSigner = getServiceNameIntern();
524         URI uri = new DefaultServiceEndpointBuilder(serviceNameForEndpoint, clientConfiguration.getProtocol()
525                 .toString()).withRegion(region).getServiceEndpoint();
526         Signer signer = computeSignerByServiceRegion(serviceNameForSigner, region.getName(), signerRegionOverride, false);
527         synchronized (this) {
528             this.isEndpointOverridden = false;
529             this.endpoint = uri;
530             this.signerProvider = createSignerProvider(signer);
531             this.signingRegion = EndpointToRegion.guessRegionNameForEndpoint(endpoint.toString(), getEndpointPrefix());
532         }
533     }
534
535     /**
536      * Convenient method for setting region.
537      *
538      * @param region region to set to; must not be null.
539      *
540      * @see #setRegion(Region)
541      * @deprecated use {@link AwsClientBuilder#setRegion(String)}
542      */

543     @Deprecated
544     public final void configureRegion(Regions region) {
545         checkMutability();
546         if (region == null)
547             throw new IllegalArgumentException("No region provided");
548         this.setRegion(Region.getRegion(region));
549     }
550
551     /**
552      * Shuts down this client object, releasing any resources that might be held
553      * open. If this method is not invoked, resources may be leaked. Once a client
554      * has been shutdown, it should not be used to make any more requests.
555      */

556     public void shutdown() {
557         if (agentMonitoringListener != null) {
558             agentMonitoringListener.shutdown();
559         }
560         client.shutdown();
561     }
562
563     /**
564      * @deprecated by {@link #addRequestHandler(RequestHandler2)}.
565      *
566      * Appends a request handler to the list of registered handlers that are run
567      * as part of a request's lifecycle.
568      *
569      * @param requestHandler
570      *            The new handler to add to the current list of request
571      *            handlers.
572      */

573     @Deprecated
574     public void addRequestHandler(RequestHandler requestHandler) {
575         checkMutability();
576         requestHandler2s.add(RequestHandler2.adapt(requestHandler));
577     }
578
579     /**
580      * Appends a request handler to the list of registered handlers that are run
581      * as part of a request's lifecycle.
582      *
583      * @param requestHandler2
584      *            The new handler to add to the current list of request
585      *            handlers.
586      * @deprecated use {@link AwsClientBuilder#withRequestHandlers(RequestHandler2...)}
587      */

588     @Deprecated
589     public void addRequestHandler(RequestHandler2 requestHandler2) {
590         checkMutability();
591         requestHandler2s.add(requestHandler2);
592     }
593
594     /**
595      * Removes a request handler from the list of registered handlers that are run
596      * as part of a request's lifecycle.
597      *
598      * @param requestHandler
599      *            The handler to remove from the current list of request
600      *            handlers.
601      * @deprecated use {@link AwsClientBuilder#withRequestHandlers(RequestHandler2...)}
602      */

603     @Deprecated
604     public void removeRequestHandler(RequestHandler requestHandler) {
605         checkMutability();
606         requestHandler2s.remove(RequestHandler2.adapt(requestHandler));
607     }
608
609     /**
610      * @deprecated use {@link AwsClientBuilder#withRequestHandlers(RequestHandler2...)}
611      */

612     @Deprecated
613     public void removeRequestHandler(RequestHandler2 requestHandler2) {
614         checkMutability();
615         requestHandler2s.remove(requestHandler2);
616     }
617
618     /**
619      * Runs the {@code beforeMarshalling} method of any
620      * {@code RequestHandler2}s associated with this client.
621      *
622      * @param request the request passed in from the user
623      * @return the (possibly different) request to marshal
624      */

625     @SuppressWarnings("unchecked")
626     protected final <T extends AmazonWebServiceRequest> T beforeMarshalling(
627             T request) {
628
629         T local = request;
630         for (RequestHandler2 handler : requestHandler2s) {
631             local = (T) handler.beforeMarshalling(local);
632         }
633         return local;
634     }
635
636     protected ExecutionContext createExecutionContext(AmazonWebServiceRequest req) {
637         return createExecutionContext(req, signerProvider);
638     }
639
640     protected ExecutionContext createExecutionContext(AmazonWebServiceRequest req,
641                                                       SignerProvider signerProvider) {
642         boolean isMetricsEnabled = isRequestMetricsEnabled(req) || isProfilingEnabled() ||
643                                    shouldGenerateClientSideMonitoringEvents();
644         return ExecutionContext.builder()
645                                .withRequestHandler2s(requestHandler2s)
646                                .withUseRequestMetrics(isMetricsEnabled)
647                                .withAwsClient(this)
648                                .withSignerProvider(signerProvider).build();
649     }
650
651     protected final ExecutionContext createExecutionContext(Request<?> req) {
652         return createExecutionContext(req.getOriginalRequest());
653     }
654
655     protected SignerProvider createSignerProvider(Signer signer) {
656         return new DefaultSignerProvider(this, signer);
657     }
658
659     /* Check the profiling system property and return true if set */
660     protected static boolean isProfilingEnabled() {
661         return System.getProperty(PROFILING_SYSTEM_PROPERTY) != null;
662     }
663
664     /*
665      * Whether to generate client side monitoring events. Only generating
666      * client side monitoring events when there are monitoring listeners attached.
667      *
668      * @see ClientSideMonitoringRequestMetricCollector
669      */

670     protected boolean shouldGenerateClientSideMonitoringEvents() {
671         return !monitoringListeners.isEmpty();
672     }
673
674     /**
675      * Returns true if request metric collection is applicable to the given
676      * request; false otherwise.
677      */

678     protected final boolean isRequestMetricsEnabled(AmazonWebServiceRequest req) {
679         RequestMetricCollector c = req.getRequestMetricCollector(); // request level collector
680         if (c != null && c.isEnabled()) {
681             return true;
682         }
683         return isRMCEnabledAtClientOrSdkLevel();
684     }
685
686     /**
687      * Returns true if request metric collection is enabled at the service
688      * client or AWS SDK level request; false otherwise.
689      */

690     private boolean isRMCEnabledAtClientOrSdkLevel() {
691         RequestMetricCollector c = requestMetricCollector();
692         return c != null && c.isEnabled();
693     }
694
695     /**
696      * Sets the optional value for time offset for this client.  This
697      * value will be applied to all requests processed through this client.
698      * Value is in seconds, positive values imply the current clock is "fast",
699      * negative values imply clock is slow.
700      *
701      * @param timeOffset
702      *            The optional value for time offset (in seconds) for this client.
703      */

704     public void setTimeOffset(int timeOffset) {
705         checkMutability();
706         this.timeOffset = timeOffset;
707     }
708
709     /**
710      * Sets the optional value for time offset for this client.  This
711      * value will be applied to all requests processed through this client.
712      * Value is in seconds, positive values imply the current clock is "fast",
713      * negative values imply clock is slow.
714      *
715      * @param timeOffset
716      *            The optional value for time offset (in seconds) for this client.
717      *
718      * @return the updated web service client
719      */

720     public AmazonWebServiceClient withTimeOffset(int timeOffset) {
721         checkMutability();
722         setTimeOffset(timeOffset);
723         return this;
724     }
725
726     /**
727      * Returns the optional value for time offset for this client.  This
728      * value will be applied to all requests processed through this client.
729      * Value is in seconds, positive values imply the current clock is "fast",
730      * negative values imply clock is slow.
731      *
732      * @return The optional value for time offset (in seconds) for this client.
733      */

734     public int getTimeOffset() {
735         return timeOffset;
736     }
737
738     /**
739      * Returns the client specific {@link RequestMetricCollector}; or null if
740      * there is none.
741      */

742     public RequestMetricCollector getRequestMetricsCollector() {
743         return client.getRequestMetricCollector();
744     }
745
746     /**
747      * Returns {@link MonitoringListener}; or null if there is none.
748      */

749     public Collection<MonitoringListener> getMonitoringListeners() {
750         return Collections.unmodifiableCollection(monitoringListeners);
751     }
752
753     /**
754      * Returns the client specific request metric collector if there is one; or
755      * the one at the AWS SDK level otherwise.
756      */

757     protected RequestMetricCollector requestMetricCollector() {
758         RequestMetricCollector mc = client.getRequestMetricCollector();
759         return mc == null ? AwsSdkMetrics.getRequestMetricCollector() : mc;
760     }
761
762     /**
763      * Returns the most specific request metric collector, starting from the request level, then
764      * client level, then finally the AWS SDK level.
765      */

766     private final RequestMetricCollector findRequestMetricCollector(
767             RequestMetricCollector reqLevelMetricsCollector) {
768
769         RequestMetricCollector requestMetricCollector;
770
771         if (reqLevelMetricsCollector != null) {
772             requestMetricCollector = reqLevelMetricsCollector;
773         } else if (getRequestMetricsCollector() != null) {
774             requestMetricCollector =  getRequestMetricsCollector();
775         } else {
776             requestMetricCollector = AwsSdkMetrics.getRequestMetricCollector();
777         }
778         return requestMetricCollector;
779     }
780
781     /**
782      * Notify request handlers that we are about to start execution.
783      */

784     protected final <T extends AmazonWebServiceRequest> T beforeClientExecution(T request) {
785         T local = request;
786         for (RequestHandler2 handler : requestHandler2s) {
787             local = (T) handler.beforeExecution(local);
788         }
789         return local;
790     }
791
792     /**
793      * Convenient method to end the client execution without logging the
794      * awsRequestMetrics.
795      */

796     protected final void endClientExecution(
797             AWSRequestMetrics awsRequestMetrics, Request<?> request,
798             Response<?> response) {
799         this.endClientExecution(awsRequestMetrics, request, response,
800                 !LOGGING_AWS_REQUEST_METRIC);
801     }
802
803     /**
804      * Common routine to end a client AWS request/response execution and collect
805      * the request metrics.  Caller of this routine is responsible for starting
806      * the event for {@link Field#ClientExecuteTime} and call this method
807      * in a try-finally block.
808      *
809      * @param loggingAwsRequestMetrics deprecated and ignored
810      */

811     protected final void endClientExecution(
812             AWSRequestMetrics awsRequestMetrics, Request<?> request,
813             Response<?> response, @Deprecated boolean loggingAwsRequestMetrics) {
814         if (request != null) {
815             awsRequestMetrics.endEvent(Field.ClientExecuteTime);
816             awsRequestMetrics.getTimingInfo().endTiming();
817             RequestMetricCollector c = findRequestMetricCollector(
818                     request.getOriginalRequest().getRequestMetricCollector());
819             c.collectMetrics(request, response);
820             awsRequestMetrics.log();
821         }
822     }
823
824     /**
825      * @deprecated by {@link #getServiceName()}.
826      */

827     @Deprecated
828     protected String getServiceAbbreviation() {
829         return getServiceNameIntern();
830     }
831
832     /**
833      * Returns the service abbreviation for this service, used for identifying
834      * service endpoints by region, identifying the necessary signer, etc.
835      * Used to be call "getServiceAbbreviation".
836      */

837     public String getServiceName() {
838         return getServiceNameIntern();
839     }
840
841     /**
842      * @return the service name that should be used when computing the region
843      *         endpoints. This method returns the value of the
844      *         regionMetadataServiceName configuration in the internal config
845      *         file if such configuration is specified for the current client,
846      *         otherwise it returns the same service name that is used for
847      *         request signing.
848      */

849     public String getEndpointPrefix() {
850         if (endpointPrefix != null) {
851             return endpointPrefix;
852         }
853
854         String httpClientName = getHttpClientName();
855         String serviceNameInRegionMetadata = ServiceNameFactory.
856                 getServiceNameInRegionMetadata(httpClientName);
857
858         synchronized (this) {
859             if (endpointPrefix != null) {
860                 return endpointPrefix;
861             }
862             if (serviceNameInRegionMetadata != null) {
863                 return endpointPrefix = serviceNameInRegionMetadata;
864             } else {
865                 return endpointPrefix = getServiceNameIntern();
866             }
867         }
868     }
869
870     /**
871      * @return The region used to sign requests with AWS SigV4 auth.
872      */

873     @SdkProtectedApi
874     protected String getSigningRegion() {
875         return this.signingRegion;
876     }
877
878     /**
879      * An internal method used to explicitly override the service name for region metadata.
880      * This service name is used to compute the region endpoints.
881      */

882     protected void setEndpointPrefix(String endpointPrefix) {
883         if (endpointPrefix == null) {
884             throw new IllegalArgumentException(
885                     "The parameter endpointPrefix must be specified!");
886         }
887         this.endpointPrefix = endpointPrefix;
888     }
889
890     /**
891      * Internal method for implementing {@link #getServiceName()}. Method is
892      * protected by intent so peculiar subclass that don't follow the class
893      * naming convention can choose to return whatever service name as needed.
894      */

895     protected String getServiceNameIntern() {
896         if (serviceName == null) {
897             synchronized (this) {
898                 if (serviceName == null) {
899                     return serviceName = computeServiceName();
900                 }
901             }
902         }
903         return serviceName;
904     }
905
906     /**
907      * An internal method used to explicitly override the service name
908      * computed by the default implementation. This method is not expected to be
909      * normally called except for AWS internal development purposes.
910      */

911     public final void setServiceNameIntern(String serviceName) {
912         if (serviceName == null)
913             throw new IllegalArgumentException(
914                     "The parameter serviceName must be specified!");
915         this.serviceName = serviceName;
916     }
917
918     /**
919      * Returns the service name of this AWS http client by first looking it up from the SDK internal
920      * configuration, and if not found, derive it from the class name of the immediate subclass of
921      * {@link AmazonWebServiceClient}. No configuration is necessary if the simple class name of the
922      * http client follows the convention of <code>(Amazon|AWS).*(JavaClient|Client)</code>.
923      */

924     private String computeServiceName() {
925         final String httpClientName = getHttpClientName();
926         String service = ServiceNameFactory.getServiceName(httpClientName);
927         if (service != null) {
928             return service; // only if it is so explicitly configured
929         }
930         // Otherwise, make use of convention over configuration
931         int j = httpClientName.indexOf("JavaClient");
932         if (j == -1) {
933             j = httpClientName.indexOf("Client");
934             if (j == -1) {
935                 throw new IllegalStateException(
936                         "Unrecognized suffix for the AWS http client class name " + httpClientName);
937             }
938         }
939         int i = httpClientName.indexOf(AMAZON);
940         int len;
941         if (i == -1) {
942             i = httpClientName.indexOf(AWS);
943             if (i == -1) {
944                 throw new IllegalStateException(
945                         "Unrecognized prefix for the AWS http client class name " + httpClientName);
946             }
947             len = AWS.length();
948         } else {
949             len = AMAZON.length();
950         }
951         if (i >= j) {
952             throw new IllegalStateException(
953                     "Unrecognized AWS http client class name " + httpClientName);
954         }
955         String serviceName = httpClientName.substring(i + len, j);
956         return StringUtils.lowerCase(serviceName);
957     }
958
959     private String getHttpClientName() {
960         Class<?> httpClientClass = Classes.childClassOf(AmazonWebServiceClient.classthis);
961         return httpClientClass.getSimpleName();
962     }
963
964     /**
965      * Returns the signer region override.
966      *
967      * @see #setSignerRegionOverride(String).
968      */

969     public final String getSignerRegionOverride() {
970         return signerRegionOverride;
971     }
972
973     /**
974      * An internal method used to explicitly override the internal signer region
975      * computed by the default implementation. This method is not expected to be
976      * normally called except for AWS internal development purposes.
977      */

978     public final void setSignerRegionOverride(String signerRegionOverride) {
979         checkMutability();
980         Signer signer = computeSignerByURI(endpoint, signerRegionOverride, true);
981         synchronized(this)  {
982             this.signerRegionOverride = signerRegionOverride;
983             this.signerProvider = createSignerProvider(signer);
984             this.signingRegion = signerRegionOverride;
985         }
986     }
987
988     /**
989      * Fluent method for {@link #setRegion(Region)}.
990      *<pre>
991      * Example:
992      *
993      *   AmazonDynamoDBClient client = new AmazonDynamoDBClient(...).<AmazonDynamoDBClient>withRegion(...);
994      *</pre>
995      * @see #setRegion(Region)
996      * @deprecated use {@link AwsClientBuilder#withRegion(Region)} for example:
997      * {@code AmazonSNSClientBuilder.standard().withRegion(region).build();}
998      */

999     @Deprecated
1000     public <T extends AmazonWebServiceClient> T withRegion(Region region) {
1001         setRegion(region);
1002         @SuppressWarnings("unchecked") T t= (T)this;
1003         return t;
1004     }
1005
1006     /**
1007      * Convenient fluent method for setting region.
1008      *
1009      * @param region region to set to; must not be null.
1010      *
1011      * @see #withRegion(Region)
1012      * @deprecated use {@link AwsClientBuilder#withRegion(Regions)} for example:
1013      * {@code AmazonSNSClientBuilder.standard().withRegion(region).build();}
1014      */

1015     @Deprecated
1016     public <T extends AmazonWebServiceClient> T withRegion(Regions region) {
1017         configureRegion(region);
1018         @SuppressWarnings("unchecked") T t= (T)this;
1019         return t;
1020     }
1021     /**
1022      * Fluent method for {@link #setEndpoint(String)}.
1023      *<pre>
1024      * Example:
1025      *
1026      *   AmazonDynamoDBClient client = new AmazonDynamoDBClient(...).<AmazonDynamoDBClient>withEndPoint(...);
1027      *</pre>
1028      * @see #setEndpoint(String)
1029      * @deprecated use {@link AwsClientBuilder#withEndpointConfiguration(AwsClientBuilder.EndpointConfiguration)} for example:
1030      * {@code AmazonSNSClientBuilder.standard().withEndpointConfiguration(new EndpointConfiguration(endpoint, signingRegion)).build();}
1031      */

1032     @Deprecated
1033     public <T extends AmazonWebServiceClient> T withEndpoint(String endpoint) {
1034         setEndpoint(endpoint);
1035         @SuppressWarnings("unchecked") T t= (T)this;
1036         return t;
1037     }
1038
1039     /**
1040      * Internal only API to lock a client's mutable methods. Only intended for use by the fluent
1041      * builders.
1042      */

1043     @Deprecated
1044     @SdkInternalApi
1045     public final void makeImmutable() {
1046         this.isImmutable = true;
1047     }
1048
1049     /**
1050      * If the client has been marked as immutable then throw an {@link
1051      * UnsupportedOperationException}, otherwise do nothing. Should be called by each mutating
1052      * method.
1053      */

1054     @SdkProtectedApi
1055     protected final void checkMutability() {
1056         if (isImmutable) {
1057             throw new UnsupportedOperationException(
1058                     "Client is immutable when created with the builder.");
1059         }
1060     }
1061
1062     /**
1063      * Hook to allow S3 client to disable strict hostname verification since it uses wildcard
1064      * certificates.
1065      *
1066      * @return True if strict hostname verification should be used, false otherwise.
1067      */

1068     protected boolean useStrictHostNameVerification() {
1069         return true;
1070     }
1071
1072     /**
1073      * Hook to allow clients to override CRC32 calculation behavior. Currently, only exercised by DynamoDB.
1074      *
1075      * @return True if the service returns CRC32 checksum from the compressed data, false otherwise.
1076      */

1077     protected boolean calculateCRC32FromCompressedData() {
1078         return false;
1079     }
1080
1081     public String getSignerOverride() {
1082         return clientConfiguration.getSignerOverride();
1083     }
1084
1085     public ClientConfiguration getClientConfiguration() {
1086         return new ClientConfiguration(clientConfiguration);
1087     }
1088
1089     /**
1090      * @return {@code trueif Client Side Monitoring is enabled, {@code false}
1091      * otherwise.
1092      */

1093     protected final boolean isCsmEnabled() {
1094         return csmConfiguration != null && csmConfiguration.isEnabled();
1095     }
1096
1097     protected String getClientId() {
1098         if (csmConfiguration == null) {
1099             return DEFAULT_CLIENT_ID;
1100         }
1101         return csmConfiguration.getClientId();
1102     }
1103
1104
1105     /**
1106      * Convenience method to return {@code nullif the provider throws {@code
1107      * SdkClientException}.
1108      */

1109     private CsmConfiguration getCsmConfiguration(
1110             CsmConfigurationProvider csmConfigurationProvider) {
1111         try {
1112             return csmConfigurationProvider.getConfiguration();
1113         } catch (SdkClientException e) {
1114             return null;
1115         }
1116     }
1117 }
1118