Skip to content

Commit 249134c

Browse files
committed
Codegen decorator
1 parent 448c1e5 commit 249134c

File tree

17 files changed

+880
-854
lines changed

17 files changed

+880
-854
lines changed

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515

1616
package software.amazon.awssdk.codegen.docs;
1717

18+
import static software.amazon.awssdk.codegen.poet.PoetExtensions.ASYNC_STREAMING_INPUT_PARAM;
19+
import static software.amazon.awssdk.codegen.poet.PoetExtensions.ASYNC_STREAMING_OUTPUT_PARAM;
20+
1821
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
1922
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
2023

@@ -66,10 +69,10 @@ protected void applyReturns(DocumentationBuilder docBuilder) {
6669
protected void applyParams(DocumentationBuilder docBuilder) {
6770
emitRequestParm(docBuilder);
6871
if (opModel.hasStreamingInput()) {
69-
docBuilder.param("requestBody", REQUEST_BODY_DOCS + getStreamingInputDocs());
72+
docBuilder.param(ASYNC_STREAMING_INPUT_PARAM, REQUEST_BODY_DOCS + getStreamingInputDocs());
7073
}
7174
if (opModel.hasStreamingOutput()) {
72-
docBuilder.param("asyncResponseTransformer", STREAM_RESPONSE_TRANSFORMER_DOCS + getStreamingOutputDocs());
75+
docBuilder.param(ASYNC_STREAMING_OUTPUT_PARAM, STREAM_RESPONSE_TRANSFORMER_DOCS + getStreamingOutputDocs());
7376
}
7477
}
7578

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import static software.amazon.awssdk.codegen.internal.Constant.SYNC_CLIENT_DESTINATION_PATH_PARAM_NAME;
1919
import static software.amazon.awssdk.codegen.internal.Constant.SYNC_CLIENT_SOURCE_PATH_PARAM_NAME;
20+
import static software.amazon.awssdk.codegen.poet.PoetExtensions.SYNC_STREAMING_INPUT_PARAM;
21+
import static software.amazon.awssdk.codegen.poet.PoetExtensions.SYNC_STREAMING_OUTPUT_PARAM;
2022

2123
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
2224
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
@@ -76,11 +78,11 @@ protected void applyReturns(DocumentationBuilder docBuilder) {
7678
protected void applyParams(DocumentationBuilder docBuilder) {
7779
emitRequestParm(docBuilder);
7880
if (opModel.hasStreamingInput()) {
79-
docBuilder.param("requestBody", REQUEST_BODY_DOCS + getStreamingInputDocs());
81+
docBuilder.param(SYNC_STREAMING_INPUT_PARAM, REQUEST_BODY_DOCS + getStreamingInputDocs());
8082

8183
}
8284
if (opModel.hasStreamingOutput()) {
83-
docBuilder.param("responseTransformer", STREAM_RESPONSE_HANDLER_DOCS + getStreamingOutputDocs(),
85+
docBuilder.param(SYNC_STREAMING_OUTPUT_PARAM, STREAM_RESPONSE_HANDLER_DOCS + getStreamingOutputDocs(),
8486
opModel.getOutputShape().getShapeName(), getStreamingOutputDocs());
8587
}
8688
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import software.amazon.awssdk.codegen.poet.builder.AsyncClientBuilderClass;
2424
import software.amazon.awssdk.codegen.poet.builder.AsyncClientBuilderInterface;
2525
import software.amazon.awssdk.codegen.poet.client.AsyncClientClass;
26+
import software.amazon.awssdk.codegen.poet.client.AbstractAsyncClientDecoratorClass;
2627
import software.amazon.awssdk.codegen.poet.client.AsyncClientInterface;
2728
import software.amazon.awssdk.codegen.poet.endpointdiscovery.EndpointDiscoveryAsyncCacheLoaderGenerator;
2829

@@ -46,13 +47,21 @@ protected List<GeneratorTask> createTasks() throws Exception {
4647
generatorTasks.add(createEndpointDiscoveryCacheLoaderTask());
4748
}
4849

50+
if (model.getCustomizationConfig().isAsyncClientDecoratorClass()) {
51+
generatorTasks.add(createDecoratorClientClassTask());
52+
}
53+
4954
return generatorTasks;
5055
}
5156

5257
private GeneratorTask createClientClassTask() throws IOException {
5358
return createPoetGeneratorTask(new AsyncClientClass(generatorTaskParams));
5459
}
5560

61+
private GeneratorTask createDecoratorClientClassTask() throws IOException {
62+
return createPoetGeneratorTask(new AbstractAsyncClientDecoratorClass(model));
63+
}
64+
5665
private GeneratorTask createClientBuilderTask() throws IOException {
5766
return createPoetGeneratorTask(new AsyncClientBuilderClass(model));
5867
}

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,10 @@ public class CustomizationConfig {
196196

197197
private RetryMode defaultRetryMode;
198198

199-
199+
/**
200+
* Whether to generate an abstract decorator class that delegates to the async service client
201+
*/
202+
private boolean asyncClientDecoratorClass;
200203

201204
private CustomizationConfig() {
202205
}
@@ -502,4 +505,12 @@ public ServiceConfig getServiceConfig() {
502505
public void setServiceConfig(ServiceConfig serviceConfig) {
503506
this.serviceConfig = serviceConfig;
504507
}
508+
509+
public boolean isAsyncClientDecoratorClass() {
510+
return asyncClientDecoratorClass;
511+
}
512+
513+
public void setAsyncClientDecoratorClass(boolean asyncClientDecoratorClass) {
514+
this.asyncClientDecoratorClass = asyncClientDecoratorClass;
515+
}
505516
}

codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/Metadata.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,4 +678,8 @@ public String getFullWaitersPackageName() {
678678
public String getFullWaitersInternalPackageName() {
679679
return joinPackageNames(getFullWaitersPackageName(), "internal");
680680
}
681+
682+
public String getFullInternalPackageName() {
683+
return joinPackageNames(getFullClientPackageName(), "internal");
684+
}
681685
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@
2727
*/
2828
public class PoetExtensions {
2929

30+
public static final String ASYNC_STREAMING_INPUT_PARAM = "requestBody";
31+
public static final String ASYNC_STREAMING_OUTPUT_PARAM = "asyncResponseTransformer";
32+
public static final String SYNC_STREAMING_INPUT_PARAM = "requestBody";
33+
public static final String SYNC_STREAMING_OUTPUT_PARAM = "responseTransformer";
34+
public static final String EVENT_PUBLISHER_PARAM_NAME = "requestStream";
35+
public static final String EVENT_RESPONSE_HANDLER_PARAM_NAME = "asyncResponseHandler";
36+
3037
private final IntermediateModel model;
3138

3239
public PoetExtensions(IntermediateModel model) {
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
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.client;
17+
18+
import static software.amazon.awssdk.codegen.poet.PoetExtensions.ASYNC_STREAMING_INPUT_PARAM;
19+
import static software.amazon.awssdk.codegen.poet.PoetExtensions.ASYNC_STREAMING_OUTPUT_PARAM;
20+
import static software.amazon.awssdk.codegen.poet.PoetExtensions.EVENT_PUBLISHER_PARAM_NAME;
21+
import static software.amazon.awssdk.codegen.poet.PoetExtensions.EVENT_RESPONSE_HANDLER_PARAM_NAME;
22+
23+
import com.squareup.javapoet.ClassName;
24+
import com.squareup.javapoet.FieldSpec;
25+
import com.squareup.javapoet.MethodSpec;
26+
import com.squareup.javapoet.TypeSpec;
27+
import javax.lang.model.element.Modifier;
28+
import software.amazon.awssdk.annotations.SdkInternalApi;
29+
import software.amazon.awssdk.codegen.model.config.customization.UtilitiesMethod;
30+
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
31+
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
32+
import software.amazon.awssdk.codegen.poet.PoetExtensions;
33+
import software.amazon.awssdk.codegen.poet.PoetUtils;
34+
import software.amazon.awssdk.codegen.utils.PaginatorUtils;
35+
36+
public class AbstractAsyncClientDecoratorClass extends AsyncClientInterface{
37+
38+
private final IntermediateModel model;
39+
private final ClassName className;
40+
private final String clientPackageName;
41+
private final PoetExtensions poetExtensions;
42+
43+
public AbstractAsyncClientDecoratorClass(IntermediateModel model) {
44+
super(model);
45+
this.clientPackageName = model.getMetadata().getFullInternalPackageName();
46+
this.model = model;
47+
this.className = ClassName.get(model.getMetadata().getFullInternalPackageName(),
48+
"Abstract" + model.getMetadata().getAsyncInterface());
49+
this.poetExtensions = new PoetExtensions(model);
50+
}
51+
52+
@Override
53+
public TypeSpec poetSpec() {
54+
ClassName interfaceClass = poetExtensions.getClientClass(model.getMetadata().getAsyncInterface());
55+
TypeSpec.Builder result = PoetUtils.createClassBuilder(className);
56+
57+
result.addSuperinterface(interfaceClass)
58+
.addAnnotation(SdkInternalApi.class)
59+
.addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
60+
.addField(FieldSpec.builder(interfaceClass, "delegate")
61+
.addModifiers(Modifier.PRIVATE, Modifier.FINAL)
62+
.build())
63+
.addMethods(operations())
64+
.addMethod(closeMethod());
65+
66+
result.addMethod(constructor(interfaceClass));
67+
68+
if (model.getCustomizationConfig().getUtilitiesMethod() != null) {
69+
result.addMethod(utilitiesMethod());
70+
}
71+
72+
if (model.hasWaiters()) {
73+
result.addMethod(waiterMethod());
74+
}
75+
76+
return result.build();
77+
}
78+
79+
private MethodSpec constructor(ClassName interfaceClass) {
80+
return MethodSpec.constructorBuilder()
81+
.addModifiers(Modifier.PUBLIC)
82+
.addParameter(interfaceClass, "delegate")
83+
.addStatement("this.delegate = delegate")
84+
.build();
85+
}
86+
87+
@Override
88+
public ClassName className() {
89+
return className;
90+
}
91+
92+
@Override
93+
protected MethodSpec.Builder operationBody(MethodSpec.Builder builder, OperationModel opModel) {
94+
95+
if (opModel.hasStreamingInput() || opModel.hasStreamingOutput()) {
96+
String variableName = opModel.hasStreamingInput() ? ASYNC_STREAMING_INPUT_PARAM : ASYNC_STREAMING_OUTPUT_PARAM;
97+
return builder.addModifiers(Modifier.PUBLIC)
98+
.addAnnotation(Override.class)
99+
.addStatement("return delegate.$N($N, $N)",
100+
opModel.getMethodName(),
101+
opModel.getInput().getVariableName(),
102+
variableName);
103+
}
104+
105+
if (opModel.hasEventStreamInput() && opModel.hasEventStreamOutput()) {
106+
return builder.addModifiers(Modifier.PUBLIC)
107+
.addAnnotation(Override.class)
108+
.addStatement("return delegate.$N($N, $N, $N)",
109+
opModel.getMethodName(),
110+
opModel.getInput().getVariableName(),
111+
EVENT_PUBLISHER_PARAM_NAME,
112+
ASYNC_STREAMING_OUTPUT_PARAM);
113+
}
114+
115+
116+
if (opModel.hasEventStreamInput() || opModel.hasEventStreamOutput()) {
117+
String variableName = opModel.hasEventStreamInput() ? EVENT_PUBLISHER_PARAM_NAME : EVENT_RESPONSE_HANDLER_PARAM_NAME;
118+
return builder.addModifiers(Modifier.PUBLIC)
119+
.addAnnotation(Override.class)
120+
.addStatement("return delegate.$N($N, $N)",
121+
opModel.getMethodName(),
122+
opModel.getInput().getVariableName(),
123+
variableName);
124+
}
125+
126+
return builder.addModifiers(Modifier.PUBLIC)
127+
.addAnnotation(Override.class)
128+
.addStatement("return delegate.$N($N)",
129+
opModel.getMethodName(),
130+
opModel.getInput().getVariableName());
131+
}
132+
133+
@Override
134+
protected MethodSpec.Builder paginatedMethodBody(MethodSpec.Builder builder, OperationModel opModel) {
135+
String methodName = PaginatorUtils.getPaginatedMethodName(opModel.getMethodName());
136+
return builder.addModifiers(Modifier.PUBLIC)
137+
.addAnnotation(Override.class)
138+
.addStatement("return delegate.$N($N)", methodName, opModel.getInput().getVariableName());
139+
}
140+
141+
142+
@Override
143+
protected MethodSpec.Builder utilitiesOperationBody(MethodSpec.Builder builder) {
144+
return builder.addAnnotation(Override.class).addStatement("return delegate.$N()", UtilitiesMethod.METHOD_NAME);
145+
}
146+
147+
@Override
148+
protected MethodSpec.Builder waiterOperationBody(MethodSpec.Builder builder) {
149+
return builder.addAnnotation(Override.class).addStatement("return delegate.waiter()");
150+
}
151+
152+
private MethodSpec closeMethod() {
153+
return MethodSpec.methodBuilder("close")
154+
.addAnnotation(Override.class)
155+
.addModifiers(Modifier.PUBLIC)
156+
.addStatement("delegate.close()")
157+
.build();
158+
}
159+
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static javax.lang.model.element.Modifier.FINAL;
2121
import static javax.lang.model.element.Modifier.PRIVATE;
2222
import static javax.lang.model.element.Modifier.STATIC;
23+
import static software.amazon.awssdk.codegen.poet.PoetExtensions.EVENT_PUBLISHER_PARAM_NAME;
2324
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.addS3ArnableFieldCode;
2425
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.applyPaginatorUserAgentMethod;
2526
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.applySignerOverrideMethod;
@@ -420,7 +421,8 @@ private TypeName eventStreamType(ShapeModel shapeModel) {
420421
return poetExtensions.getModelClass(shapeModel.getShapeName());
421422
}
422423

423-
private MethodSpec utilitiesMethod() {
424+
@Override
425+
protected MethodSpec utilitiesMethod() {
424426
UtilitiesMethod config = model.getCustomizationConfig().getUtilitiesMethod();
425427
ClassName returnType = PoetUtils.classNameFromFqcn(config.getReturnType());
426428
String instanceClass = config.getInstanceType();

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

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
package software.amazon.awssdk.codegen.poet.client;
1717

1818
import static java.util.stream.Collectors.toList;
19+
import static software.amazon.awssdk.codegen.poet.PoetExtensions.ASYNC_STREAMING_INPUT_PARAM;
20+
import static software.amazon.awssdk.codegen.poet.PoetExtensions.EVENT_PUBLISHER_PARAM_NAME;
21+
import static software.amazon.awssdk.codegen.poet.PoetExtensions.EVENT_RESPONSE_HANDLER_PARAM_NAME;
1922

2023
import com.squareup.javapoet.ClassName;
2124
import com.squareup.javapoet.FieldSpec;
@@ -57,7 +60,6 @@
5760
public class AsyncClientInterface implements ClassSpec {
5861

5962
public static final TypeVariableName STREAMING_TYPE_VARIABLE = TypeVariableName.get("ReturnT");
60-
protected static final String EVENT_PUBLISHER_PARAM_NAME = "requestStream";
6163

6264
protected final IntermediateModel model;
6365
protected final ClassName className;
@@ -304,7 +306,7 @@ private MethodSpec traditionalMethod(OperationModel opModel) {
304306
.addJavadoc(opModel.getDocs(model, ClientType.ASYNC));
305307

306308
if (opModel.hasStreamingInput()) {
307-
builder.addParameter(ClassName.get(AsyncRequestBody.class), "requestBody");
309+
builder.addParameter(ClassName.get(AsyncRequestBody.class), ASYNC_STREAMING_INPUT_PARAM);
308310
} else if (opModel.hasEventStreamInput()) {
309311
String eventStreamShapeName = EventStreamUtils.getEventStreamInRequest(opModel.getInputShape())
310312
.getShapeName();
@@ -319,7 +321,7 @@ private MethodSpec traditionalMethod(OperationModel opModel) {
319321
.get(ClassName.get(AsyncResponseTransformer.class), responsePojoType, STREAMING_TYPE_VARIABLE);
320322
builder.addParameter(asyncResponseHandlerType, "asyncResponseTransformer");
321323
} else if (opModel.hasEventStreamOutput()) {
322-
builder.addParameter(poetExtensions.eventStreamResponseHandlerType(opModel), "asyncResponseHandler");
324+
builder.addParameter(poetExtensions.eventStreamResponseHandlerType(opModel), EVENT_RESPONSE_HANDLER_PARAM_NAME);
323325
}
324326
return operationBody(builder, opModel).build();
325327
}
@@ -448,26 +450,33 @@ private String consumerBuilderJavadoc(OperationModel opModel, SimpleMethodOverlo
448450
return opModel.getDocs(model, ClientType.ASYNC, overload, new DocConfiguration().isConsumerBuilder(true));
449451
}
450452

451-
private MethodSpec utilitiesMethod() {
453+
protected MethodSpec utilitiesMethod() {
452454
UtilitiesMethod config = model.getCustomizationConfig().getUtilitiesMethod();
453455
ClassName returnType = PoetUtils.classNameFromFqcn(config.getReturnType());
454456

455-
return MethodSpec.methodBuilder(UtilitiesMethod.METHOD_NAME)
456-
.returns(returnType)
457-
.addModifiers(Modifier.PUBLIC)
458-
.addModifiers(Modifier.DEFAULT)
459-
.addStatement("throw new $T()", UnsupportedOperationException.class)
460-
.addJavadoc("Creates an instance of {@link $T} object with the "
461-
+ "configuration set on this client.", returnType)
462-
.build();
457+
MethodSpec.Builder builder = MethodSpec.methodBuilder(UtilitiesMethod.METHOD_NAME)
458+
.returns(returnType)
459+
.addModifiers(Modifier.PUBLIC)
460+
.addJavadoc("Creates an instance of {@link $T} object with the "
461+
+ "configuration set on this client.", returnType);
462+
return utilitiesOperationBody(builder).build();
463463
}
464464

465-
private MethodSpec waiterMethod() {
466-
return MethodSpec.methodBuilder("waiter")
467-
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
468-
.returns(poetExtensions.getAsyncWaiterInterface())
469-
.addStatement("throw new $T()", UnsupportedOperationException.class)
470-
.addJavadoc(WaiterDocs.waiterMethodInClient(poetExtensions.getAsyncWaiterInterface()))
471-
.build();
465+
protected MethodSpec.Builder utilitiesOperationBody(MethodSpec.Builder builder) {
466+
return builder.addModifiers(Modifier.DEFAULT).addStatement("throw new $T()", UnsupportedOperationException.class);
467+
}
468+
469+
protected MethodSpec waiterMethod() {
470+
MethodSpec.Builder builder = MethodSpec.methodBuilder("waiter")
471+
.addModifiers(Modifier.PUBLIC)
472+
.returns(poetExtensions.getAsyncWaiterInterface())
473+
.addJavadoc(WaiterDocs.waiterMethodInClient(poetExtensions.getAsyncWaiterInterface()));
474+
475+
return waiterOperationBody(builder).build();
476+
}
477+
478+
protected MethodSpec.Builder waiterOperationBody(MethodSpec.Builder builder) {
479+
return builder.addModifiers(Modifier.DEFAULT, Modifier.PUBLIC)
480+
.addStatement("throw new $T()", UnsupportedOperationException.class);
472481
}
473482
}

0 commit comments

Comments
 (0)