Skip to content

Commit 179ac87

Browse files
16lim21Michael Li
andauthored
Adding batchManager() method into code generated sync and async clients (#2666)
* Moving protected APIs out of internal package * Refactoring test import * Adding configurable option for users to specify batchKey and batchBuffer limit * Modifying batchBuffer and batchingMap to handle limits * Returning exception on batch entry failure * Modifying test to expect exception on batch entry failure * Refactoring core DefaultBatchManager Allows for either an exception or response to be returned by the responseMapper. Also adding tests and option to specify batchKey and batchBuffer limits. * Modifying SqsBatchManager and associated files to accept generated client's executor and ScheduledExecutor * Adding batchManager configuration class * Adding batchManager config into CustomizationConfig * Adding batchManager() method * Adding batchManager config into sqs customization.config * Removed need for a hasExecutor and hasScheduledExecutor configuration * Removed need to check and sepcify instance type * Adding .batchManager() method to async client * Removing create() method in AsyncBatchManager and adding async batch manager return type to customization config * Adding expected generated test files * Adding tests for codegen batchManager() method * Modifying SqsBatchManager tests to use client's batchManager() method * Modifying codegen to use a scheduledExecutor (sync clients don't support regular executor) * Addressing PR comments * Addressing more PR comments * Only create default executor if builder.executor is null. Adding tests to check as well * Fixing checkstyle issues * Reverting to using Executor instead of ExecutorService Co-authored-by: Michael Li <[email protected]>
1 parent 2adad8d commit 179ac87

File tree

25 files changed

+579
-70
lines changed

25 files changed

+579
-70
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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.config.customization;
17+
18+
/**
19+
* Config required to generate a batchManager method that returns an instance of a BatchManager in addition to any required
20+
* executors or scheduledExecutors.
21+
*/
22+
public class BatchManagerMethod {
23+
24+
public static final String METHOD_NAME = "batchManager";
25+
26+
/** Fqcn of the return type of the operation for the sync client */
27+
private String returnType;
28+
29+
/** Fqcn of the return type of the operation for the async client */
30+
private String asyncReturnType;
31+
32+
public String getReturnType() {
33+
return returnType;
34+
}
35+
36+
public void setReturnType(String returnType) {
37+
this.returnType = returnType;
38+
}
39+
40+
public String getAsyncReturnType() {
41+
return asyncReturnType;
42+
}
43+
44+
public void setAsyncReturnType(String asyncReturnType) {
45+
this.asyncReturnType = asyncReturnType;
46+
}
47+
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ public class CustomizationConfig {
189189

190190
private String userAgent;
191191

192+
private BatchManagerMethod batchManagerMethod;
193+
192194
private CustomizationConfig() {
193195
}
194196

@@ -485,4 +487,12 @@ public CustomizationConfig withUserAgent(String userAgent) {
485487
this.userAgent = userAgent;
486488
return this;
487489
}
490+
491+
public BatchManagerMethod getBatchManagerMethod() {
492+
return batchManagerMethod;
493+
}
494+
495+
public void setBatchManagerMethod(BatchManagerMethod batchManagerMethod) {
496+
this.batchManagerMethod = batchManagerMethod;
497+
}
488498
}

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.addS3ArnableFieldCode;
2424
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.applyPaginatorUserAgentMethod;
2525
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.applySignerOverrideMethod;
26+
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.batchMangerMethod;
2627
import static software.amazon.awssdk.codegen.poet.client.SyncClientClass.getProtocolSpecs;
2728

2829
import com.squareup.javapoet.ClassName;
@@ -83,13 +84,15 @@ public final class AsyncClientClass extends AsyncClientInterface {
8384
private final PoetExtensions poetExtensions;
8485
private final ClassName className;
8586
private final ProtocolSpec protocolSpec;
87+
private boolean hasScheduledExecutor;
8688

8789
public AsyncClientClass(GeneratorTaskParams dependencies) {
8890
super(dependencies.getModel());
8991
this.model = dependencies.getModel();
9092
this.poetExtensions = dependencies.getPoetExtensions();
9193
this.className = poetExtensions.getClientClass(model.getMetadata().getAsyncClient());
9294
this.protocolSpec = getProtocolSpecs(poetExtensions, model);
95+
this.hasScheduledExecutor = false;
9396
}
9497

9598
@Override
@@ -141,12 +144,16 @@ public TypeSpec poetSpec() {
141144
protocolSpec.createErrorResponseHandler().ifPresent(classBuilder::addMethod);
142145

143146
if (model.hasWaiters()) {
144-
classBuilder.addField(FieldSpec.builder(ClassName.get(ScheduledExecutorService.class), "executorService")
145-
.addModifiers(PRIVATE, FINAL)
146-
.build());
147147
classBuilder.addMethod(waiterImplMethod());
148+
addScheduledExecutorIfNeeded(classBuilder);
149+
}
150+
151+
if (model.getCustomizationConfig().getBatchManagerMethod() != null) {
152+
classBuilder.addMethod(batchMangerMethod(model, false));
153+
addScheduledExecutorIfNeeded(classBuilder);
148154
}
149155

156+
150157
return classBuilder.build();
151158
}
152159

@@ -195,7 +202,7 @@ private MethodSpec constructor(Builder classBuilder) {
195202
builder.endControlFlow();
196203
}
197204

198-
if (model.hasWaiters()) {
205+
if (model.hasWaiters() || model.getCustomizationConfig().getBatchManagerMethod() != null) {
199206
builder.addStatement("this.executorService = clientConfiguration.option($T.SCHEDULED_EXECUTOR_SERVICE)",
200207
SdkClientOption.class);
201208
}
@@ -485,4 +492,13 @@ private boolean hasStreamingV4AuthOperations() {
485492
return model.getOperations().values().stream()
486493
.anyMatch(this::shouldUseAsyncWithBodySigner);
487494
}
495+
496+
private void addScheduledExecutorIfNeeded(Builder classBuilder) {
497+
if (!hasScheduledExecutor) {
498+
classBuilder.addField(FieldSpec.builder(ClassName.get(ScheduledExecutorService.class), "executorService")
499+
.addModifiers(PRIVATE, FINAL)
500+
.build());
501+
hasScheduledExecutor = true;
502+
}
503+
}
488504
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientInterface.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import software.amazon.awssdk.codegen.docs.DocConfiguration;
4040
import software.amazon.awssdk.codegen.docs.SimpleMethodOverload;
4141
import software.amazon.awssdk.codegen.docs.WaiterDocs;
42+
import software.amazon.awssdk.codegen.model.config.customization.BatchManagerMethod;
4243
import software.amazon.awssdk.codegen.model.config.customization.UtilitiesMethod;
4344
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
4445
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
@@ -108,6 +109,10 @@ public TypeSpec poetSpec() {
108109
result.addMethod(waiterMethod());
109110
}
110111

112+
if (model.getCustomizationConfig().getBatchManagerMethod() != null) {
113+
result.addMethod(batchManagerMethod());
114+
}
115+
111116
return result.build();
112117
}
113118

@@ -467,4 +472,17 @@ private MethodSpec waiterMethod() {
467472
.addJavadoc(WaiterDocs.waiterMethodInClient(poetExtensions.getAsyncWaiterInterface()))
468473
.build();
469474
}
475+
476+
private MethodSpec batchManagerMethod() {
477+
BatchManagerMethod config = model.getCustomizationConfig().getBatchManagerMethod();
478+
ClassName returnType = PoetUtils.classNameFromFqcn(config.getAsyncReturnType());
479+
480+
return MethodSpec.methodBuilder("batchManager")
481+
.returns(returnType)
482+
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
483+
.addStatement("throw new $T()", UnsupportedOperationException.class)
484+
.addJavadoc("Creates an instance of {@link $T} object with the "
485+
+ "configuration set on this client.", returnType)
486+
.build();
487+
}
470488
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/ClientClassUtils.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import software.amazon.awssdk.arns.Arn;
3333
import software.amazon.awssdk.auth.signer.EventStreamAws4Signer;
3434
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
35+
import software.amazon.awssdk.codegen.model.config.customization.BatchManagerMethod;
3536
import software.amazon.awssdk.codegen.model.config.customization.S3ArnableFieldConfig;
3637
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
3738
import software.amazon.awssdk.codegen.model.intermediate.MemberModel;
@@ -268,6 +269,25 @@ static Optional<CodeBlock> addS3ArnableFieldCode(OperationModel opModel, Interme
268269
return Optional.empty();
269270
}
270271

272+
static MethodSpec batchMangerMethod(IntermediateModel model, boolean isSync) {
273+
String scheduledExecutor = "executorService";
274+
BatchManagerMethod config = model.getCustomizationConfig().getBatchManagerMethod();
275+
ClassName returnType;
276+
if (isSync) {
277+
returnType = PoetUtils.classNameFromFqcn(config.getReturnType());
278+
} else {
279+
returnType = PoetUtils.classNameFromFqcn(config.getAsyncReturnType());
280+
}
281+
282+
return MethodSpec.methodBuilder(BatchManagerMethod.METHOD_NAME)
283+
.addModifiers(Modifier.PUBLIC)
284+
.addAnnotation(Override.class)
285+
.returns(returnType)
286+
.addStatement("return $T.builder().client(this).scheduledExecutor($N).build()",
287+
returnType, scheduledExecutor)
288+
.build();
289+
}
290+
271291
/**
272292
* Given operation and c2j name, returns the String that represents calling the
273293
* c2j member's getter method in the opmodel input shape.

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.addS3ArnableFieldCode;
2222
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.applyPaginatorUserAgentMethod;
2323
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.applySignerOverrideMethod;
24+
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.batchMangerMethod;
2425

2526
import com.squareup.javapoet.ClassName;
2627
import com.squareup.javapoet.FieldSpec;
@@ -32,6 +33,7 @@
3233
import java.util.ArrayList;
3334
import java.util.Collections;
3435
import java.util.List;
36+
import java.util.concurrent.ScheduledExecutorService;
3537
import java.util.stream.Collectors;
3638
import javax.lang.model.element.Modifier;
3739
import software.amazon.awssdk.annotations.SdkInternalApi;
@@ -116,6 +118,13 @@ public TypeSpec poetSpec() {
116118
classBuilder.addMethod(utilitiesMethod());
117119
}
118120

121+
if (model.getCustomizationConfig().getBatchManagerMethod() != null) {
122+
classBuilder.addMethod(batchMangerMethod(model, true));
123+
classBuilder.addField(FieldSpec.builder(ClassName.get(ScheduledExecutorService.class), "executorService")
124+
.addModifiers(PRIVATE, FINAL)
125+
.build());
126+
}
127+
119128
model.getEndpointOperation().ifPresent(
120129
o -> classBuilder.addField(EndpointDiscoveryRefreshCache.class, "endpointDiscoveryCache", PRIVATE));
121130

@@ -181,6 +190,11 @@ private MethodSpec constructor() {
181190
builder.endControlFlow();
182191
}
183192

193+
if (model.getCustomizationConfig().getBatchManagerMethod() != null) {
194+
builder.addStatement("this.executorService = clientConfiguration.option($T.SCHEDULED_EXECUTOR_SERVICE)",
195+
SdkClientOption.class);
196+
}
197+
184198
return builder.build();
185199
}
186200

codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientInterface.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import software.amazon.awssdk.codegen.docs.DocConfiguration;
4343
import software.amazon.awssdk.codegen.docs.SimpleMethodOverload;
4444
import software.amazon.awssdk.codegen.docs.WaiterDocs;
45+
import software.amazon.awssdk.codegen.model.config.customization.BatchManagerMethod;
4546
import software.amazon.awssdk.codegen.model.config.customization.UtilitiesMethod;
4647
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
4748
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
@@ -110,6 +111,10 @@ public TypeSpec poetSpec() {
110111
result.addMethod(waiterMethod());
111112
}
112113

114+
if (model.getCustomizationConfig().getBatchManagerMethod() != null) {
115+
result.addMethod(batchManagerMethod());
116+
}
117+
113118
return result.build();
114119
}
115120

@@ -498,4 +503,17 @@ private MethodSpec waiterMethod() {
498503
.addJavadoc(WaiterDocs.waiterMethodInClient(poetExtensions.getSyncWaiterInterface()))
499504
.build();
500505
}
506+
507+
private MethodSpec batchManagerMethod() {
508+
BatchManagerMethod config = model.getCustomizationConfig().getBatchManagerMethod();
509+
ClassName returnType = PoetUtils.classNameFromFqcn(config.getReturnType());
510+
511+
return MethodSpec.methodBuilder("batchManager")
512+
.returns(returnType)
513+
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
514+
.addStatement("throw new $T()", UnsupportedOperationException.class)
515+
.addJavadoc("Creates an instance of {@link $T} object with the "
516+
+ "configuration set on this client.", returnType)
517+
.build();
518+
}
501519
}

codegen/src/test/java/software/amazon/awssdk/codegen/poet/ClientTestModels.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,18 @@ public static IntermediateModel internalConfigModels() {
109109
return new IntermediateModelBuilder(models).build();
110110
}
111111

112+
public static IntermediateModel batchManagerModels() {
113+
File serviceModel = new File(ClientTestModels.class.getResource("client/c2j/batchmanager/service-2.json").getFile());
114+
File customizationModel = new File(ClientTestModels.class.getResource("client/c2j/batchmanager/customization.config").getFile());
115+
116+
C2jModels models = C2jModels.builder()
117+
.serviceModel(getServiceModel(serviceModel))
118+
.customizationConfig(getCustomizationConfig(customizationModel))
119+
.build();
120+
121+
return new IntermediateModelBuilder(models).build();
122+
}
123+
112124
private static ServiceModel getServiceModel(File file) {
113125
return ModelLoaderUtils.loadModel(ServiceModel.class, file);
114126
}

codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/PoetClientFunctionalTests.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
2424
import software.amazon.awssdk.codegen.poet.ClassSpec;
2525
import software.amazon.awssdk.codegen.poet.ClientTestModels;
26+
import software.amazon.awssdk.codegen.poet.waiters.WaiterInterfaceSpec;
2627

2728
public class PoetClientFunctionalTests {
2829

@@ -117,4 +118,29 @@ public void syncClientCustomServiceMetaData() throws Exception {
117118
ClassSpec syncClientCustomServiceMetaData = createSyncClientClass(ClientTestModels.customContentTypeModels());
118119
assertThat(syncClientCustomServiceMetaData, generatesTo("test-customservicemetadata-sync.java"));
119120
}
121+
122+
@Test
123+
public void syncClientBatchManager() throws Exception {
124+
ClassSpec syncClientBatchManager = createSyncClientClass(ClientTestModels.batchManagerModels());
125+
assertThat(syncClientBatchManager, generatesTo("test-batchmanager-sync-class.java"));
126+
}
127+
128+
@Test
129+
public void asyncClientBatchManager() throws Exception {
130+
ClassSpec asyncClientBatchManager = new AsyncClientClass(
131+
GeneratorTaskParams.create(ClientTestModels.batchManagerModels(), "sources/", "tests/"));
132+
assertThat(asyncClientBatchManager, generatesTo("test-batchmanager-async-class.java"));
133+
}
134+
135+
@Test
136+
public void syncClientBatchManagerInterface() throws Exception {
137+
ClassSpec syncClientBatchManagerInterface = new SyncClientInterface(ClientTestModels.batchManagerModels());
138+
assertThat(syncClientBatchManagerInterface, generatesTo("test-batchmanager-sync-interface.java"));
139+
}
140+
141+
@Test
142+
public void asyncClientBatchManagerInterface() throws Exception {
143+
ClassSpec asyncClientBatchManagerInterface = new AsyncClientInterface(ClientTestModels.batchManagerModels());
144+
assertThat(asyncClientBatchManagerInterface, generatesTo("test-batchmanager-async-interface.java"));
145+
}
120146
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"batchManagerMethod": {
3+
"returnType": "software.amazon.awssdk.services.batchmanagertest.batchmanager.SyncBatchManagerTest",
4+
"asyncReturnType": "software.amazon.awssdk.services.batchmanagertest.batchmanager.AsyncBatchManagerTest"
5+
}
6+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"version":"2.0",
3+
"metadata":{
4+
"apiVersion":"2016-03-11",
5+
"endpointPrefix":"batchmanager",
6+
"jsonVersion":"1.1",
7+
"protocol":"rest-json",
8+
"serviceAbbreviation":"BatchManager",
9+
"serviceFullName":"BatchManager",
10+
"serviceId":"BatchManager",
11+
"signatureVersion":"v4",
12+
"uid":"batchmanager-2016-03-11"
13+
},
14+
"operations":{
15+
},
16+
"shapes": {
17+
"String":{"type":"string"}
18+
},
19+
"documentation": "A service that implements the batchManager() method"
20+
}

0 commit comments

Comments
 (0)