Skip to content

Commit b154ef3

Browse files
committed
Make WaitersRuntime a per-service private class
This keeps the runtime as a private implementation detail and no longer a backwards compat concern as it would be if left as an SdkProtectedApi.
1 parent e371de4 commit b154ef3

File tree

13 files changed

+142
-57
lines changed

13 files changed

+142
-57
lines changed

codegen/src/main/java/software/amazon/awssdk/codegen/emitters/GeneratorPathProvider.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,8 @@ public String getAuthorizerDirectory() {
6464
public String getWaitersDirectory() {
6565
return sourceDirectory + "/" + Utils.packageToDirectory(model.getMetadata().getFullWaitersPackageName());
6666
}
67+
68+
public String getWaitersInternalDirectory() {
69+
return sourceDirectory + "/" + Utils.packageToDirectory(model.getMetadata().getFullWaitersInternalPackageName());
70+
}
6771
}

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

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

1818
import java.util.ArrayList;
1919
import java.util.List;
20+
import software.amazon.awssdk.annotations.SdkInternalApi;
2021
import software.amazon.awssdk.codegen.emitters.GeneratorTask;
2122
import software.amazon.awssdk.codegen.emitters.GeneratorTaskParams;
2223
import software.amazon.awssdk.codegen.emitters.PoetGeneratorTask;
@@ -25,13 +26,13 @@
2526
import software.amazon.awssdk.codegen.poet.waiters.WaiterClassSpec;
2627
import software.amazon.awssdk.codegen.poet.waiters.WaiterInterfaceSpec;
2728

29+
@SdkInternalApi
2830
public class WaitersGeneratorTasks extends BaseGeneratorTasks {
29-
30-
private final String waitersClassDir;
31+
private final GeneratorTaskParams generatorTaskParams;
3132

3233
public WaitersGeneratorTasks(GeneratorTaskParams dependencies) {
3334
super(dependencies);
34-
this.waitersClassDir = dependencies.getPathProvider().getWaitersDirectory();
35+
this.generatorTaskParams = dependencies;
3536
}
3637

3738
@Override
@@ -44,24 +45,29 @@ protected List<GeneratorTask> createTasks() {
4445
List<GeneratorTask> generatorTasks = new ArrayList<>();
4546
generatorTasks.addAll(createSyncTasks());
4647
generatorTasks.addAll(createAsyncTasks());
48+
generatorTasks.add(new WaitersRuntimeGeneratorTask(generatorTaskParams));
4749
return generatorTasks;
4850
}
4951

5052
private List<GeneratorTask> createSyncTasks() {
5153
List<GeneratorTask> syncTasks = new ArrayList<>();
52-
syncTasks.add(new PoetGeneratorTask(waitersClassDir, model.getFileHeader(),
54+
syncTasks.add(new PoetGeneratorTask(waitersClassDir(), model.getFileHeader(),
5355
new WaiterInterfaceSpec(model)));
54-
syncTasks.add(new PoetGeneratorTask(waitersClassDir, model.getFileHeader(),
56+
syncTasks.add(new PoetGeneratorTask(waitersClassDir(), model.getFileHeader(),
5557
new WaiterClassSpec(model)));
5658
return syncTasks;
5759
}
5860

5961
private List<GeneratorTask> createAsyncTasks() {
6062
List<GeneratorTask> asyncTasks = new ArrayList<>();
61-
asyncTasks.add(new PoetGeneratorTask(waitersClassDir, model.getFileHeader(),
63+
asyncTasks.add(new PoetGeneratorTask(waitersClassDir(), model.getFileHeader(),
6264
new AsyncWaiterInterfaceSpec(model)));
63-
asyncTasks.add(new PoetGeneratorTask(waitersClassDir, model.getFileHeader(),
65+
asyncTasks.add(new PoetGeneratorTask(waitersClassDir(), model.getFileHeader(),
6466
new AsyncWaiterClassSpec(model)));
6567
return asyncTasks;
6668
}
69+
70+
private String waitersClassDir() {
71+
return generatorTaskParams.getPathProvider().getWaitersDirectory();
72+
}
6773
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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.emitters.tasks;
17+
18+
import java.io.IOException;
19+
import java.io.InputStream;
20+
import java.io.UncheckedIOException;
21+
import java.util.Collections;
22+
import java.util.List;
23+
import software.amazon.awssdk.codegen.emitters.GeneratorTask;
24+
import software.amazon.awssdk.codegen.emitters.GeneratorTaskParams;
25+
import software.amazon.awssdk.codegen.emitters.SimpleGeneratorTask;
26+
import software.amazon.awssdk.utils.IoUtils;
27+
28+
public final class WaitersRuntimeGeneratorTask extends BaseGeneratorTasks {
29+
public static final String RUNTIME_CLASS_NAME = "WaitersRuntime";
30+
31+
private final String waitersInternalClassDir;
32+
private final String waitersInternalPackageName;
33+
private final String fileHeader;
34+
private final String runtimeClassCode;
35+
36+
public WaitersRuntimeGeneratorTask(GeneratorTaskParams generatorTaskParams) {
37+
super(generatorTaskParams);
38+
this.waitersInternalClassDir = generatorTaskParams.getPathProvider().getWaitersInternalDirectory();
39+
this.waitersInternalPackageName = generatorTaskParams.getModel().getMetadata().getFullWaitersInternalPackageName();
40+
this.fileHeader = generatorTaskParams.getModel().getFileHeader();
41+
this.runtimeClassCode = loadWaitersRuntimeCode();
42+
}
43+
44+
@Override
45+
protected List<GeneratorTask> createTasks() throws Exception {
46+
String codeContents = "" +
47+
"package " + waitersInternalPackageName + ";\n" +
48+
"\n"
49+
+ runtimeClassCode;
50+
51+
String fileName = RUNTIME_CLASS_NAME + ".java";
52+
return Collections.singletonList(new SimpleGeneratorTask(waitersInternalClassDir, fileName, fileHeader,
53+
codeContents));
54+
}
55+
56+
private static String loadWaitersRuntimeCode() {
57+
try {
58+
InputStream is = WaitersRuntimeGeneratorTask.class.getResourceAsStream(
59+
"/software/amazon/awssdk/codegen/waiters/WaitersRuntime.java");
60+
return IoUtils.toUtf8String(is);
61+
} catch (IOException ioe) {
62+
throw new UncheckedIOException(ioe);
63+
}
64+
}
65+
}

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
@@ -681,4 +681,8 @@ public Metadata withWaitersPackageName(String waitersPackageName) {
681681
public String getFullWaitersPackageName() {
682682
return joinPackageNames(rootPackageName, getWaitersPackageName());
683683
}
684+
685+
public String getFullWaitersInternalPackageName() {
686+
return joinPackageNames(getFullWaitersPackageName(), "internal");
687+
}
684688
}

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

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import software.amazon.awssdk.annotations.SdkInternalApi;
4444
import software.amazon.awssdk.annotations.ThreadSafe;
4545
import software.amazon.awssdk.awscore.exception.AwsServiceException;
46+
import software.amazon.awssdk.codegen.emitters.tasks.WaitersRuntimeGeneratorTask;
4647
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
4748
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
4849
import software.amazon.awssdk.codegen.model.service.Acceptor;
@@ -54,25 +55,25 @@
5455
import software.amazon.awssdk.core.waiters.PollingStrategy;
5556
import software.amazon.awssdk.core.waiters.WaiterAcceptor;
5657
import software.amazon.awssdk.core.waiters.WaiterState;
57-
import software.amazon.awssdk.core.waiters.WaitersRuntime;
5858
import software.amazon.awssdk.utils.AttributeMap;
5959
import software.amazon.awssdk.utils.SdkAutoCloseable;
6060

6161
/**
6262
* Base class containing common logic shared between the sync waiter class and the async waiter class
6363
*/
6464
public abstract class BaseWaiterClassSpec implements ClassSpec {
65-
6665
private final IntermediateModel model;
6766
private final String modelPackage;
6867
private final Map<String, WaiterDefinition> waiters;
6968
private final ClassName waiterClassName;
69+
private final JmesPathAcceptorGenerator jmesPathAcceptorGenerator;
7070

7171
public BaseWaiterClassSpec(IntermediateModel model, ClassName waiterClassName) {
7272
this.model = model;
7373
this.modelPackage = model.getMetadata().getFullModelPackageName();
7474
this.waiters = model.getWaiters();
7575
this.waiterClassName = waiterClassName;
76+
this.jmesPathAcceptorGenerator = new JmesPathAcceptorGenerator(waitersRuntimeClass());
7677
}
7778

7879
@Override
@@ -305,7 +306,7 @@ private MethodSpec acceptorInitializer(String waiterKey, WaiterDefinition waiter
305306
.addCode(");");
306307
}
307308

308-
acceptorsMethod.addStatement("result.addAll($T.DEFAULT_ACCEPTORS)", WaitersRuntime.class);
309+
acceptorsMethod.addStatement("result.addAll($T.DEFAULT_ACCEPTORS)", waitersRuntimeClass());
309310

310311
acceptorsMethod.addStatement("return result");
311312

@@ -378,8 +379,8 @@ private CodeBlock acceptor(Acceptor acceptor) {
378379
case "status":
379380
// Note: Ignores the result we've built so far because this uses a special acceptor implementation.
380381
int expected = Integer.parseInt(acceptor.getExpected().asText());
381-
return CodeBlock.of("new $T($L, $T.$L)", WaitersRuntime.ResponseStatusAcceptor.class, expected,
382-
WaiterState.class, waiterState(acceptor));
382+
return CodeBlock.of("new $T($L, $T.$L)", waitersRuntimeClass().nestedClass("ResponseStatusAcceptor"),
383+
expected, WaiterState.class, waiterState(acceptor));
383384
case "error":
384385
result.add("OnExceptionAcceptor(");
385386
result.add(errorAcceptorBody(acceptor));
@@ -410,9 +411,9 @@ private CodeBlock pathAcceptorBody(Acceptor acceptor) {
410411
String expectedType = acceptor.getExpected() instanceof JrsString ? "$S" : "$L";
411412
return CodeBlock.builder()
412413
.add("response -> {")
413-
.add("$1T input = new $1T(response);", WaitersRuntime.Value.class)
414+
.add("$1T input = new $1T(response);", waitersRuntimeClass().nestedClass("Value"))
414415
.add("return $T.equals(", Objects.class)
415-
.add(JmesPathAcceptorGenerator.interpret(acceptor.getArgument(), "input"))
416+
.add(jmesPathAcceptorGenerator.interpret(acceptor.getArgument(), "input"))
416417
.add(".value(), " + expectedType + ");", expected)
417418
.add("}")
418419
.build();
@@ -423,9 +424,9 @@ private CodeBlock pathAllAcceptorBody(Acceptor acceptor) {
423424
String expectedType = acceptor.getExpected() instanceof JrsString ? "$S" : "$L";
424425
return CodeBlock.builder()
425426
.add("response -> {")
426-
.add("$1T input = new $1T(response);", WaitersRuntime.Value.class)
427+
.add("$1T input = new $1T(response);", waitersRuntimeClass().nestedClass("Value"))
427428
.add("$T<$T> resultValues = ", List.class, Object.class)
428-
.add(JmesPathAcceptorGenerator.interpret(acceptor.getArgument(), "input"))
429+
.add(jmesPathAcceptorGenerator.interpret(acceptor.getArgument(), "input"))
429430
.add(".values();")
430431
.add("return !resultValues.isEmpty() && "
431432
+ "resultValues.stream().allMatch(v -> $T.equals(v, " + expectedType + "));",
@@ -439,9 +440,9 @@ private CodeBlock pathAnyAcceptorBody(Acceptor acceptor) {
439440
String expectedType = acceptor.getExpected() instanceof JrsString ? "$S" : "$L";
440441
return CodeBlock.builder()
441442
.add("response -> {")
442-
.add("$1T input = new $1T(response);", WaitersRuntime.Value.class)
443+
.add("$1T input = new $1T(response);", waitersRuntimeClass().nestedClass("Value"))
443444
.add("$T<$T> resultValues = ", List.class, Object.class)
444-
.add(JmesPathAcceptorGenerator.interpret(acceptor.getArgument(), "input"))
445+
.add(jmesPathAcceptorGenerator.interpret(acceptor.getArgument(), "input"))
445446
.add(".values();")
446447
.add("return !resultValues.isEmpty() && "
447448
+ "resultValues.stream().anyMatch(v -> $T.equals(v, " + expectedType + "));",
@@ -467,4 +468,9 @@ private MethodSpec staticErrorCodeMethod() {
467468
.addCode("return null;")
468469
.build();
469470
}
471+
472+
private ClassName waitersRuntimeClass() {
473+
return ClassName.get(model.getMetadata().getFullWaitersInternalPackageName(),
474+
WaitersRuntimeGeneratorTask.RUNTIME_CLASS_NAME);
475+
}
470476
}

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

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

1818
import com.fasterxml.jackson.jr.stree.JrsBoolean;
1919
import com.fasterxml.jackson.jr.stree.JrsValue;
20+
import com.squareup.javapoet.ClassName;
2021
import com.squareup.javapoet.CodeBlock;
2122
import java.util.ArrayDeque;
2223
import java.util.Deque;
@@ -47,7 +48,6 @@
4748
import software.amazon.awssdk.codegen.jmespath.parser.JmesPathParser;
4849
import software.amazon.awssdk.codegen.jmespath.parser.JmesPathVisitor;
4950
import software.amazon.awssdk.core.SdkPojo;
50-
import software.amazon.awssdk.core.waiters.WaitersRuntime;
5151
import software.amazon.awssdk.utils.Validate;
5252

5353
/**
@@ -57,14 +57,17 @@
5757
* this interpreter make heavy use of the {@link WaitersRuntime}.
5858
*/
5959
public class JmesPathAcceptorGenerator {
60-
private JmesPathAcceptorGenerator() {
60+
private final ClassName waitersRuntimeClass;
61+
62+
public JmesPathAcceptorGenerator(ClassName waitersRuntimeClass) {
63+
this.waitersRuntimeClass = waitersRuntimeClass;
6164
}
6265

6366
/**
6467
* Interpret the provided expression into a java statement that executes against the provided input value. This inputValue
6568
* should be a JMESPath Value in scope.
6669
*/
67-
public static CodeBlock interpret(String expression, String inputValue) {
70+
public CodeBlock interpret(String expression, String inputValue) {
6871
CodeBlock.Builder codeBlock = CodeBlock.builder();
6972
Visitor visitor = new Visitor(codeBlock, inputValue);
7073
JmesPathParser.parse(expression).visit(visitor);
@@ -74,7 +77,7 @@ public static CodeBlock interpret(String expression, String inputValue) {
7477
/**
7578
* An implementation of {@link JmesPathVisitor} used by {@link #interpret(String, String)}.
7679
*/
77-
private static class Visitor implements JmesPathVisitor {
80+
private class Visitor implements JmesPathVisitor {
7881
private final CodeBlock.Builder codeBlock;
7982
private final Deque<String> variables = new ArrayDeque<>();
8083
private int variableIndex = 0;
@@ -278,7 +281,7 @@ public void visitIdentifier(String input) {
278281

279282
@Override
280283
public void visitNumber(int input) {
281-
codeBlock.add(".constant($L)", WaitersRuntime.Value.class, input);
284+
codeBlock.add(".constant($L)", waitersRuntimeClass.nestedClass("Value"), input);
282285
}
283286

284287
/**

core/sdk-core/src/main/java/software/amazon/awssdk/core/waiters/WaitersRuntime.java renamed to codegen/src/main/resources/software/amazon/awssdk/codegen/waiters/WaitersRuntime.java

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,3 @@
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.core.waiters;
17-
181
import static java.util.stream.Collectors.toList;
192

203
import java.util.ArrayList;
@@ -24,17 +7,22 @@
247
import java.util.List;
258
import java.util.Objects;
269
import java.util.function.Function;
27-
import software.amazon.awssdk.annotations.SdkProtectedApi;
10+
import software.amazon.awssdk.annotations.Generated;
11+
import software.amazon.awssdk.annotations.SdkInternalApi;
2812
import software.amazon.awssdk.core.SdkPojo;
2913
import software.amazon.awssdk.core.SdkResponse;
3014
import software.amazon.awssdk.core.exception.SdkClientException;
3115
import software.amazon.awssdk.core.exception.SdkServiceException;
16+
import software.amazon.awssdk.core.waiters.WaiterAcceptor;
17+
import software.amazon.awssdk.core.waiters.WaiterState;
3218
import software.amazon.awssdk.utils.ToString;
3319

3420
/**
35-
* Contains classes used at runtime by the code generator classes for waiter acceptors generated from JMESPath expressions.
21+
* Contains classes used at runtime by the code generator classes for waiter acceptors generated from JMESPath
22+
* expressions.
3623
*/
37-
@SdkProtectedApi
24+
@Generated("software.amazon.awssdk:codegen")
25+
@SdkInternalApi
3826
public final class WaitersRuntime {
3927
/**
4028
* The default acceptors that should be matched *last* in the list of acceptors used by the SDK client waiters.
@@ -526,4 +514,4 @@ public boolean matches(Throwable throwable) {
526514
return false;
527515
}
528516
}
529-
}
517+
}

codegen/src/test/java/software/amazon/awssdk/codegen/poet/waiters/JmesPathAcceptorGeneratorTest.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,18 @@
1818

1919
import static org.assertj.core.api.Assertions.assertThat;
2020

21+
import com.squareup.javapoet.ClassName;
22+
import org.junit.Before;
2123
import org.junit.Test;
22-
import software.amazon.awssdk.codegen.jmespath.component.Comparator;
23-
import software.amazon.awssdk.codegen.jmespath.component.Expression;
24-
import software.amazon.awssdk.codegen.jmespath.parser.JmesPathParser;
2524

2625
public class JmesPathAcceptorGeneratorTest {
26+
private JmesPathAcceptorGenerator acceptorGenerator;
27+
28+
@Before
29+
public void setup() {
30+
acceptorGenerator = new JmesPathAcceptorGenerator(ClassName.get("software.amazon.awssdk.codegen", "WaitersRuntime"));
31+
}
32+
2733
@Test
2834
public void testAutoScalingComplexExpression() {
2935
testConversion("contains(AutoScalingGroups[].[length(Instances[?LifecycleState=='InService']) >= MinSize][], `false`)",
@@ -294,8 +300,8 @@ public void testNegativeNumber() {
294300
testConversion("foo[-10]", "input.field(\"foo\").index(-10)");
295301
}
296302

297-
private static void testConversion(String jmesPathString, String expectedCode) {
298-
assertThat(JmesPathAcceptorGenerator.interpret(jmesPathString, "input").toString()).isEqualTo((expectedCode));
303+
private void testConversion(String jmesPathString, String expectedCode) {
304+
assertThat(acceptorGenerator.interpret(jmesPathString, "input").toString()).isEqualTo((expectedCode));
299305
}
300306

301307
}

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/waiters/query-async-waiter-class.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
import software.amazon.awssdk.core.waiters.WaiterAcceptor;
1919
import software.amazon.awssdk.core.waiters.WaiterResponse;
2020
import software.amazon.awssdk.core.waiters.WaiterState;
21-
import software.amazon.awssdk.core.waiters.WaitersRuntime;
2221
import software.amazon.awssdk.services.query.QueryAsyncClient;
2322
import software.amazon.awssdk.services.query.model.APostOperationRequest;
2423
import software.amazon.awssdk.services.query.model.APostOperationResponse;
24+
import software.amazon.awssdk.services.query.waiters.internal.WaitersRuntime;
2525
import software.amazon.awssdk.utils.AttributeMap;
2626
import software.amazon.awssdk.utils.SdkAutoCloseable;
2727
import software.amazon.awssdk.utils.ThreadFactoryBuilder;

0 commit comments

Comments
 (0)