Skip to content

Commit 65c4ab0

Browse files
Nicholas DeJacodagnir
authored andcommitted
Add ability to set execution attributes as part of client and request override configurations
1 parent 0370309 commit 65c4ab0

File tree

8 files changed

+246
-13
lines changed

8 files changed

+246
-13
lines changed

core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/handler/AwsClientHandlerUtils.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ static <InputT extends SdkRequest, OutputT extends SdkResponse> ExecutionContext
100100
.putAttribute(SdkInternalExecutionAttribute.DISABLE_HOST_PREFIX_INJECTION,
101101
clientConfig.option(SdkAdvancedClientOption.DISABLE_HOST_PREFIX_INJECTION));
102102

103+
executionAttributes.putAllAttributes(clientConfig.option(SdkClientOption.EXECUTION_ATTRIBUTES));
104+
originalRequest.overrideConfiguration().ifPresent(requestOverrideConfiguration ->
105+
executionAttributes.putAllAttributes(requestOverrideConfiguration.executionAttributes()));
106+
103107
ExecutionInterceptorChain executionInterceptorChain =
104108
new ExecutionInterceptorChain(clientConfig.option(SdkClientOption.EXECUTION_INTERCEPTORS));
105109
return ExecutionContext.builder()

core/sdk-core/src/main/java/software/amazon/awssdk/core/RequestOverrideConfiguration.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.function.Consumer;
2828
import software.amazon.awssdk.annotations.Immutable;
2929
import software.amazon.awssdk.annotations.SdkPublicApi;
30+
import software.amazon.awssdk.core.interceptor.ExecutionAttribute;
3031
import software.amazon.awssdk.core.signer.Signer;
3132
import software.amazon.awssdk.metrics.MetricPublisher;
3233
import software.amazon.awssdk.utils.CollectionUtils;
@@ -46,6 +47,7 @@ public abstract class RequestOverrideConfiguration {
4647
private final Duration apiCallAttemptTimeout;
4748
private final Signer signer;
4849
private final List<MetricPublisher> metricPublishers;
50+
private final Map<ExecutionAttribute<?>, Object> executionAttributes;
4951

5052
protected RequestOverrideConfiguration(Builder<?> builder) {
5153
this.headers = CollectionUtils.deepUnmodifiableMap(builder.headers(), () -> new TreeMap<>(String.CASE_INSENSITIVE_ORDER));
@@ -55,6 +57,7 @@ protected RequestOverrideConfiguration(Builder<?> builder) {
5557
this.apiCallAttemptTimeout = Validate.isPositiveOrNull(builder.apiCallAttemptTimeout(), "apiCallAttemptTimeout");
5658
this.signer = builder.signer();
5759
this.metricPublishers = Collections.unmodifiableList(new ArrayList<>(builder.metricPublishers()));
60+
this.executionAttributes = Collections.unmodifiableMap(new HashMap<>(builder.executionAttributes()));
5861
}
5962

6063
/**
@@ -138,6 +141,14 @@ public List<MetricPublisher> metricPublishers() {
138141
return metricPublishers;
139142
}
140143

144+
/**
145+
* Returns the additional execution attributes to be added to this request.
146+
* This collection of attributes is added in addition to the attributes set on the client.
147+
* An attribute value added on the client within the collection of attributes is superseded by an
148+
* attribute value added on the request.
149+
*/
150+
public Map<ExecutionAttribute<?>, Object> executionAttributes() { return executionAttributes; }
151+
141152
@Override
142153
public boolean equals(Object o) {
143154
if (this == o) {
@@ -371,6 +382,22 @@ default B putRawQueryParameter(String name, String value) {
371382

372383
List<MetricPublisher> metricPublishers();
373384

385+
/**
386+
* Sets the additional execution attributes collection for this request.
387+
* @param executionAttributes Execution attributes map for this request
388+
* @return This object for method chaining.
389+
*/
390+
B executionAttributes(Map<ExecutionAttribute<?>, Object> executionAttributes);
391+
392+
/**
393+
* Add an execution attribute to the existing collection of execution attributes.
394+
* @param attribute The execution attribute object
395+
* @param value The value of the execution attribute.
396+
*/
397+
B addExecutionAttribute(ExecutionAttribute attribute, Object value);
398+
399+
Map<ExecutionAttribute<?>, Object> executionAttributes();
400+
374401
/**
375402
* Create a new {@code SdkRequestOverrideConfiguration} with the properties set on this builder.
376403
*
@@ -387,6 +414,7 @@ protected abstract static class BuilderImpl<B extends Builder> implements Builde
387414
private Duration apiCallAttemptTimeout;
388415
private Signer signer;
389416
private List<MetricPublisher> metricPublishers = new ArrayList<>();
417+
private Map<ExecutionAttribute<?>, Object> executionAttributes = new HashMap<>();
390418

391419
protected BuilderImpl() {
392420
}
@@ -526,5 +554,23 @@ public void setMetricPublishers(List<MetricPublisher> metricPublishers) {
526554
public List<MetricPublisher> metricPublishers() {
527555
return metricPublishers;
528556
}
557+
558+
@Override
559+
public B executionAttributes(Map<ExecutionAttribute<?>, Object> executionAttributes) {
560+
Validate.paramNotNull(executionAttributes, "executionAttributes");
561+
this.executionAttributes = executionAttributes;
562+
return (B) this;
563+
}
564+
565+
@Override
566+
public B addExecutionAttribute(ExecutionAttribute executionAttribute, Object value) {
567+
this.executionAttributes.put(executionAttribute, value);
568+
return (B) this;
569+
}
570+
571+
@Override
572+
public Map<ExecutionAttribute<?>, Object> executionAttributes() { return executionAttributes; }
573+
574+
public void setExecutionAttributes(Map<ExecutionAttribute<?>, Object> executionAttributes) { executionAttributes(executionAttributes); }
529575
}
530576
}

core/sdk-core/src/main/java/software/amazon/awssdk/core/client/builder/SdkDefaultClientBuilder.java

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,7 @@
2222
import static software.amazon.awssdk.core.client.config.SdkAdvancedClientOption.SIGNER;
2323
import static software.amazon.awssdk.core.client.config.SdkAdvancedClientOption.USER_AGENT_PREFIX;
2424
import static software.amazon.awssdk.core.client.config.SdkAdvancedClientOption.USER_AGENT_SUFFIX;
25-
import static software.amazon.awssdk.core.client.config.SdkClientOption.ADDITIONAL_HTTP_HEADERS;
26-
import static software.amazon.awssdk.core.client.config.SdkClientOption.API_CALL_ATTEMPT_TIMEOUT;
27-
import static software.amazon.awssdk.core.client.config.SdkClientOption.API_CALL_TIMEOUT;
28-
import static software.amazon.awssdk.core.client.config.SdkClientOption.ASYNC_HTTP_CLIENT;
29-
import static software.amazon.awssdk.core.client.config.SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED;
30-
import static software.amazon.awssdk.core.client.config.SdkClientOption.ENDPOINT_OVERRIDDEN;
31-
import static software.amazon.awssdk.core.client.config.SdkClientOption.EXECUTION_INTERCEPTORS;
32-
import static software.amazon.awssdk.core.client.config.SdkClientOption.METRIC_PUBLISHERS;
33-
import static software.amazon.awssdk.core.client.config.SdkClientOption.PROFILE_FILE;
34-
import static software.amazon.awssdk.core.client.config.SdkClientOption.PROFILE_NAME;
35-
import static software.amazon.awssdk.core.client.config.SdkClientOption.RETRY_POLICY;
36-
import static software.amazon.awssdk.core.client.config.SdkClientOption.SCHEDULED_EXECUTOR_SERVICE;
37-
import static software.amazon.awssdk.core.client.config.SdkClientOption.SIGNER_OVERRIDDEN;
25+
import static software.amazon.awssdk.core.client.config.SdkClientOption.*;
3826
import static software.amazon.awssdk.core.internal.SdkInternalTestAdvancedClientOption.ENDPOINT_OVERRIDDEN_OVERRIDE;
3927
import static software.amazon.awssdk.utils.CollectionUtils.mergeLists;
4028
import static software.amazon.awssdk.utils.Validate.paramNotNull;
@@ -370,6 +358,7 @@ public final B overrideConfiguration(ClientOverrideConfiguration overrideConfig)
370358
clientConfiguration.option(PROFILE_FILE, overrideConfig.defaultProfileFile().orElse(null));
371359
clientConfiguration.option(PROFILE_NAME, overrideConfig.defaultProfileName().orElse(null));
372360
clientConfiguration.option(METRIC_PUBLISHERS, overrideConfig.metricPublishers());
361+
clientConfiguration.option(EXECUTION_ATTRIBUTES, overrideConfig.executionAttributes());
373362
overrideConfig.advancedOption(ENDPOINT_OVERRIDDEN_OVERRIDE).ifPresent(value -> {
374363
clientConfiguration.option(ENDPOINT_OVERRIDDEN, value);
375364
});

core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/ClientOverrideConfiguration.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.TreeMap;
2626
import java.util.function.Consumer;
2727
import software.amazon.awssdk.annotations.SdkPublicApi;
28+
import software.amazon.awssdk.core.interceptor.ExecutionAttribute;
2829
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
2930
import software.amazon.awssdk.core.retry.RetryMode;
3031
import software.amazon.awssdk.core.retry.RetryPolicy;
@@ -57,6 +58,7 @@ public final class ClientOverrideConfiguration
5758
private final ProfileFile defaultProfileFile;
5859
private final String defaultProfileName;
5960
private final List<MetricPublisher> metricPublishers;
61+
private final Map<ExecutionAttribute<?>, Object> executionAttributes;
6062

6163
/**
6264
* Initialize this configuration. Private to require use of {@link #builder()}.
@@ -71,6 +73,7 @@ private ClientOverrideConfiguration(Builder builder) {
7173
this.defaultProfileFile = builder.defaultProfileFile();
7274
this.defaultProfileName = builder.defaultProfileName();
7375
this.metricPublishers = Collections.unmodifiableList(new ArrayList<>(builder.metricPublishers()));
76+
this.executionAttributes = Collections.unmodifiableMap(new HashMap<>(builder.executionAttributes()));
7477
}
7578

7679
@Override
@@ -196,6 +199,13 @@ public List<MetricPublisher> metricPublishers() {
196199
return metricPublishers;
197200
}
198201

202+
/**
203+
* Returns the additional execution attributes to be added for this client.
204+
*
205+
* @Return Map of execution attributes.
206+
*/
207+
public Map<ExecutionAttribute<?>, Object> executionAttributes() { return executionAttributes; }
208+
199209
@Override
200210
public String toString() {
201211
return ToString.builder("ClientOverrideConfiguration")
@@ -439,6 +449,22 @@ default Builder retryPolicy(RetryMode retryMode) {
439449
Builder addMetricPublisher(MetricPublisher metricPublisher);
440450

441451
List<MetricPublisher> metricPublishers();
452+
453+
/**
454+
* Sets the additional execution attributes collection for this client.
455+
* @param executionAttributes Execution attributes map for this client.
456+
* @return This object for method chaining.
457+
*/
458+
Builder executionAttributes(Map<ExecutionAttribute<?>, Object> executionAttributes);
459+
460+
/**
461+
* Add an execution attribute to the existing collection of execution attributes.
462+
* @param attribute The execution attribute object
463+
* @param value The value of the execution attribute.
464+
*/
465+
Builder addExecutionAttribute(ExecutionAttribute attribute, Object value);
466+
467+
Map<ExecutionAttribute<?>, Object> executionAttributes();
442468
}
443469

444470
/**
@@ -454,6 +480,7 @@ private static final class DefaultClientOverrideConfigurationBuilder implements
454480
private ProfileFile defaultProfileFile;
455481
private String defaultProfileName;
456482
private List<MetricPublisher> metricPublishers = new ArrayList<>();
483+
private Map<ExecutionAttribute<?>, Object> executionAttributes = new HashMap<>();
457484

458485
@Override
459486
public Builder headers(Map<String, List<String>> headers) {
@@ -618,6 +645,22 @@ public List<MetricPublisher> metricPublishers() {
618645
return Collections.unmodifiableList(metricPublishers);
619646
}
620647

648+
@Override
649+
public Builder executionAttributes(Map<ExecutionAttribute<?>, Object> executionAttributes) {
650+
Validate.paramNotNull(executionAttributes, "executionAttributes");
651+
this.executionAttributes = executionAttributes;
652+
return this;
653+
}
654+
655+
@Override
656+
public Builder addExecutionAttribute(ExecutionAttribute executionAttribute, Object value) {
657+
this.executionAttributes.put(executionAttribute, value);
658+
return this;
659+
}
660+
661+
@Override
662+
public Map<ExecutionAttribute<?>, Object> executionAttributes() { return executionAttributes; }
663+
621664
@Override
622665
public ClientOverrideConfiguration build() {
623666
return new ClientOverrideConfiguration(this);

core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOption.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import software.amazon.awssdk.annotations.SdkProtectedApi;
2424
import software.amazon.awssdk.core.ClientType;
2525
import software.amazon.awssdk.core.ServiceConfiguration;
26+
import software.amazon.awssdk.core.interceptor.ExecutionAttribute;
2627
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
2728
import software.amazon.awssdk.core.retry.RetryPolicy;
2829
import software.amazon.awssdk.http.SdkHttpClient;
@@ -138,6 +139,12 @@ public final class SdkClientOption<T> extends ClientOption<T> {
138139
*/
139140
public static final SdkClientOption<Boolean> SIGNER_OVERRIDDEN = new SdkClientOption<>(Boolean.class);
140141

142+
/**
143+
* Option to specify additional execution attributes to each client call.
144+
*/
145+
public static final SdkClientOption<Map<ExecutionAttribute<?>, Object>> EXECUTION_ATTRIBUTES =
146+
new SdkClientOption<>(new UnsafeValueType(Map.class));
147+
141148
private SdkClientOption(Class<T> valueClass) {
142149
super(valueClass);
143150
}

core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/ExecutionAttributes.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ public <U> ExecutionAttributes putAttribute(ExecutionAttribute<U> attribute, U v
4848
return this;
4949
}
5050

51+
/**
52+
* Add all execution attributes from the provided collection to the internal collection of attributes.
53+
*/
54+
public <U> ExecutionAttributes putAllAttributes(Map<ExecutionAttribute<?>, Object> executionAttributes) {
55+
this.attributes.putAll(executionAttributes);
56+
return this;
57+
}
58+
5159
/**
5260
* Set the provided attribute in this collection of attributes if it does not already exist in the collection.
5361
*/

core/sdk-core/src/test/java/software/amazon/awssdk/core/RequestOverrideConfigurationTest.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.List;
2727
import java.util.Map;
2828
import org.junit.Test;
29+
import software.amazon.awssdk.core.interceptor.ExecutionAttribute;
2930
import software.amazon.awssdk.metrics.MetricPublisher;
3031
import software.amazon.awssdk.utils.ImmutableMap;
3132

@@ -165,4 +166,71 @@ public void addMetricPublisher_listPreviouslyAdded_appendedToList() {
165166

166167
assertThat(overrideConfig.metricPublishers()).containsExactly(publishers.get(0), publishers.get(1), thirdAdded);
167168
}
169+
170+
@Test
171+
public void executionAttributes_createsCopy() {
172+
Map<ExecutionAttribute<?>, Object> executionAttributes = new HashMap<>();
173+
174+
ExecutionAttribute testAttribute = new ExecutionAttribute("TestAttribute");
175+
String expectedValue = "Value1";
176+
executionAttributes.put(testAttribute, expectedValue);
177+
178+
SdkRequestOverrideConfiguration overrideConfig = SdkRequestOverrideConfiguration.builder()
179+
.executionAttributes(executionAttributes)
180+
.build();
181+
182+
executionAttributes.remove(testAttribute);
183+
assertThat(overrideConfig.executionAttributes().get(testAttribute)).isEqualTo(expectedValue);
184+
}
185+
186+
@Test
187+
public void executionAttributes_maintainsAllAdded() {
188+
Map<ExecutionAttribute, Object> executionAttributeObjectMap = new HashMap<>();
189+
for (int i = 0; i < 5; i++) {
190+
executionAttributeObjectMap.put(new ExecutionAttribute<>("Attribute" + i), mock(Object.class));
191+
}
192+
193+
SdkRequestOverrideConfiguration.Builder builder = SdkRequestOverrideConfiguration.builder();
194+
195+
for (Map.Entry<ExecutionAttribute, Object> attributeObjectEntry : executionAttributeObjectMap.entrySet()) {
196+
builder.addExecutionAttribute(attributeObjectEntry.getKey(), attributeObjectEntry.getValue());
197+
}
198+
199+
SdkRequestOverrideConfiguration overrideConfig = builder.build();
200+
assertThat(overrideConfig.executionAttributes()).isEqualTo(executionAttributeObjectMap);
201+
}
202+
203+
@Test
204+
public void executionAttributes_overwritesPreviouslyAdded() {
205+
Map<ExecutionAttribute<?>, Object> executionAttributes = new HashMap<>();
206+
for (int i = 0; i < 5; i++) {
207+
executionAttributes.put(new ExecutionAttribute<>("Attribute" + i), mock(Object.class));
208+
}
209+
210+
SdkRequestOverrideConfiguration.Builder builder = SdkRequestOverrideConfiguration.builder();
211+
212+
builder.addExecutionAttribute(new ExecutionAttribute("AddedAttribute"), mock(Object.class));
213+
builder.executionAttributes(executionAttributes);
214+
SdkRequestOverrideConfiguration overrideConfig = builder.build();
215+
assertThat(overrideConfig.executionAttributes()).isEqualTo(executionAttributes);
216+
}
217+
218+
@Test
219+
public void executionAttributes_listPreviouslyAdded_appendedToList() {
220+
Map<ExecutionAttribute<?>, Object> executionAttributes = new HashMap<>();
221+
for (int i = 0; i < 5; i++) {
222+
executionAttributes.put(new ExecutionAttribute<>("Attribute" + i), mock(Object.class));
223+
}
224+
225+
SdkRequestOverrideConfiguration.Builder builder = SdkRequestOverrideConfiguration.builder();
226+
227+
builder.executionAttributes(executionAttributes);
228+
ExecutionAttribute addedAttribute = new ExecutionAttribute("AddedAttribute");
229+
Object addedValue = mock(Object.class);
230+
231+
builder.addExecutionAttribute(addedAttribute, addedValue);
232+
233+
SdkRequestOverrideConfiguration overrideConfig = builder.build();
234+
assertThat(overrideConfig.executionAttributes().get(addedAttribute)).isEqualTo(addedValue);
235+
}
168236
}

0 commit comments

Comments
 (0)