Skip to content

Commit 43b1f1b

Browse files
authored
Include partitions.json data statically in provider (#3637)
Include the raw partitions.json data as a string within DefaultPartitionDataProvider so it doesn't need to be loaded at runtime as a classpath resource.
1 parent be9bd3f commit 43b1f1b

File tree

8 files changed

+227
-56
lines changed

8 files changed

+227
-56
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "bugfix",
3+
"category": "AWS SDK for Java v2",
4+
"contributor": "",
5+
"description": "Include the raw `partitions.json` data as a string within `DefaultPartitionDataProvider` so it doesn't need to be loaded at runtime as a classpath resource."
6+
}

codegen/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@
127127
<artifactId>ruleset-testing-core</artifactId>
128128
<version>${awsjavasdk.version}</version>
129129
</dependency>
130+
<dependency>
131+
<groupId>software.amazon.awssdk</groupId>
132+
<artifactId>json-utils</artifactId>
133+
<version>${awsjavasdk.version}</version>
134+
</dependency>
130135

131136
<dependency>
132137
<artifactId>org.eclipse.jdt.core</artifactId>

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig;
2727
import software.amazon.awssdk.codegen.model.service.ClientContextParam;
2828
import software.amazon.awssdk.codegen.poet.rules.ClientContextParamsClassSpec;
29+
import software.amazon.awssdk.codegen.poet.rules.DefaultPartitionDataProviderSpec;
2930
import software.amazon.awssdk.codegen.poet.rules.EndpointAuthSchemeInterceptorClassSpec;
3031
import software.amazon.awssdk.codegen.poet.rules.EndpointParametersClassSpec;
3132
import software.amazon.awssdk.codegen.poet.rules.EndpointProviderInterfaceSpec;
@@ -58,6 +59,7 @@ protected List<GeneratorTask> createTasks() throws Exception {
5859
tasks.add(generateClientContextParams());
5960
}
6061
tasks.add(new RulesEngineRuntimeGeneratorTask(generatorTaskParams));
62+
tasks.add(generateDefaultPartitionsProvider());
6163
return tasks;
6264
}
6365

@@ -73,6 +75,11 @@ private GeneratorTask generateDefaultProvider() {
7375
return new PoetGeneratorTask(endpointRulesInternalDir(), model.getFileHeader(), new EndpointProviderSpec(model));
7476
}
7577

78+
private GeneratorTask generateDefaultPartitionsProvider() {
79+
return new PoetGeneratorTask(endpointRulesInternalDir(), model.getFileHeader(),
80+
new DefaultPartitionDataProviderSpec(model));
81+
}
82+
7683
private Collection<GeneratorTask> generateInterceptors() {
7784
return Arrays.asList(
7885
new PoetGeneratorTask(endpointRulesInternalDir(), model.getFileHeader(), new EndpointResolverInterceptorSpec(model)),

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

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,14 @@
1818
import java.io.IOException;
1919
import java.io.InputStream;
2020
import java.io.UncheckedIOException;
21-
import java.net.URL;
2221
import java.util.ArrayList;
2322
import java.util.Collection;
2423
import java.util.List;
25-
import java.util.jar.JarFile;
2624
import java.util.stream.Collectors;
27-
import java.util.zip.ZipEntry;
2825
import software.amazon.awssdk.codegen.emitters.GeneratorTask;
2926
import software.amazon.awssdk.codegen.emitters.GeneratorTaskParams;
3027
import software.amazon.awssdk.codegen.emitters.SimpleGeneratorTask;
28+
import software.amazon.awssdk.codegen.poet.rules.EndpointRulesSpecUtils;
3129
import software.amazon.awssdk.utils.IoUtils;
3230
import software.amazon.awssdk.utils.StringUtils;
3331
import software.amazon.awssdk.utils.Validate;
@@ -39,20 +37,22 @@ public final class RulesEngineRuntimeGeneratorTask extends BaseGeneratorTasks {
3937
private final String engineInternalResourcesDir;
4038
private final String engineInternalPackageName;
4139
private final String fileHeader;
40+
private final EndpointRulesSpecUtils endpointRulesSpecUtils;
4241

4342
public RulesEngineRuntimeGeneratorTask(GeneratorTaskParams generatorTaskParams) {
4443
super(generatorTaskParams);
4544
this.engineInternalClassDir = generatorTaskParams.getPathProvider().getEndpointRulesInternalDirectory();
4645
this.engineInternalResourcesDir = generatorTaskParams.getPathProvider().getEndpointRulesInternalResourcesDirectory();
4746
this.engineInternalPackageName = generatorTaskParams.getModel().getMetadata().getFullInternalEndpointRulesPackageName();
4847
this.fileHeader = generatorTaskParams.getModel().getFileHeader();
48+
this.endpointRulesSpecUtils = new EndpointRulesSpecUtils(generatorTaskParams.getModel());
4949
}
5050

5151
@Override
5252
protected List<GeneratorTask> createTasks() throws Exception {
5353
List<GeneratorTask> copyTasks = new ArrayList<>();
5454

55-
List<String> rulesEngineFiles = rulesEngineResourceFiles();
55+
List<String> rulesEngineFiles = endpointRulesSpecUtils.rulesEngineResourceFiles();
5656

5757
for (String path : rulesEngineJavaFilePaths(rulesEngineFiles)) {
5858
String newFileName = computeNewName(path);
@@ -62,15 +62,6 @@ protected List<GeneratorTask> createTasks() throws Exception {
6262
() -> rulesEngineFileContent("/" + path)));
6363
}
6464

65-
for (String path : rulesEngineJsonFilePaths(rulesEngineFiles)) {
66-
String newFileName = computeNewName(path);
67-
copyTasks.add(new SimpleGeneratorTask(engineInternalResourcesDir,
68-
newFileName,
69-
".json",
70-
"",
71-
() -> loadResourceAsString("/" + path)));
72-
}
73-
7465
return copyTasks;
7566
}
7667

@@ -80,23 +71,6 @@ private List<String> rulesEngineJavaFilePaths(Collection<String> runtimeEngineFi
8071
.collect(Collectors.toList());
8172
}
8273

83-
private List<String> rulesEngineJsonFilePaths(Collection<String> runtimeEngineFiles) {
84-
return runtimeEngineFiles.stream()
85-
.filter(e -> e.endsWith(".json.resource"))
86-
.collect(Collectors.toList());
87-
}
88-
89-
private List<String> rulesEngineResourceFiles() {
90-
URL currentJarUrl = RulesEngineRuntimeGeneratorTask.class.getProtectionDomain().getCodeSource().getLocation();
91-
try (JarFile jarFile = new JarFile(currentJarUrl.getFile())) {
92-
return jarFile.stream()
93-
.map(ZipEntry::getName)
94-
.filter(e -> e.startsWith("software/amazon/awssdk/codegen/rules"))
95-
.collect(Collectors.toList());
96-
} catch (IOException e) {
97-
throw new UncheckedIOException(e);
98-
}
99-
}
10074

10175
private String rulesEngineFileContent(String path) {
10276
return "package " + engineInternalPackageName + ";\n" +
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
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.rules;
17+
18+
import com.squareup.javapoet.ClassName;
19+
import com.squareup.javapoet.CodeBlock;
20+
import com.squareup.javapoet.FieldSpec;
21+
import com.squareup.javapoet.MethodSpec;
22+
import com.squareup.javapoet.ParameterizedTypeName;
23+
import com.squareup.javapoet.TypeSpec;
24+
import java.io.IOException;
25+
import java.io.InputStream;
26+
import java.io.UncheckedIOException;
27+
import javax.lang.model.element.Modifier;
28+
import software.amazon.awssdk.annotations.SdkInternalApi;
29+
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
30+
import software.amazon.awssdk.codegen.poet.ClassSpec;
31+
import software.amazon.awssdk.codegen.poet.PoetUtils;
32+
import software.amazon.awssdk.protocols.jsoncore.JsonNode;
33+
import software.amazon.awssdk.utils.IoUtils;
34+
import software.amazon.awssdk.utils.Lazy;
35+
import software.amazon.awssdk.utils.Validate;
36+
37+
public class DefaultPartitionDataProviderSpec implements ClassSpec {
38+
private final IntermediateModel model;
39+
private final EndpointRulesSpecUtils endpointRulesSpecUtils;
40+
41+
private final ClassName partitionsClass;
42+
43+
public DefaultPartitionDataProviderSpec(IntermediateModel model) {
44+
this.model = model;
45+
this.endpointRulesSpecUtils = new EndpointRulesSpecUtils(model);
46+
this.partitionsClass = endpointRulesSpecUtils.rulesRuntimeClassName("Partitions");
47+
}
48+
49+
@Override
50+
public TypeSpec poetSpec() {
51+
TypeSpec.Builder builder = PoetUtils.createClassBuilder(className())
52+
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
53+
.addAnnotation(SdkInternalApi.class)
54+
.addSuperinterface(
55+
endpointRulesSpecUtils.rulesRuntimeClassName("PartitionDataProvider"));
56+
57+
builder.addField(partitionDataField());
58+
builder.addField(partitionsLazyField());
59+
builder.addMethod(loadPartitionsMethod());
60+
builder.addMethod(doLoadPartitionsMethod());
61+
return builder.build();
62+
}
63+
64+
@Override
65+
public ClassName className() {
66+
return endpointRulesSpecUtils.rulesRuntimeClassName("DefaultPartitionDataProvider");
67+
}
68+
69+
private MethodSpec loadPartitionsMethod() {
70+
MethodSpec.Builder builder = MethodSpec.methodBuilder("loadPartitions")
71+
.addAnnotation(Override.class)
72+
.addModifiers(Modifier.PUBLIC)
73+
.returns(partitionsClass);
74+
75+
builder.addStatement("return PARTITIONS.getValue()");
76+
77+
return builder.build();
78+
}
79+
80+
private FieldSpec partitionDataField() {
81+
FieldSpec.Builder builder = FieldSpec.builder(String.class, "DEFAULT_PARTITION_DATA", Modifier.PRIVATE,
82+
Modifier.STATIC, Modifier.FINAL);
83+
builder.initializer("$S", readPartitionsJson());
84+
return builder.build();
85+
}
86+
87+
private FieldSpec partitionsLazyField() {
88+
ParameterizedTypeName lazyType = ParameterizedTypeName.get(ClassName.get(Lazy.class),
89+
partitionsClass);
90+
FieldSpec.Builder builder = FieldSpec.builder(lazyType, "PARTITIONS")
91+
.addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL);
92+
CodeBlock init = CodeBlock.builder()
93+
.addStatement("new $T<>($T::doLoadPartitions)", Lazy.class, className())
94+
.build();
95+
96+
builder.initializer(init);
97+
98+
return builder.build();
99+
}
100+
101+
private MethodSpec doLoadPartitionsMethod() {
102+
MethodSpec.Builder builder = MethodSpec.methodBuilder("doLoadPartitions")
103+
.addModifiers(Modifier.PRIVATE, Modifier.STATIC)
104+
.returns(partitionsClass);
105+
106+
builder.addStatement("return $T.fromNode($T.parser().parse(DEFAULT_PARTITION_DATA))", partitionsClass, JsonNode.class);
107+
108+
return builder.build();
109+
}
110+
111+
private String readPartitionsJson() {
112+
String jsonPath = endpointRulesSpecUtils.rulesEngineResourceFiles()
113+
.stream()
114+
.filter(e -> e.endsWith("partitions.json.resource"))
115+
.findFirst()
116+
.orElseThrow(
117+
() -> new RuntimeException("Could not find partitions.json.resource"));
118+
119+
return loadResourceAsString("/" + jsonPath);
120+
}
121+
122+
private String loadResourceAsString(String path) {
123+
try {
124+
return IoUtils.toUtf8String(loadResource(path));
125+
} catch (IOException e) {
126+
throw new UncheckedIOException(e);
127+
}
128+
}
129+
130+
private InputStream loadResource(String name) {
131+
InputStream resourceAsStream = DefaultPartitionDataProviderSpec.class.getResourceAsStream(name);
132+
Validate.notNull(resourceAsStream, "Failed to load resource from %s", name);
133+
return resourceAsStream;
134+
}
135+
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules/EndpointRulesSpecUtils.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,15 @@
2222
import com.squareup.javapoet.CodeBlock;
2323
import com.squareup.javapoet.ParameterizedTypeName;
2424
import com.squareup.javapoet.TypeName;
25+
import java.io.IOException;
26+
import java.io.UncheckedIOException;
27+
import java.net.URL;
28+
import java.util.List;
2529
import java.util.Locale;
2630
import java.util.concurrent.CompletableFuture;
31+
import java.util.jar.JarFile;
32+
import java.util.stream.Collectors;
33+
import java.util.zip.ZipEntry;
2734
import software.amazon.awssdk.codegen.internal.Utils;
2835
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
2936
import software.amazon.awssdk.codegen.model.intermediate.Metadata;
@@ -182,4 +189,16 @@ public boolean isS3Control() {
182189
public TypeName resolverReturnType() {
183190
return ParameterizedTypeName.get(CompletableFuture.class, Endpoint.class);
184191
}
192+
193+
public List<String> rulesEngineResourceFiles() {
194+
URL currentJarUrl = EndpointRulesSpecUtils.class.getProtectionDomain().getCodeSource().getLocation();
195+
try (JarFile jarFile = new JarFile(currentJarUrl.getFile())) {
196+
return jarFile.stream()
197+
.map(ZipEntry::getName)
198+
.filter(e -> e.startsWith("software/amazon/awssdk/codegen/rules"))
199+
.collect(Collectors.toList());
200+
} catch (IOException e) {
201+
throw new UncheckedIOException(e);
202+
}
203+
}
185204
}

codegen/src/main/resources/software/amazon/awssdk/codegen/rules/DefaultPartitionDataProvider.java.resource

Lines changed: 0 additions & 26 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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.services.endpointproviders;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
20+
import org.junit.jupiter.api.BeforeEach;
21+
import org.junit.jupiter.api.Test;
22+
import software.amazon.awssdk.services.restjsonendpointproviders.endpoints.internal.DefaultPartitionDataProvider;
23+
import software.amazon.awssdk.services.restjsonendpointproviders.endpoints.internal.Partition;
24+
import software.amazon.awssdk.services.restjsonendpointproviders.endpoints.internal.Partitions;
25+
26+
public class DefaultPartitionDataProviderTest {
27+
private DefaultPartitionDataProvider provider;
28+
29+
@BeforeEach
30+
public void setup() {
31+
provider = new DefaultPartitionDataProvider();
32+
}
33+
34+
@Test
35+
public void loadPartitions_returnsData() {
36+
Partitions partitions = provider.loadPartitions();
37+
assertThat(partitions.partitions()).isNotEmpty();
38+
}
39+
40+
@Test
41+
public void loadPartitions_partitionsContainsValidData() {
42+
Partition awsPartition = provider.loadPartitions()
43+
.partitions()
44+
.stream().filter(e -> e.id().equals("aws"))
45+
.findFirst()
46+
.orElseThrow(
47+
() -> new RuntimeException("could not find aws partition"));
48+
49+
assertThat(awsPartition.regions()).containsKey("us-west-2");
50+
}
51+
}

0 commit comments

Comments
 (0)