Skip to content

Commit 5dd15f7

Browse files
committed
Update codegen module to generate service waiter implementation classes
1 parent 2933e22 commit 5dd15f7

File tree

26 files changed

+1815
-16
lines changed

26 files changed

+1815
-16
lines changed

codegen/src/main/java/software/amazon/awssdk/codegen/docs/WaiterDocs.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.squareup.javapoet.ClassName;
1919
import com.squareup.javapoet.CodeBlock;
2020
import java.util.Map;
21+
import java.util.concurrent.ScheduledExecutorService;
2122
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
2223
import software.amazon.awssdk.codegen.model.service.WaiterDefinition;
2324
import software.amazon.awssdk.core.waiters.PollingStrategy;
@@ -73,9 +74,26 @@ public static CodeBlock waiterBuilderPollingStrategy() {
7374
.build();
7475
}
7576

77+
public static CodeBlock waiterBuilderScheduledExecutorServiceJavadoc() {
78+
String javadocs = new DocumentationBuilder()
79+
.description("Sets a custom {@link $T} that will be used to schedule async polling attempts \n "
80+
+ "<p> This executorService must be closed by the caller when it is ready to be disposed. The"
81+
+ " SDK will not close the executorService when the waiter is closed")
82+
.param("executorService", "the executorService to set")
83+
.returns("a reference to this object so that method calls can be chained together.")
84+
.build();
85+
86+
return CodeBlock.builder()
87+
.add(javadocs, ClassName.get(ScheduledExecutorService.class))
88+
.build();
89+
}
90+
7691
public static CodeBlock waiterBuilderClientJavadoc(ClassName className) {
7792
String javadocs = new DocumentationBuilder()
7893
.description("Defines the {@link $T} to use when polling a resource")
94+
.description("Sets a custom {@link $T} that will be used to pool the resource \n "
95+
+ "<p> This SDK client must be closed by the caller when it is ready to be disposed. The"
96+
+ " SDK will not close the client when the waiter is closed")
7997
.param("client", "the client to send the request")
8098
.returns("a reference to this object so that method calls can be chained together.")
8199
.build();

codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/WaitersGeneratorTasks.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
import software.amazon.awssdk.codegen.emitters.GeneratorTask;
2121
import software.amazon.awssdk.codegen.emitters.GeneratorTaskParams;
2222
import software.amazon.awssdk.codegen.emitters.PoetGeneratorTask;
23+
import software.amazon.awssdk.codegen.poet.waiters.AsyncWaiterClassSpec;
2324
import software.amazon.awssdk.codegen.poet.waiters.AsyncWaiterInterfaceSpec;
25+
import software.amazon.awssdk.codegen.poet.waiters.WaiterClassSpec;
2426
import software.amazon.awssdk.codegen.poet.waiters.WaiterInterfaceSpec;
2527

2628
public class WaitersGeneratorTasks extends BaseGeneratorTasks {
@@ -49,13 +51,17 @@ private List<GeneratorTask> createSyncTasks() {
4951
List<GeneratorTask> syncTasks = new ArrayList<>();
5052
syncTasks.add(new PoetGeneratorTask(waitersClassDir, model.getFileHeader(),
5153
new WaiterInterfaceSpec(model)));
54+
syncTasks.add(new PoetGeneratorTask(waitersClassDir, model.getFileHeader(),
55+
new WaiterClassSpec(model)));
5256
return syncTasks;
5357
}
5458

5559
private List<GeneratorTask> createAsyncTasks() {
5660
List<GeneratorTask> asyncTasks = new ArrayList<>();
5761
asyncTasks.add(new PoetGeneratorTask(waitersClassDir, model.getFileHeader(),
5862
new AsyncWaiterInterfaceSpec(model)));
63+
asyncTasks.add(new PoetGeneratorTask(waitersClassDir, model.getFileHeader(),
64+
new AsyncWaiterClassSpec(model)));
5965
return asyncTasks;
6066
}
6167
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/PoetExtensions.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,21 @@ public ClassName getSyncWaiterInterface() {
8080
return ClassName.get(model.getMetadata().getFullWaitersPackageName(), model.getMetadata().getServiceName() + "Waiter");
8181
}
8282

83+
public ClassName getSyncWaiterClass() {
84+
return ClassName.get(model.getMetadata().getFullWaitersPackageName(), "Default" + model.getMetadata().getServiceName() +
85+
"Waiter");
86+
}
87+
8388
public ClassName getAsyncWaiterInterface() {
8489
return ClassName.get(model.getMetadata().getFullWaitersPackageName(), model.getMetadata().getServiceName() +
8590
"AsyncWaiter");
8691
}
8792

93+
public ClassName getAsyncWaiterClass() {
94+
return ClassName.get(model.getMetadata().getFullWaitersPackageName(), "Default" + model.getMetadata().getServiceName() +
95+
"AsyncWaiter");
96+
}
97+
8898
/**
8999
* @param operationName Name of the operation
90100
* @return A Poet {@link ClassName} for the response type of a async paginated operation in the base service package.

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static com.squareup.javapoet.TypeSpec.Builder;
1919
import static java.util.Collections.singletonList;
20+
import static javax.lang.model.element.Modifier.FINAL;
2021
import static javax.lang.model.element.Modifier.PRIVATE;
2122
import static javax.lang.model.element.Modifier.STATIC;
2223
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.applyPaginatorUserAgentMethod;
@@ -35,6 +36,7 @@
3536
import java.util.Collections;
3637
import java.util.List;
3738
import java.util.concurrent.Executor;
39+
import java.util.concurrent.ScheduledExecutorService;
3840
import java.util.stream.Collectors;
3941
import javax.lang.model.element.Modifier;
4042
import org.reactivestreams.Publisher;
@@ -132,6 +134,13 @@ public TypeSpec poetSpec() {
132134

133135
protocolSpec.createErrorResponseHandler().ifPresent(classBuilder::addMethod);
134136

137+
if (model.hasWaiters()) {
138+
classBuilder.addField(FieldSpec.builder(ClassName.get(ScheduledExecutorService.class), "executorService")
139+
.addModifiers(PRIVATE, FINAL)
140+
.build());
141+
classBuilder.addMethod(waiterImplMethod());
142+
}
143+
135144
return classBuilder.build();
136145
}
137146

@@ -169,6 +178,11 @@ private MethodSpec constructor(Builder classBuilder) {
169178
builder.endControlFlow();
170179
}
171180

181+
if (model.hasWaiters()) {
182+
builder.addStatement("this.executorService = clientConfiguration.option($T.SCHEDULED_EXECUTOR_SERVICE)",
183+
SdkClientOption.class);
184+
}
185+
172186
return builder.build();
173187
}
174188

@@ -326,6 +340,17 @@ private MethodSpec utilitiesMethod() {
326340
.build();
327341
}
328342

343+
private MethodSpec waiterImplMethod() {
344+
return MethodSpec.methodBuilder("waiter")
345+
.addModifiers(Modifier.PUBLIC)
346+
.addAnnotation(Override.class)
347+
.addStatement("return $T.builder().client(this)"
348+
+ ".executorService(executorService).build()",
349+
poetExtensions.getAsyncWaiterInterface())
350+
.returns(poetExtensions.getAsyncWaiterInterface())
351+
.build();
352+
}
353+
329354
private MethodSpec resolveMetricPublishersMethod() {
330355
String clientConfigName = "clientConfiguration";
331356
String requestOverrideConfigName = "requestOverrideConfiguration";

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ public TypeSpec poetSpec() {
9292
result.addMethod(utilitiesMethod());
9393
}
9494

95+
if (model.hasWaiters()) {
96+
result.addMethod(waiterMethod());
97+
}
98+
9599
return result.build();
96100
}
97101

@@ -442,4 +446,13 @@ private MethodSpec utilitiesMethod() {
442446
+ "configuration set on this client.", returnType)
443447
.build();
444448
}
449+
450+
private MethodSpec waiterMethod() {
451+
return MethodSpec.methodBuilder("waiter")
452+
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
453+
.returns(poetExtensions.getAsyncWaiterInterface())
454+
.addStatement("throw new $T()", UnsupportedOperationException.class)
455+
.addJavadoc("Creates an instance of {@link $T} object", poetExtensions.getAsyncWaiterInterface())
456+
.build();
457+
}
445458
}

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
@@ -116,6 +116,10 @@ public TypeSpec poetSpec() {
116116
model.getEndpointOperation().ifPresent(
117117
o -> classBuilder.addField(EndpointDiscoveryRefreshCache.class, "endpointDiscoveryCache", PRIVATE));
118118

119+
if (model.hasWaiters()) {
120+
classBuilder.addMethod(waiterMethod());
121+
}
122+
119123
return classBuilder.build();
120124
}
121125

@@ -320,4 +324,14 @@ private MethodSpec resolveMetricPublishersMethod() {
320324

321325
return methodBuilder.build();
322326
}
327+
328+
private MethodSpec waiterMethod() {
329+
return MethodSpec.methodBuilder("waiter")
330+
.addModifiers(Modifier.PUBLIC)
331+
.addAnnotation(Override.class)
332+
.addStatement("return $T.builder().client(this).build()",
333+
poetExtensions.getSyncWaiterInterface())
334+
.returns(poetExtensions.getSyncWaiterInterface())
335+
.build();
336+
}
323337
}

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,13 @@ public TypeSpec poetSpec() {
9090
result.addMethod(utilitiesMethod());
9191
}
9292

93+
if (model.hasWaiters()) {
94+
result.addMethod(waiterMethod());
95+
}
96+
9397
return result.build();
9498
}
9599

96-
97100
@Override
98101
public ClassName className() {
99102
return className;
@@ -456,4 +459,13 @@ private MethodSpec utilitiesMethod() {
456459
+ "configuration set on this client.", returnType)
457460
.build();
458461
}
462+
463+
private MethodSpec waiterMethod() {
464+
return MethodSpec.methodBuilder("waiter")
465+
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
466+
.addStatement("throw new $T()", UnsupportedOperationException.class)
467+
.returns(poetExtensions.getSyncWaiterInterface())
468+
.addJavadoc("Creates an instance of {@link $T} object", poetExtensions.getSyncWaiterInterface())
469+
.build();
470+
}
459471
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
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.poet.waiters;
17+
18+
import static javax.lang.model.element.Modifier.FINAL;
19+
import static javax.lang.model.element.Modifier.PRIVATE;
20+
import static javax.lang.model.element.Modifier.STATIC;
21+
22+
import com.squareup.javapoet.ClassName;
23+
import com.squareup.javapoet.FieldSpec;
24+
import com.squareup.javapoet.MethodSpec;
25+
import com.squareup.javapoet.ParameterizedTypeName;
26+
import com.squareup.javapoet.TypeSpec;
27+
import java.util.Optional;
28+
import java.util.concurrent.CompletableFuture;
29+
import java.util.concurrent.Executors;
30+
import java.util.concurrent.ScheduledExecutorService;
31+
import javax.lang.model.element.Modifier;
32+
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
33+
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
34+
import software.amazon.awssdk.codegen.poet.PoetExtensions;
35+
import software.amazon.awssdk.core.internal.waiters.WaiterAttribute;
36+
import software.amazon.awssdk.core.waiters.AsyncWaiter;
37+
import software.amazon.awssdk.core.waiters.WaiterResponse;
38+
import software.amazon.awssdk.utils.ThreadFactoryBuilder;
39+
40+
public class AsyncWaiterClassSpec extends BaseWaiterClassSpec {
41+
42+
private final PoetExtensions poetExtensions;
43+
private final ClassName className;
44+
private final IntermediateModel model;
45+
private final String modelPackage;
46+
47+
public AsyncWaiterClassSpec(IntermediateModel model) {
48+
super(model, ClassName.get(AsyncWaiter.class));
49+
this.model = model;
50+
this.modelPackage = model.getMetadata().getFullModelPackageName();
51+
this.poetExtensions = new PoetExtensions(model);
52+
this.className = poetExtensions.getAsyncWaiterClass();
53+
}
54+
55+
@Override
56+
public ClassName className() {
57+
return className;
58+
}
59+
60+
@Override
61+
protected ClassName clientClassName() {
62+
return poetExtensions.getClientClass(model.getMetadata().getAsyncInterface());
63+
}
64+
65+
@Override
66+
protected ParameterizedTypeName getWaiterResponseType(OperationModel opModel) {
67+
ClassName pojoResponse = ClassName.get(modelPackage, opModel.getReturnType().getReturnType());
68+
ParameterizedTypeName waiterResponse = ParameterizedTypeName.get(ClassName.get(WaiterResponse.class), pojoResponse);
69+
70+
return ParameterizedTypeName.get(ClassName.get(CompletableFuture.class),
71+
waiterResponse);
72+
}
73+
74+
@Override
75+
protected ClassName interfaceClassName() {
76+
return poetExtensions.getAsyncWaiterInterface();
77+
}
78+
79+
@Override
80+
protected Optional<String> additionalWaiterConfig() {
81+
return Optional.of(".scheduledExecutorService(executorService)");
82+
}
83+
84+
@Override
85+
protected void additionalConstructorInitialization(MethodSpec.Builder method) {
86+
method.beginControlFlow("if (builder.executorService == null)")
87+
.addStatement("this.executorService = $T.newScheduledThreadPool(5, new $T().threadNamePrefix"
88+
+ "($S).build())",
89+
Executors.class,
90+
ThreadFactoryBuilder.class,
91+
"waiters-ScheduledExecutor")
92+
.addStatement("attributeMapBuilder.put(SCHEDULED_EXECUTOR_SERVICE_ATTRIBUTE, this.executorService)")
93+
.endControlFlow();
94+
95+
method.beginControlFlow("else")
96+
.addStatement("this.executorService = builder.executorService")
97+
.endControlFlow();
98+
}
99+
100+
@Override
101+
protected void additionalTypeSpecModification(TypeSpec.Builder type) {
102+
type.addField(FieldSpec.builder(ParameterizedTypeName.get(WaiterAttribute.class, ScheduledExecutorService.class),
103+
"SCHEDULED_EXECUTOR_SERVICE_ATTRIBUTE", PRIVATE, STATIC, FINAL)
104+
.initializer("new $T<>($T.class)", WaiterAttribute.class, ScheduledExecutorService.class)
105+
.build());
106+
type.addField(FieldSpec.builder(ScheduledExecutorService.class, "executorService")
107+
.addModifiers(PRIVATE, FINAL)
108+
.build());
109+
}
110+
111+
@Override
112+
protected void additionalBuilderTypeSpecModification(TypeSpec.Builder type) {
113+
type.addField(ClassName.get(ScheduledExecutorService.class), "executorService", PRIVATE);
114+
type.addMethod(MethodSpec.methodBuilder("executorService")
115+
.addModifiers(Modifier.PUBLIC)
116+
.addAnnotation(Override.class)
117+
.addParameter(ClassName.get(ScheduledExecutorService.class), "executorService")
118+
.addStatement("this.executorService = executorService")
119+
.addStatement("return this")
120+
.returns(interfaceClassName().nestedClass("Builder"))
121+
.build());
122+
}
123+
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/waiters/AsyncWaiterInterfaceSpec.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,13 @@
1616
package software.amazon.awssdk.codegen.poet.waiters;
1717

1818
import com.squareup.javapoet.ClassName;
19+
import com.squareup.javapoet.MethodSpec;
1920
import com.squareup.javapoet.ParameterizedTypeName;
21+
import com.squareup.javapoet.TypeSpec;
2022
import java.util.concurrent.CompletableFuture;
23+
import java.util.concurrent.ScheduledExecutorService;
24+
import javax.lang.model.element.Modifier;
25+
import software.amazon.awssdk.codegen.docs.WaiterDocs;
2126
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
2227
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
2328
import software.amazon.awssdk.codegen.poet.PoetExtensions;
@@ -38,6 +43,11 @@ public AsyncWaiterInterfaceSpec(IntermediateModel model) {
3843
this.className = poetExtensions.getAsyncWaiterInterface();
3944
}
4045

46+
@Override
47+
protected ClassName waiterImplName() {
48+
return poetExtensions.getAsyncWaiterClass();
49+
}
50+
4151
@Override
4252
protected ClassName clientClassName() {
4353
return poetExtensions.getClientClass(model.getMetadata().getAsyncInterface());
@@ -56,4 +66,14 @@ protected ParameterizedTypeName getWaiterResponseType(OperationModel opModel) {
5666
return ParameterizedTypeName.get(ClassName.get(CompletableFuture.class),
5767
waiterResponse);
5868
}
69+
70+
@Override
71+
protected void additionalBuilderTypeSpecModification(TypeSpec.Builder type) {
72+
type.addMethod(MethodSpec.methodBuilder("executorService")
73+
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
74+
.addParameter(ClassName.get(ScheduledExecutorService.class), "executorService")
75+
.addJavadoc(WaiterDocs.waiterBuilderScheduledExecutorServiceJavadoc())
76+
.returns(className().nestedClass("Builder"))
77+
.build());
78+
}
5979
}

0 commit comments

Comments
 (0)