Skip to content

Commit d70d43c

Browse files
committed
fix(CopySourceRequestInS3): Updated codegen to customize the request before sending, instead of using interceptors. This change ensures that customized parameters are available for EndpointResolveInterceptors during beforeExecution.
1 parent 1905e7e commit d70d43c

File tree

15 files changed

+385
-56
lines changed

15 files changed

+385
-56
lines changed

Diff for: codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java

+15
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import software.amazon.awssdk.codegen.model.rules.endpoints.ParameterModel;
2424
import software.amazon.awssdk.codegen.model.service.ClientContextParam;
2525
import software.amazon.awssdk.codegen.model.service.CustomOperationContextParam;
26+
import software.amazon.awssdk.codegen.model.service.RequestCustomizer;
2627
import software.amazon.awssdk.core.retry.RetryMode;
2728
import software.amazon.awssdk.core.traits.PayloadTrait;
2829
import software.amazon.awssdk.utils.AttributeMap;
@@ -328,6 +329,11 @@ public class CustomizationConfig {
328329

329330
private List<CustomOperationContextParam> customOperationContextParams;
330331

332+
/**
333+
* Special case API where an api request needs customization before the service call is made.
334+
*/
335+
private Map<String, RequestCustomizer> requestCustomizerMap;
336+
331337
private CustomizationConfig() {
332338
}
333339

@@ -869,4 +875,13 @@ public List<CustomOperationContextParam> getCustomOperationContextParams() {
869875
public void setCustomOperationContextParams(List<CustomOperationContextParam> customOperationContextParams) {
870876
this.customOperationContextParams = customOperationContextParams;
871877
}
878+
879+
public Map<String, RequestCustomizer> getRequestCustomizerMap() {
880+
return requestCustomizerMap;
881+
}
882+
883+
public void setRequestCustomizerMap(Map<String, RequestCustomizer> requestCustomizerMap) {
884+
this.requestCustomizerMap = requestCustomizerMap;
885+
}
886+
872887
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 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+
16+
package software.amazon.awssdk.codegen.model.service;
17+
18+
19+
/**
20+
* This class Customizes any request before the calling the service
21+
*/
22+
public class RequestCustomizer {
23+
24+
// Fully qualified class name of that has a static method which transforms the request.
25+
private String className;
26+
27+
// MethodName that is static method pf class as specified in above className . This function takes the request as input.
28+
// Modifies the input and returns the transformed request.
29+
private String methodName;
30+
31+
public String getClassName() {
32+
return className;
33+
}
34+
35+
public void setClassName(String className) {
36+
this.className = className;
37+
}
38+
39+
public String getMethodName() {
40+
return methodName;
41+
}
42+
43+
public void setMethodName(String methodName) {
44+
this.methodName = methodName;
45+
}
46+
}

Diff for: codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import static software.amazon.awssdk.codegen.internal.Constant.EVENT_PUBLISHER_PARAM_NAME;
2626
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.addS3ArnableFieldCode;
2727
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.applySignerOverrideMethod;
28+
import static software.amazon.awssdk.codegen.poet.client.SyncClientClass.addRequestModifierCode;
2829
import static software.amazon.awssdk.codegen.poet.client.SyncClientClass.getProtocolSpecs;
2930

3031
import com.squareup.javapoet.ClassName;
@@ -332,6 +333,7 @@ protected void addCloseMethod(TypeSpec.Builder type) {
332333
@Override
333334
protected MethodSpec.Builder operationBody(MethodSpec.Builder builder, OperationModel opModel) {
334335

336+
addRequestModifierCode(opModel, model).ifPresent(builder::addCode);
335337
builder.addModifiers(PUBLIC)
336338
.addAnnotation(Override.class);
337339
builder.addStatement("$T clientConfiguration = updateSdkClientConfiguration($L, this.clientConfiguration)",

Diff for: codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java

+26
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020
import static javax.lang.model.element.Modifier.PROTECTED;
2121
import static javax.lang.model.element.Modifier.PUBLIC;
2222
import static javax.lang.model.element.Modifier.STATIC;
23+
import static software.amazon.awssdk.codegen.poet.PoetUtils.classNameFromFqcn;
2324
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.addS3ArnableFieldCode;
2425
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.applySignerOverrideMethod;
2526

2627
import com.squareup.javapoet.ClassName;
28+
import com.squareup.javapoet.CodeBlock;
2729
import com.squareup.javapoet.FieldSpec;
2830
import com.squareup.javapoet.MethodSpec;
2931
import com.squareup.javapoet.ParameterizedTypeName;
@@ -36,6 +38,7 @@
3638
import java.util.List;
3739
import java.util.Map;
3840
import java.util.Objects;
41+
import java.util.Optional;
3942
import java.util.concurrent.CompletableFuture;
4043
import java.util.stream.Collectors;
4144
import java.util.stream.Stream;
@@ -50,6 +53,7 @@
5053
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
5154
import software.amazon.awssdk.codegen.model.intermediate.Protocol;
5255
import software.amazon.awssdk.codegen.model.service.ClientContextParam;
56+
import software.amazon.awssdk.codegen.model.service.RequestCustomizer;
5357
import software.amazon.awssdk.codegen.poet.PoetExtension;
5458
import software.amazon.awssdk.codegen.poet.PoetUtils;
5559
import software.amazon.awssdk.codegen.poet.auth.scheme.AuthSchemeSpecUtils;
@@ -249,6 +253,8 @@ private Stream<MethodSpec> operations(OperationModel opModel) {
249253
private MethodSpec traditionalMethod(OperationModel opModel) {
250254
MethodSpec.Builder method = SyncClientInterface.operationMethodSignature(model, opModel)
251255
.addAnnotation(Override.class);
256+
257+
addRequestModifierCode(opModel, model).ifPresent(method::addCode);
252258
if (!useSraAuth) {
253259
method.addCode(ClientClassUtils.callApplySignerOverrideMethod(opModel));
254260
}
@@ -341,6 +347,26 @@ private MethodSpec traditionalMethod(OperationModel opModel) {
341347
return method.build();
342348
}
343349

350+
public static Optional<CodeBlock> addRequestModifierCode(OperationModel opModel, IntermediateModel model) {
351+
Map<String, RequestCustomizer> requestCustomizerMap = model.getCustomizationConfig().getRequestCustomizerMap();
352+
if (!CollectionUtils.isNullOrEmpty(requestCustomizerMap)) {
353+
RequestCustomizer requestCustomizer = requestCustomizerMap.get(opModel.getOperationName());
354+
355+
if (requestCustomizer != null) {
356+
CodeBlock.Builder builder = CodeBlock.builder();
357+
ClassName instanceType = classNameFromFqcn(requestCustomizer.getClassName());
358+
builder.addStatement("$L = $T.$N($L)",
359+
opModel.getInput().getVariableName(),
360+
instanceType,
361+
requestCustomizer.getMethodName(),
362+
opModel.getInput().getVariableName());
363+
return Optional.of(builder.build());
364+
}
365+
366+
}
367+
return Optional.empty();
368+
}
369+
344370
@Override
345371
protected void addCloseMethod(TypeSpec.Builder type) {
346372
MethodSpec method = MethodSpec.methodBuilder("close")

Diff for: codegen/src/test/java/software/amazon/awssdk/codegen/internal/UtilsTest.java

+5
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,9 @@ public void testUnCapitalize() {
4343
capitalizedToUncapitalized.forEach((capitalized,unCapitalized) ->
4444
assertThat(Utils.unCapitalize(capitalized), is(equalTo(unCapitalized))));
4545
}
46+
47+
// Dummy No-op function which just returns the input as the return function.
48+
public static <T> T dummyRequestModifier(T input) {
49+
return input;
50+
}
4651
}

Diff for: codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/query/customization.config

+7-1
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,11 @@
2121
}
2222
}
2323
}
24-
]
24+
],
25+
"requestCustomizerMap": {
26+
"OperationWithCustomMember": {
27+
"methodName": "dummyRequestModifier",
28+
"className": "software.amazon.awssdk.codegen.internal.UtilsTest"
29+
}
30+
}
2531
}

Diff for: codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/query/service-2.json

+19
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@
8888
"encodings": ["gzip"]
8989
}
9090
},
91+
"OperationWithCustomMember": {
92+
"name": "OperationWithCustomMember",
93+
"http": {
94+
"method": "POST",
95+
"requestUri": "/"
96+
},
97+
"input":{"shape":"WithCustomMember"}
98+
},
9199
"APostOperation": {
92100
"name": "APostOperation",
93101
"http": {
@@ -202,6 +210,17 @@
202210
}
203211
}
204212
},
213+
"WithCustomMember": {
214+
"type": "structure",
215+
"members": {
216+
"StringMemberToBeUpdate" : {
217+
"shape": "String"
218+
},
219+
"StringMember": {
220+
"shape": "String"
221+
}
222+
}
223+
},
205224
"WithOperationContextParam": {
206225
"type": "structure",
207226
"members": {

Diff for: codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/sra/test-query-async-client-class.java

+61
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import software.amazon.awssdk.awscore.exception.AwsServiceException;
1515
import software.amazon.awssdk.awscore.internal.AwsProtocolMetadata;
1616
import software.amazon.awssdk.awscore.internal.AwsServiceProtocol;
17+
import software.amazon.awssdk.codegen.internal.UtilsTest;
1718
import software.amazon.awssdk.core.CredentialType;
1819
import software.amazon.awssdk.core.RequestOverrideConfiguration;
1920
import software.amazon.awssdk.core.SdkPlugin;
@@ -51,6 +52,8 @@
5152
import software.amazon.awssdk.services.query.model.OperationWithChecksumRequiredResponse;
5253
import software.amazon.awssdk.services.query.model.OperationWithContextParamRequest;
5354
import software.amazon.awssdk.services.query.model.OperationWithContextParamResponse;
55+
import software.amazon.awssdk.services.query.model.OperationWithCustomMemberRequest;
56+
import software.amazon.awssdk.services.query.model.OperationWithCustomMemberResponse;
5457
import software.amazon.awssdk.services.query.model.OperationWithCustomizedOperationContextParamRequest;
5558
import software.amazon.awssdk.services.query.model.OperationWithCustomizedOperationContextParamResponse;
5659
import software.amazon.awssdk.services.query.model.OperationWithNoneAuthTypeRequest;
@@ -74,6 +77,7 @@
7477
import software.amazon.awssdk.services.query.transform.GetOperationWithChecksumRequestMarshaller;
7578
import software.amazon.awssdk.services.query.transform.OperationWithChecksumRequiredRequestMarshaller;
7679
import software.amazon.awssdk.services.query.transform.OperationWithContextParamRequestMarshaller;
80+
import software.amazon.awssdk.services.query.transform.OperationWithCustomMemberRequestMarshaller;
7781
import software.amazon.awssdk.services.query.transform.OperationWithCustomizedOperationContextParamRequestMarshaller;
7882
import software.amazon.awssdk.services.query.transform.OperationWithNoneAuthTypeRequestMarshaller;
7983
import software.amazon.awssdk.services.query.transform.OperationWithOperationContextParamRequestMarshaller;
@@ -470,6 +474,63 @@ public CompletableFuture<OperationWithContextParamResponse> operationWithContext
470474
}
471475
}
472476

477+
/**
478+
* Invokes the OperationWithCustomMember operation asynchronously.
479+
*
480+
* @param operationWithCustomMemberRequest
481+
* @return A Java Future containing the result of the OperationWithCustomMember operation returned by the service.<br/>
482+
* The CompletableFuture returned by this method can be completed exceptionally with the following
483+
* exceptions. The exception returned is wrapped with CompletionException, so you need to invoke
484+
* {@link Throwable#getCause} to retrieve the underlying exception.
485+
* <ul>
486+
* <li>SdkException Base class for all exceptions that can be thrown by the SDK (both service and client).
487+
* Can be used for catch all scenarios.</li>
488+
* <li>SdkClientException If any client side error occurs such as an IO related failure, failure to get
489+
* credentials, etc.</li>
490+
* <li>QueryException Base class for all service exceptions. Unknown exceptions will be thrown as an
491+
* instance of this type.</li>
492+
* </ul>
493+
* @sample QueryAsyncClient.OperationWithCustomMember
494+
* @see <a href="https://docs.aws.amazon.com/goto/WebAPI/query-service-2010-05-08/OperationWithCustomMember"
495+
* target="_top">AWS API Documentation</a>
496+
*/
497+
@Override
498+
public CompletableFuture<OperationWithCustomMemberResponse> operationWithCustomMember(
499+
OperationWithCustomMemberRequest operationWithCustomMemberRequest) {
500+
operationWithCustomMemberRequest = UtilsTest.dummyRequestModifier(operationWithCustomMemberRequest);
501+
SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(operationWithCustomMemberRequest,
502+
this.clientConfiguration);
503+
List<MetricPublisher> metricPublishers = resolveMetricPublishers(clientConfiguration, operationWithCustomMemberRequest
504+
.overrideConfiguration().orElse(null));
505+
MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector
506+
.create("ApiCall");
507+
try {
508+
apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "Query Service");
509+
apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "OperationWithCustomMember");
510+
511+
HttpResponseHandler<OperationWithCustomMemberResponse> responseHandler = protocolFactory
512+
.createResponseHandler(OperationWithCustomMemberResponse::builder);
513+
514+
HttpResponseHandler<AwsServiceException> errorResponseHandler = protocolFactory.createErrorResponseHandler();
515+
516+
CompletableFuture<OperationWithCustomMemberResponse> executeFuture = clientHandler
517+
.execute(new ClientExecutionParams<OperationWithCustomMemberRequest, OperationWithCustomMemberResponse>()
518+
.withOperationName("OperationWithCustomMember").withProtocolMetadata(protocolMetadata)
519+
.withMarshaller(new OperationWithCustomMemberRequestMarshaller(protocolFactory))
520+
.withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler)
521+
.withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector)
522+
.withInput(operationWithCustomMemberRequest));
523+
CompletableFuture<OperationWithCustomMemberResponse> whenCompleteFuture = null;
524+
whenCompleteFuture = executeFuture.whenComplete((r, e) -> {
525+
metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect()));
526+
});
527+
return CompletableFutureUtils.forwardExceptionTo(whenCompleteFuture, executeFuture);
528+
} catch (Throwable t) {
529+
metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect()));
530+
return CompletableFutureUtils.failedFuture(t);
531+
}
532+
}
533+
473534
/**
474535
* Invokes the OperationWithCustomizedOperationContextParam operation asynchronously.
475536
*

Diff for: codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/sra/test-query-client-class.java

+52
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import software.amazon.awssdk.awscore.exception.AwsServiceException;
99
import software.amazon.awssdk.awscore.internal.AwsProtocolMetadata;
1010
import software.amazon.awssdk.awscore.internal.AwsServiceProtocol;
11+
import software.amazon.awssdk.codegen.internal.UtilsTest;
1112
import software.amazon.awssdk.core.CredentialType;
1213
import software.amazon.awssdk.core.RequestOverrideConfiguration;
1314
import software.amazon.awssdk.core.SdkPlugin;
@@ -45,6 +46,8 @@
4546
import software.amazon.awssdk.services.query.model.OperationWithChecksumRequiredResponse;
4647
import software.amazon.awssdk.services.query.model.OperationWithContextParamRequest;
4748
import software.amazon.awssdk.services.query.model.OperationWithContextParamResponse;
49+
import software.amazon.awssdk.services.query.model.OperationWithCustomMemberRequest;
50+
import software.amazon.awssdk.services.query.model.OperationWithCustomMemberResponse;
4851
import software.amazon.awssdk.services.query.model.OperationWithCustomizedOperationContextParamRequest;
4952
import software.amazon.awssdk.services.query.model.OperationWithCustomizedOperationContextParamResponse;
5053
import software.amazon.awssdk.services.query.model.OperationWithNoneAuthTypeRequest;
@@ -68,6 +71,7 @@
6871
import software.amazon.awssdk.services.query.transform.GetOperationWithChecksumRequestMarshaller;
6972
import software.amazon.awssdk.services.query.transform.OperationWithChecksumRequiredRequestMarshaller;
7073
import software.amazon.awssdk.services.query.transform.OperationWithContextParamRequestMarshaller;
74+
import software.amazon.awssdk.services.query.transform.OperationWithCustomMemberRequestMarshaller;
7175
import software.amazon.awssdk.services.query.transform.OperationWithCustomizedOperationContextParamRequestMarshaller;
7276
import software.amazon.awssdk.services.query.transform.OperationWithNoneAuthTypeRequestMarshaller;
7377
import software.amazon.awssdk.services.query.transform.OperationWithOperationContextParamRequestMarshaller;
@@ -404,6 +408,54 @@ public OperationWithContextParamResponse operationWithContextParam(
404408
}
405409
}
406410

411+
/**
412+
* Invokes the OperationWithCustomMember operation.
413+
*
414+
* @param operationWithCustomMemberRequest
415+
* @return Result of the OperationWithCustomMember operation returned by the service.
416+
* @throws SdkException
417+
* Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for
418+
* catch all scenarios.
419+
* @throws SdkClientException
420+
* If any client side error occurs such as an IO related failure, failure to get credentials, etc.
421+
* @throws QueryException
422+
* Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type.
423+
* @sample QueryClient.OperationWithCustomMember
424+
* @see <a href="https://docs.aws.amazon.com/goto/WebAPI/query-service-2010-05-08/OperationWithCustomMember"
425+
* target="_top">AWS API Documentation</a>
426+
*/
427+
@Override
428+
public OperationWithCustomMemberResponse operationWithCustomMember(
429+
OperationWithCustomMemberRequest operationWithCustomMemberRequest) throws AwsServiceException, SdkClientException,
430+
QueryException {
431+
operationWithCustomMemberRequest = UtilsTest.dummyRequestModifier(operationWithCustomMemberRequest);
432+
433+
HttpResponseHandler<OperationWithCustomMemberResponse> responseHandler = protocolFactory
434+
.createResponseHandler(OperationWithCustomMemberResponse::builder);
435+
436+
HttpResponseHandler<AwsServiceException> errorResponseHandler = protocolFactory.createErrorResponseHandler();
437+
SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(operationWithCustomMemberRequest,
438+
this.clientConfiguration);
439+
List<MetricPublisher> metricPublishers = resolveMetricPublishers(clientConfiguration, operationWithCustomMemberRequest
440+
.overrideConfiguration().orElse(null));
441+
MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector
442+
.create("ApiCall");
443+
try {
444+
apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "Query Service");
445+
apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "OperationWithCustomMember");
446+
447+
return clientHandler
448+
.execute(new ClientExecutionParams<OperationWithCustomMemberRequest, OperationWithCustomMemberResponse>()
449+
.withOperationName("OperationWithCustomMember").withProtocolMetadata(protocolMetadata)
450+
.withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler)
451+
.withRequestConfiguration(clientConfiguration).withInput(operationWithCustomMemberRequest)
452+
.withMetricCollector(apiCallMetricCollector)
453+
.withMarshaller(new OperationWithCustomMemberRequestMarshaller(protocolFactory)));
454+
} finally {
455+
metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect()));
456+
}
457+
}
458+
407459
/**
408460
* Invokes the OperationWithCustomizedOperationContextParam operation.
409461
*

0 commit comments

Comments
 (0)