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.annotation.SdkInternalApi;
19 import com.amazonaws.auth.AWSCredentials;
20 import com.amazonaws.auth.AWSCredentialsProvider;
21 import com.amazonaws.event.ProgressListener;
22 import com.amazonaws.handlers.HandlerContextKey;
23 import com.amazonaws.internal.StaticCredentialsProvider;
24 import com.amazonaws.metrics.RequestMetricCollector;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.LinkedList;
28 import java.util.List;
29 import java.util.Map;
30
31 /**
32  * Base class for all user facing web service requests.
33  */

34 @NotThreadSafe
35 public abstract class AmazonWebServiceRequest implements Cloneable, ReadLimitInfo, HandlerContextAware {
36
37     public static final AmazonWebServiceRequest NOOP = new AmazonWebServiceRequest() {
38     };
39
40     /**
41      * The optional progress listener for receiving updates about the progress of the request.
42      */

43     private ProgressListener progressListener = ProgressListener.NOOP;
44
45     /**
46      * Arbitrary options storage for individual {@link AmazonWebServiceRequest}s. This field is not
47      * intended to be used by clients.
48      */

49     private final RequestClientOptions requestClientOptions = new RequestClientOptions();
50
51     /**
52      * A request metric collector used for this specific service request; or null if there is none.
53      * This collector always takes precedence over the ones specified at the http client level and
54      * AWS SDK level.
55      */

56     private RequestMetricCollector requestMetricCollector;
57
58     /**
59      * The optional credentials to use for this request - overrides the default credentials set at
60      * the client level.
61      */

62     private AWSCredentialsProvider credentialsProvider;
63
64     /**
65      * A map of custom header names to header values.
66      */

67     private Map<String, String> customRequestHeaders;
68
69     /**
70      * Custom query parameters for the request.
71      */

72     private Map<String, List<String>> customQueryParameters;
73
74     /**
75      * User-defined context for the request.
76      */

77     private transient Map<HandlerContextKey<?>, Object> handlerContext = new HashMap<HandlerContextKey<?>, Object>();
78
79     /**
80      * The source object from which the current object was cloned; or null if there isn't one.
81      */

82     private AmazonWebServiceRequest cloneSource;
83
84     private Integer sdkRequestTimeout = null;
85
86     private Integer sdkClientExecutionTimeout = null;
87
88     /**
89      * Sets the optional credentials to use for this request, overriding the default credentials set at the client level.
90      *
91      * @param credentials The optional AWS security credentials to use for this request, overriding the default credentials set at
92      *                    the client level.
93      * @deprecated by {@link #setRequestCredentialsProvider(AWSCredentialsProvider)}. If you must use {@link AWSCredentials} you
94      * can wrap it with a {@link com.amazonaws.auth.AWSStaticCredentialsProvider}.
95      */

96     @Deprecated
97     public void setRequestCredentials(AWSCredentials credentials) {
98         this.credentialsProvider = credentials == null ? null : new StaticCredentialsProvider(credentials);
99     }
100
101     /**
102      * Returns the optional credentials to use to sign this request, overriding the default
103      * credentials set at the client level.
104      *
105      * @return The optional credentials to use to sign this request, overriding the default
106      *         credentials set at the client level.
107      *
108      * @deprecated by {@link #getRequestCredentialsProvider()}
109      */

110     @Deprecated
111     public AWSCredentials getRequestCredentials() {
112         return credentialsProvider == null ? null : credentialsProvider.getCredentials();
113     }
114
115     /**
116      * Sets the optional credentials provider to use for this request, overriding the default credentials
117      * provider at the client level.
118      *
119      * @param credentialsProvider
120      *            The optional AWS security credentials provider to use for this request, overriding the
121      *            default credentials provider at the client level.
122      */

123     public void setRequestCredentialsProvider(AWSCredentialsProvider credentialsProvider) {
124         this.credentialsProvider = credentialsProvider;
125     }
126
127     /**
128      * Returns the optional credentials provider to use to sign this request, overriding the default
129      * credentials provider at the client level.
130      *
131      * @return The optional credentials provider to use to sign this request, overriding the default
132      *         credentials provider at the client level.
133      */

134     public AWSCredentialsProvider getRequestCredentialsProvider() {
135         return credentialsProvider;
136     }
137
138     /**
139      * Sets the optional credentials provider to use for this request, overriding the default credentials
140      * provider at the client level.
141      *
142      * @param credentialsProvider
143      *            The optional AWS security credentials provider to use for this request, overriding the
144      *            default credentials provider at the client level.
145      * @return A reference to this updated object so that method calls can be chained together.
146      */

147     public <T extends AmazonWebServiceRequest> T withRequestCredentialsProvider(final AWSCredentialsProvider credentialsProvider) {
148         setRequestCredentialsProvider(credentialsProvider);
149         @SuppressWarnings("unchecked")
150         T t = (T) this;
151         return t;
152     }
153
154     /**
155      * Gets the options stored with this request object. Intended for internal use only.
156      */

157     public RequestClientOptions getRequestClientOptions() {
158         return requestClientOptions;
159     }
160
161     /**
162      * Returns a request level metric collector; or null if not specified.
163      */

164     public RequestMetricCollector getRequestMetricCollector() {
165         return requestMetricCollector;
166     }
167
168     /**
169      * Sets a request level request metric collector which takes precedence over the ones at the
170      * http client level and AWS SDK level.
171      */

172     public void setRequestMetricCollector(RequestMetricCollector requestMetricCollector) {
173         this.requestMetricCollector = requestMetricCollector;
174     }
175
176     /**
177      * Specifies a request level metric collector which takes precedence over the ones at the http
178      * client level and AWS SDK level.
179      */

180     public <T extends AmazonWebServiceRequest> T withRequestMetricCollector(RequestMetricCollector metricCollector) {
181         setRequestMetricCollector(metricCollector);
182         @SuppressWarnings("unchecked")
183         T t = (T) this;
184         return t;
185     }
186
187     /**
188      * Sets the optional progress listener for receiving updates about the progress of the request.
189      *
190      * @param progressListener
191      *            The new progress listener.
192      */

193     public void setGeneralProgressListener(ProgressListener progressListener) {
194         this.progressListener = progressListener == null ? ProgressListener.NOOP : progressListener;
195     }
196
197     /**
198      * Returns the optional progress listener for receiving updates about the progress of the
199      * request.
200      *
201      * @return the optional progress listener for receiving updates about the progress of the
202      *         request.
203      */

204     public ProgressListener getGeneralProgressListener() {
205         return progressListener;
206     }
207
208     /**
209      * Sets the optional progress listener for receiving updates about the progress of the request,
210      * and returns a reference to this object so that method calls can be chained together.
211      *
212      * @param progressListener
213      *            The new progress listener.
214      * @return A reference to this updated object so that method calls can be chained together.
215      */

216     public <T extends AmazonWebServiceRequest> T withGeneralProgressListener(ProgressListener progressListener) {
217         setGeneralProgressListener(progressListener);
218         @SuppressWarnings("unchecked")
219         T t = (T) this;
220         return t;
221     }
222
223     /**
224      * Returns an immutable map of custom header names to header values.
225      *
226      * @return The immutable map of custom header names to header values.
227      */

228     public Map<String, String> getCustomRequestHeaders() {
229         if (customRequestHeaders == null) {
230             return null;
231         }
232         return Collections.unmodifiableMap(customRequestHeaders);
233     }
234
235     /**
236      * Put a new custom header to the map of custom header names to custom header values, and return
237      * the previous value if the header has already been set in this map.
238      * <p>
239      * Any custom headers that are defined are used in the HTTP request to the AWS service. These
240      * headers will be silently ignored in the event that AWS does not recognize them.
241      * <p>
242      * NOTE: Custom header values set via this method will overwrite any conflicting values coming
243      * from the request parameters.
244      *
245      * @param name
246      *            The name of the header to add
247      * @param value
248      *            The value of the header to add
249      * @return the previous value for the name if it was set, null otherwise
250      */

251     public String putCustomRequestHeader(String name, String value) {
252         if (customRequestHeaders == null) {
253             customRequestHeaders = new HashMap<String, String>();
254         }
255         return customRequestHeaders.put(name, value);
256     }
257
258     /**
259      * @return the immutable map of custom query parameters. The parameter value is modeled as a
260      *         list of strings because multiple values can be specified for the same parameter name.
261      */

262     public Map<String, List<String>> getCustomQueryParameters() {
263         if (customQueryParameters == null) {
264             return null;
265         }
266         return Collections.unmodifiableMap(customQueryParameters);
267     }
268
269     /**
270      * Add a custom query parameter for the request. Since multiple values are allowed for the same
271      * query parameter, this method does NOT overwrite any existing parameter values in the request.
272      * <p>
273      * Any custom query parameters that are defined are used in the HTTP request to the AWS service.
274      *
275      * @param name
276      *            The name of the query parameter
277      * @param value
278      *            The value of the query parameter. Only the parameter name will be added in the URI
279      *            if the value is set to null. For example, putCustomQueryParameter("param"null)
280      *            will be serialized to "?param"while putCustomQueryParameter("param""") will be
281      *            serialized to "?param=".
282      */

283     public void putCustomQueryParameter(String name, String value) {
284         if (customQueryParameters == null) {
285             customQueryParameters = new HashMap<String, List<String>>();
286         }
287         List<String> paramList = customQueryParameters.get(name);
288         if (paramList == null) {
289             paramList = new LinkedList<String>();
290             customQueryParameters.put(name, paramList);
291         }
292         paramList.add(value);
293     }
294
295     @Override
296     public final int getReadLimit() {
297         return requestClientOptions.getReadLimit();
298     }
299
300     /**
301      * Copies the internal state of this base class to that of the target request.
302      *
303      * @return the target request
304      */

305     protected final <T extends AmazonWebServiceRequest> T copyBaseTo(T target) {
306         if (customRequestHeaders != null) {
307             for (Map.Entry<String, String> e : customRequestHeaders.entrySet())
308                 target.putCustomRequestHeader(e.getKey(), e.getValue());
309         }
310         if (customQueryParameters != null) {
311             for (Map.Entry<String, List<String>> e : customQueryParameters.entrySet()) {
312                 if (e.getValue() != null) {
313                     for (String value : e.getValue()) {
314                         target.putCustomQueryParameter(e.getKey(), value);
315                     }
316                 }
317             }
318         }
319
320         target.setRequestCredentialsProvider(credentialsProvider);
321         target.setGeneralProgressListener(progressListener);
322         target.setRequestMetricCollector(requestMetricCollector);
323         requestClientOptions.copyTo(target.getRequestClientOptions());
324         return target;
325     }
326
327     /**
328      * Returns the source object from which the current object was cloned; or null if there isn't
329      * one.
330      */

331     public AmazonWebServiceRequest getCloneSource() {
332         return cloneSource;
333     }
334
335     /**
336      * Returns the root object from which the current object was cloned; or null if there isn't one.
337      */

338     public AmazonWebServiceRequest getCloneRoot() {
339         AmazonWebServiceRequest cloneRoot = cloneSource;
340         if (cloneRoot != null) {
341             while (cloneRoot.getCloneSource() != null) {
342                 cloneRoot = cloneRoot.getCloneSource();
343             }
344         }
345         return cloneRoot;
346     }
347
348     private void setCloneSource(AmazonWebServiceRequest cloneSource) {
349         this.cloneSource = cloneSource;
350     }
351
352     /**
353      * Returns the amount of time to wait (in milliseconds) for the request to complete before
354      * giving up and timing out. A non-positive value disables this feature.
355      * <p>
356      * This feature requires buffering the entire response (for non-streaming APIs) into memory to
357      * enforce a hard timeout when reading the response. For APIs that return large responses this
358      * could be expensive.
359      * <p>
360      * <p>
361      * The request timeout feature doesn't have strict guarantees on how quickly a request is
362      * aborted when the timeout is breached. The typical case aborts the request within a few
363      * milliseconds but there may occasionally be requests that don't get aborted until several
364      * seconds after the timer has been breached. Because of this the request timeout feature should
365      * not be used when absolute precision is needed.
366      * </p>
367      * <p>
368      * <b>Note:</b> This feature is not compatible with Java 1.6.
369      * </p>
370      *
371      * @return The amount of time to wait (in milliseconds) for the request to complete before
372      *         giving up and timing out. A non-positive value disables the timeout for this request.
373      * @see {@link AmazonWebServiceRequest#setSdkClientExecutionTimeout(int)} to enforce a timeout
374      *      across all retries
375      */

376     public Integer getSdkRequestTimeout() {
377         return sdkRequestTimeout;
378     }
379
380     /**
381      * Sets the amount of time to wait (in milliseconds) for the request to complete before giving
382      * up and timing out. A non-positive value disables this feature.
383      * <p>
384      * This feature requires buffering the entire response (for non-streaming APIs) into memory to
385      * enforce a hard timeout when reading the response. For APIs that return large responses this
386      * could be expensive.
387      * <p>
388      * <p>
389      * The request timeout feature doesn't have strict guarantees on how quickly a request is
390      * aborted when the timeout is breached. The typical case aborts the request within a few
391      * milliseconds but there may occasionally be requests that don't get aborted until several
392      * seconds after the timer has been breached. Because of this the request timeout feature should
393      * not be used when absolute precision is needed.
394      * </p>
395      * <p>
396      * <b>Note:</b> This feature is not compatible with Java 1.6.
397      * </p>
398      *
399      * @param sdkRequestTimeout
400      *            The amount of time to wait (in milliseconds) for the request to complete before
401      *            giving up and timing out. A non-positive value disables the timeout for this
402      *            request.
403      * @see {@link AmazonWebServiceRequest#setSdkClientExecutionTimeout(int)} to enforce a timeout
404      *      across all retries
405      */

406     public void setSdkRequestTimeout(int sdkRequestTimeout) {
407         this.sdkRequestTimeout = sdkRequestTimeout;
408     }
409
410     /**
411      * Sets the amount of time to wait (in milliseconds) for the request to complete before giving
412      * up and timing out. A non-positive value disables this feature. Returns the updated
413      * AmazonWebServiceRequest object so that additional method calls may be chained together.
414      * <p>
415      * This feature requires buffering the entire response (for non-streaming APIs) into memory to
416      * enforce a hard timeout when reading the response. For APIs that return large responses this
417      * could be expensive.
418      * <p>
419      * <p>
420      * The request timeout feature doesn't have strict guarantees on how quickly a request is
421      * aborted when the timeout is breached. The typical case aborts the request within a few
422      * milliseconds but there may occasionally be requests that don't get aborted until several
423      * seconds after the timer has been breached. Because of this the request timeout feature should
424      * not be used when absolute precision is needed.
425      * </p>
426      * <p>
427      * <b>Note:</b> This feature is not compatible with Java 1.6.
428      * </p>
429      *
430      * @param sdkRequestTimeout
431      *            The amount of time to wait (in milliseconds) for the request to complete before
432      *            giving up and timing out. A non-positive value disables the timeout for this
433      *            request.
434      * @return The updated {@link AmazonWebServiceRequest} object.
435      * @see {@link AmazonWebServiceRequest#setSdkClientExecutionTimeout(int)} to enforce a timeout
436      *      across all retries
437      */

438     public <T extends AmazonWebServiceRequest> T withSdkRequestTimeout(int sdkRequestTimeout) {
439         setSdkRequestTimeout(sdkRequestTimeout);
440         @SuppressWarnings("unchecked")
441         T t = (T) this;
442         return t;
443     }
444
445     /**
446      * Returns the amount of time (in milliseconds) to allow the client to complete the execution of
447      * an API call. This timeout covers the entire client execution except for marshalling. This
448      * includes request handler execution, all HTTP request including retries, unmarshalling, etc.
449      * <p>
450      * This feature requires buffering the entire response (for non-streaming APIs) into memory to
451      * enforce a hard timeout when reading the response. For APIs that return large responses this
452      * could be expensive.
453      * <p>
454      * <p>
455      * The client execution timeout feature doesn't have strict guarantees on how quickly a request
456      * is aborted when the timeout is breached. The typical case aborts the request within a few
457      * milliseconds but there may occasionally be requests that don't get aborted until several
458      * seconds after the timer has been breached. Because of this the client execution timeout
459      * feature should not be used when absolute precision is needed.
460      * </p>
461      * <p>
462      * This may be used together with {@link AmazonWebServiceRequest#setSdkRequestTimeout(int)} to
463      * enforce both a timeout on each individual HTTP request (i.e. each retry) and the total time
464      * spent on all requests across retries (i.e. the 'client execution' time). A non-positive value
465      * disables this feature.
466      * </p>
467      * <p>
468      * <b>Note:</b> This feature is not compatible with Java 1.6.
469      * </p>
470      *
471      * @return The amount of time (in milliseconds) to allow the client to complete the execution of
472      *         an API call. A non-positive value disables the timeout for this request.
473      * @see {@link AmazonWebServiceRequest#setSdkRequestTimeout(int)} to enforce a timeout per HTTP
474      *      request
475      */

476     public Integer getSdkClientExecutionTimeout() {
477         return this.sdkClientExecutionTimeout;
478     }
479
480     /**
481      * Sets the amount of time (in milliseconds) to allow the client to complete the execution of
482      * an API call. This timeout covers the entire client execution except for marshalling. This
483      * includes request handler execution, all HTTP request including retries, unmarshalling, etc.
484      * <p>
485      * This feature requires buffering the entire response (for non-streaming APIs) into memory to
486      * enforce a hard timeout when reading the response. For APIs that return large responses this
487      * could be expensive.
488      * <p>
489      * <p>
490      * The client execution timeout feature doesn't have strict guarantees on how quickly a request
491      * is aborted when the timeout is breached. The typical case aborts the request within a few
492      * milliseconds but there may occasionally be requests that don't get aborted until several
493      * seconds after the timer has been breached. Because of this the client execution timeout
494      * feature should not be used when absolute precision is needed.
495      * </p>
496      * <p>
497      * This may be used together with {@link AmazonWebServiceRequest#setSdkRequestTimeout(int)} to
498      * enforce both a timeout on each individual HTTP request (i.e. each retry) and the total time
499      * spent on all requests across retries (i.e. the 'client execution' time). A non-positive value
500      * disables this feature.
501      * </p>
502      * <p>
503      * <b>Note:</b> This feature is not compatible with Java 1.6.
504      * </p>
505      *
506      * @param sdkClientExecutionTimeout
507      *            The amount of time (in milliseconds) to allow the client to complete the execution
508      *            of an API call. A non-positive value disables the timeout for this request.
509      * @see {@link AmazonWebServiceRequest#setSdkRequestTimeout(int)} to enforce a timeout per HTTP
510      *      request
511      */

512     public void setSdkClientExecutionTimeout(int sdkClientExecutionTimeout) {
513         this.sdkClientExecutionTimeout = sdkClientExecutionTimeout;
514     }
515
516     /**
517      * Sets the amount of time (in milliseconds) to allow the client to complete the execution of
518      * an API call. This timeout covers the entire client execution except for marshalling. This
519      * includes request handler execution, all HTTP request including retries, unmarshalling, etc.
520      * <p>
521      * This feature requires buffering the entire response (for non-streaming APIs) into memory to
522      * enforce a hard timeout when reading the response. For APIs that return large responses this
523      * could be expensive.
524      * <p>
525      * <p>
526      * The client execution timeout feature doesn't have strict guarantees on how quickly a request
527      * is aborted when the timeout is breached. The typical case aborts the request within a few
528      * milliseconds but there may occasionally be requests that don't get aborted until several
529      * seconds after the timer has been breached. Because of this the client execution timeout
530      * feature should not be used when absolute precision is needed.
531      * </p>
532      * <p>
533      * This may be used together with {@link AmazonWebServiceRequest#setSdkRequestTimeout(int)} to
534      * enforce both a timeout on each individual HTTP request (i.e. each retry) and the total time
535      * spent on all requests across retries (i.e. the 'client execution' time). A non-positive value
536      * disables this feature.
537      * </p>
538      * <p>
539      * <b>Note:</b> This feature is not compatible with Java 1.6.
540      * </p>
541      *
542      * @param sdkClientExecutionTimeout
543      *            The amount of time (in milliseconds) to allow the client to complete the execution
544      *            of an API call. A non-positive value disables the timeout for this request.
545      * @return The updated AmazonWebServiceRequest object for method chaining
546      * @see {@link AmazonWebServiceRequest#setSdkRequestTimeout(int)} to enforce a timeout per HTTP
547      *      request
548      */

549     public <T extends AmazonWebServiceRequest> T withSdkClientExecutionTimeout(int sdkClientExecutionTimeout) {
550         setSdkClientExecutionTimeout(sdkClientExecutionTimeout);
551         @SuppressWarnings("unchecked")
552         T t = (T) this;
553         return t;
554     }
555
556     @Override
557     public <X> void addHandlerContext(HandlerContextKey<X> key, X value) {
558         this.handlerContext.put(key, value);
559     }
560
561     @Override
562     @SuppressWarnings("unchecked")
563     public <X> X getHandlerContext(HandlerContextKey<X> key) {
564         return (X) this.handlerContext.get(key);
565     }
566
567     /**
568      * Retrieve an unmodifiable collection of all handler context objects. This allows a {@link Request} derived from a
569      * {@link AmazonWebServiceRequest} to inherit its context. This does not protect the objects within the map from being
570      * modified.
571      *
572      * <p>This should not be used by customers.</p>
573      */

574     @SdkInternalApi
575     Map<HandlerContextKey<?>, Object> getHandlerContext() {
576         return Collections.unmodifiableMap(this.handlerContext);
577     }
578
579     /**
580      * Creates a shallow clone of this object for all fields except the handler context. Explicitly does <em>not</em> clone the
581      * deep structure of the other fields in the message.
582      *
583      * @see Object#clone()
584      */

585     @Override
586     public AmazonWebServiceRequest clone() {
587         try {
588             AmazonWebServiceRequest cloned = (AmazonWebServiceRequest) super.clone();
589             cloned.setCloneSource(this);
590
591             // Deep-copy context to ensure modifications made by the handlers do not leak back to the caller or other uses of the
592             // same request.
593             cloned.handlerContext = new HashMap<HandlerContextKey<?>, Object>(cloned.handlerContext);
594
595             return cloned;
596         } catch (CloneNotSupportedException e) {
597             throw new IllegalStateException(
598                     "Got a CloneNotSupportedException from Object.clone() " + "even though we're Cloneable!", e);
599         }
600     }
601 }
602