Skip to content

Commit 4abe11e

Browse files
authored
[Default Configuration Part 3]: add defaults from defaults mode to the configuration resolution chain (#2803)
* Wiring up configuration * Address comments * Add test * Update debug statement and add singleton for AttributeMap
1 parent 56f5207 commit 4abe11e

File tree

20 files changed

+960
-18
lines changed

20 files changed

+960
-18
lines changed

codegen-lite-maven-plugin/src/main/java/software/amazon/awssdk/codegen/lite/maven/plugin/DefaultsModeGenerationMojo.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import software.amazon.awssdk.codegen.lite.CodeGenerator;
2626
import software.amazon.awssdk.codegen.lite.defaultsmode.DefaultConfiguration;
2727
import software.amazon.awssdk.codegen.lite.defaultsmode.DefaultsLoader;
28+
import software.amazon.awssdk.codegen.lite.defaultsmode.DefaultsModeConfigurationGenerator;
2829
import software.amazon.awssdk.codegen.lite.defaultsmode.DefaultsModeGenerator;
2930

3031
/**
@@ -34,6 +35,7 @@
3435
public class DefaultsModeGenerationMojo extends AbstractMojo {
3536

3637
private static final String DEFAULTS_MODE_BASE = "software.amazon.awssdk.defaultsmode";
38+
private static final String DEFAULTS_MODE_CONFIGURATION_BASE = "software.amazon.awssdk.internal.defaultsmode";
3739

3840
@Parameter(property = "outputDirectory", defaultValue = "${project.build.directory}")
3941
private String outputDirectory;
@@ -52,6 +54,7 @@ public void execute() {
5254
DefaultConfiguration configuration = DefaultsLoader.load(defaultConfigurationFile);
5355

5456
generateDefaultsModeClass(baseSourcesDirectory, configuration);
57+
generateDefaultsModeConfiguartionClass(baseSourcesDirectory, configuration);
5558

5659
project.addCompileSourceRoot(baseSourcesDirectory.toFile().getAbsolutePath());
5760
project.addTestCompileSourceRoot(testsDirectory.toFile().getAbsolutePath());
@@ -62,4 +65,10 @@ public void generateDefaultsModeClass(Path baseSourcesDirectory, DefaultConfigur
6265
new CodeGenerator(sourcesDirectory.toString(), new DefaultsModeGenerator(DEFAULTS_MODE_BASE, configuration)).generate();
6366
}
6467

68+
public void generateDefaultsModeConfiguartionClass(Path baseSourcesDirectory, DefaultConfiguration configuration) {
69+
Path sourcesDirectory = baseSourcesDirectory.resolve(DEFAULTS_MODE_CONFIGURATION_BASE.replace(".", "/"));
70+
new CodeGenerator(sourcesDirectory.toString(), new DefaultsModeConfigurationGenerator(DEFAULTS_MODE_CONFIGURATION_BASE,
71+
DEFAULTS_MODE_BASE,
72+
configuration)).generate();
73+
}
6574
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
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.lite.defaultsmode;
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.PUBLIC;
21+
import static javax.lang.model.element.Modifier.STATIC;
22+
23+
import com.squareup.javapoet.AnnotationSpec;
24+
import com.squareup.javapoet.ClassName;
25+
import com.squareup.javapoet.CodeBlock;
26+
import com.squareup.javapoet.FieldSpec;
27+
import com.squareup.javapoet.MethodSpec;
28+
import com.squareup.javapoet.ParameterizedTypeName;
29+
import com.squareup.javapoet.TypeSpec;
30+
import java.util.EnumMap;
31+
import java.util.HashMap;
32+
import java.util.Locale;
33+
import java.util.Map;
34+
import java.util.Set;
35+
import javax.lang.model.element.Modifier;
36+
import software.amazon.awssdk.annotations.Generated;
37+
import software.amazon.awssdk.annotations.SdkInternalApi;
38+
import software.amazon.awssdk.codegen.lite.PoetClass;
39+
import software.amazon.awssdk.utils.AttributeMap;
40+
41+
/**
42+
* Generates DefaultsModeConfiguration class that contains default options for each mode
43+
*/
44+
public class DefaultsModeConfigurationGenerator implements PoetClass {
45+
46+
private static final String DEFAULT_CONFIG_BY_MODE_ENUM_MAP = "DEFAULT_CONFIG_BY_MODE";
47+
private static final String DEFAULT_HTTP_CONFIG_BY_MODE_ENUM_MAP = "DEFAULT_HTTP_CONFIG_BY_MODE";
48+
private static final String DEFAULTS_VAR_SUFFIX = "_DEFAULTS";
49+
private static final String HTTP_DEFAULTS_VAR_SUFFIX = "_HTTP_DEFAULTS";
50+
private static final Map<String, OptionMetadata> CONFIGURATION_MAPPING = new HashMap<>();
51+
private static final Map<String, OptionMetadata> HTTP_CONFIGURATION_MAPPING = new HashMap<>();
52+
private final String basePackage;
53+
private final String defaultsModeBase;
54+
private final DefaultConfiguration configuration;
55+
56+
static {
57+
HTTP_CONFIGURATION_MAPPING.put("connectTimeoutInMillis",
58+
new OptionMetadata(ClassName.get("java.time", "Duration"),
59+
ClassName.get("software.amazon.awssdk.http",
60+
"SdkHttpConfigurationOption", "CONNECTION_TIMEOUT")));
61+
CONFIGURATION_MAPPING.put("retryMode", new OptionMetadata(ClassName.get("software.amazon.awssdk.core.retry", "RetryMode"
62+
), ClassName.get("software.amazon.awssdk.core.client.config", "SdkClientOption", "DEFAULT_RETRY_MODE")));
63+
}
64+
65+
public DefaultsModeConfigurationGenerator(String basePackage, String defaultsModeBase, DefaultConfiguration configuration) {
66+
this.basePackage = basePackage;
67+
this.configuration = configuration;
68+
this.defaultsModeBase = defaultsModeBase;
69+
}
70+
71+
@Override
72+
public TypeSpec poetClass() {
73+
TypeSpec.Builder builder = TypeSpec.classBuilder(className())
74+
.addModifiers(PUBLIC, FINAL)
75+
.addJavadoc(documentation())
76+
.addAnnotation(SdkInternalApi.class)
77+
.addAnnotation(AnnotationSpec.builder(Generated.class)
78+
.addMember("value",
79+
"$S",
80+
"software.amazon.awssdk:codegen")
81+
.build())
82+
.addMethod(defaultConfigMethod(DEFAULT_CONFIG_BY_MODE_ENUM_MAP, "defaultConfig"))
83+
.addMethod(defaultConfigMethod(DEFAULT_HTTP_CONFIG_BY_MODE_ENUM_MAP,
84+
"defaultHttpConfig"))
85+
.addMethod(createConstructor());
86+
87+
88+
configuration.modeDefaults().entrySet().forEach(entry -> {
89+
builder.addField(addDefaultsFieldForMode(entry));
90+
builder.addField(addHttpDefaultsFieldForMode(entry));
91+
});
92+
93+
addDefaultsFieldForLegacy(builder, "LEGACY_DEFAULTS");
94+
addDefaultsFieldForLegacy(builder, "LEGACY_HTTP_DEFAULTS");
95+
96+
addEnumMapField(builder, DEFAULT_CONFIG_BY_MODE_ENUM_MAP);
97+
addEnumMapField(builder, DEFAULT_HTTP_CONFIG_BY_MODE_ENUM_MAP);
98+
99+
addStaticEnumMapBlock(builder);
100+
return builder.build();
101+
}
102+
103+
private void addStaticEnumMapBlock(TypeSpec.Builder builder) {
104+
CodeBlock.Builder staticCodeBlock = CodeBlock.builder();
105+
106+
putItemsToEnumMap(staticCodeBlock, configuration.modeDefaults().keySet(), DEFAULTS_VAR_SUFFIX,
107+
DEFAULT_CONFIG_BY_MODE_ENUM_MAP);
108+
putItemsToEnumMap(staticCodeBlock, configuration.modeDefaults().keySet(), HTTP_DEFAULTS_VAR_SUFFIX,
109+
DEFAULT_HTTP_CONFIG_BY_MODE_ENUM_MAP);
110+
111+
builder.addStaticBlock(staticCodeBlock.build());
112+
}
113+
114+
private void addEnumMapField(TypeSpec.Builder builder, String name) {
115+
ParameterizedTypeName map = ParameterizedTypeName.get(ClassName.get(Map.class),
116+
defaultsModeClassName(),
117+
ClassName.get(AttributeMap.class));
118+
FieldSpec field = FieldSpec.builder(map, name, PRIVATE, STATIC, FINAL)
119+
.initializer("new $T<>(DefaultsMode.class)", EnumMap.class).build();
120+
builder.addField(field);
121+
}
122+
123+
private void putItemsToEnumMap(CodeBlock.Builder codeBlock, Set<String> modes, String suffix, String mapName) {
124+
modes.forEach(m -> {
125+
String mode = sanitizeMode(m);
126+
codeBlock.addStatement("$N.put(DefaultsMode.$N, $N)", mapName, mode, mode + suffix);
127+
});
128+
129+
// Add LEGACY since LEGACY is not in the modes set
130+
codeBlock.addStatement("$N.put(DefaultsMode.LEGACY, LEGACY$N)", mapName, suffix);
131+
}
132+
133+
@Override
134+
public ClassName className() {
135+
return ClassName.get(basePackage, "DefaultsModeConfiguration");
136+
}
137+
138+
private FieldSpec addDefaultsFieldForMode(Map.Entry<String, Map<String, String>> modeEntry) {
139+
String mode = modeEntry.getKey();
140+
String fieldName = sanitizeMode(mode) + DEFAULTS_VAR_SUFFIX;
141+
142+
CodeBlock.Builder attributeBuilder = CodeBlock.builder()
143+
.add("$T.builder()", AttributeMap.class);
144+
145+
modeEntry.getValue()
146+
.entrySet()
147+
.stream()
148+
.filter(e -> CONFIGURATION_MAPPING.containsKey(e.getKey()))
149+
.forEach(e -> attributeMapBuilder(e.getKey(), e.getValue(), attributeBuilder));
150+
151+
152+
FieldSpec.Builder fieldSpec = FieldSpec.builder(AttributeMap.class, fieldName, PRIVATE, STATIC, FINAL)
153+
.initializer(attributeBuilder
154+
.add(".build()")
155+
.build());
156+
157+
158+
return fieldSpec.build();
159+
}
160+
161+
private void addDefaultsFieldForLegacy(TypeSpec.Builder builder, String name) {
162+
FieldSpec field = FieldSpec.builder(AttributeMap.class, name, PRIVATE, STATIC, FINAL)
163+
.initializer("$T.empty()", AttributeMap.class).build();
164+
builder.addField(field);
165+
}
166+
167+
private void attributeMapBuilder(String option, String value, CodeBlock.Builder attributeBuilder) {
168+
OptionMetadata optionMetadata = CONFIGURATION_MAPPING.get(option);
169+
switch (option) {
170+
case "retryMode":
171+
attributeBuilder.add(".put($T, $T.$N)", optionMetadata.attribute, optionMetadata.type,
172+
value.toUpperCase(Locale.US));
173+
break;
174+
default:
175+
throw new IllegalStateException("Unsupported option " + option);
176+
}
177+
}
178+
179+
private void httpAttributeMapBuilder(String option, String value, CodeBlock.Builder attributeBuilder) {
180+
OptionMetadata optionMetadata = HTTP_CONFIGURATION_MAPPING.get(option);
181+
switch (option) {
182+
case "connectTimeoutInMillis":
183+
attributeBuilder.add(".put($T, $T.ofMillis($N))", optionMetadata.attribute, optionMetadata.type, value);
184+
break;
185+
default:
186+
throw new IllegalStateException("Unsupported option " + option);
187+
}
188+
}
189+
190+
private FieldSpec addHttpDefaultsFieldForMode(Map.Entry<String, Map<String, String>> modeEntry) {
191+
String mode = modeEntry.getKey();
192+
String fieldName = sanitizeMode(mode) + HTTP_DEFAULTS_VAR_SUFFIX;
193+
194+
CodeBlock.Builder attributeBuilder = CodeBlock.builder()
195+
.add("$T.builder()", AttributeMap.class);
196+
197+
modeEntry.getValue()
198+
.entrySet()
199+
.stream()
200+
.filter(e -> HTTP_CONFIGURATION_MAPPING.containsKey(e.getKey()))
201+
.forEach(e -> httpAttributeMapBuilder(e.getKey(), e.getValue(), attributeBuilder));
202+
203+
FieldSpec.Builder fieldSpec = FieldSpec.builder(AttributeMap.class, fieldName, PRIVATE, STATIC, FINAL)
204+
.initializer(attributeBuilder
205+
.add(".build()")
206+
.build());
207+
208+
return fieldSpec.build();
209+
}
210+
211+
private String sanitizeMode(String str) {
212+
return str.replace('-', '_').toUpperCase(Locale.US);
213+
}
214+
215+
private CodeBlock documentation() {
216+
CodeBlock.Builder builder = CodeBlock.builder()
217+
.add("Contains a collection of default configuration options for each "
218+
+ "DefaultsMode");
219+
220+
return builder.build();
221+
}
222+
223+
private MethodSpec defaultConfigMethod(String enumMap, String methodName) {
224+
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(methodName)
225+
.returns(AttributeMap.class)
226+
.addModifiers(PUBLIC, STATIC)
227+
.addJavadoc("Return the default config options for a given defaults "
228+
+ "mode")
229+
.addParameter(defaultsModeClassName(), "mode")
230+
.addStatement("return $N.getOrDefault(mode, $T.empty())",
231+
enumMap, AttributeMap.class);
232+
233+
return methodBuilder.build();
234+
}
235+
236+
private ClassName defaultsModeClassName() {
237+
return ClassName.get(defaultsModeBase, "DefaultsMode");
238+
}
239+
240+
private MethodSpec createConstructor() {
241+
return MethodSpec.constructorBuilder()
242+
.addModifiers(Modifier.PRIVATE)
243+
.build();
244+
}
245+
246+
private static final class OptionMetadata {
247+
private final ClassName type;
248+
private final ClassName attribute;
249+
250+
OptionMetadata(ClassName type, ClassName attribute) {
251+
this.type = type;
252+
this.attribute = attribute;
253+
}
254+
}
255+
}

codegen-lite/src/test/java/software/amazon/awssdk/codegen/lite/defaultsmode/DefaultsModeGenerationTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,10 @@ public void defaultsModeEnum() {
4242
assertThat(generator, generatesTo("defaults-mode.java"));
4343
}
4444

45+
@Test
46+
public void defaultsModeConfigurationClass() {
47+
DefaultsModeConfigurationGenerator generator = new DefaultsModeConfigurationGenerator(DEFAULTS_MODE_BASE, DEFAULTS_MODE_BASE, defaultConfiguration);
48+
assertThat(generator, generatesTo("defaults-mode-configuration.java"));
49+
}
50+
4551
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package software.amazon.awssdk.defaultsmode;
2+
3+
import java.time.Duration;
4+
import java.util.EnumMap;
5+
import java.util.Map;
6+
import software.amazon.awssdk.annotations.Generated;
7+
import software.amazon.awssdk.annotations.SdkInternalApi;
8+
import software.amazon.awssdk.core.client.config.SdkClientOption;
9+
import software.amazon.awssdk.core.retry.RetryMode;
10+
import software.amazon.awssdk.http.SdkHttpConfigurationOption;
11+
import software.amazon.awssdk.utils.AttributeMap;
12+
13+
/**
14+
* Contains a collection of default configuration options for each DefaultsMode
15+
*/
16+
@SdkInternalApi
17+
@Generated("software.amazon.awssdk:codegen")
18+
public final class DefaultsModeConfiguration {
19+
private static final AttributeMap STANDARD_DEFAULTS = AttributeMap.builder()
20+
.put(SdkClientOption.DEFAULT_RETRY_MODE, RetryMode.STANDARD).build();
21+
22+
private static final AttributeMap STANDARD_HTTP_DEFAULTS = AttributeMap.builder()
23+
.put(SdkHttpConfigurationOption.CONNECTION_TIMEOUT, Duration.ofMillis(2000)).build();
24+
25+
private static final AttributeMap MOBILE_DEFAULTS = AttributeMap.builder()
26+
.put(SdkClientOption.DEFAULT_RETRY_MODE, RetryMode.ADAPTIVE).build();
27+
28+
private static final AttributeMap MOBILE_HTTP_DEFAULTS = AttributeMap.builder()
29+
.put(SdkHttpConfigurationOption.CONNECTION_TIMEOUT, Duration.ofMillis(10000)).build();
30+
31+
private static final AttributeMap CROSS_REGION_DEFAULTS = AttributeMap.builder()
32+
.put(SdkClientOption.DEFAULT_RETRY_MODE, RetryMode.STANDARD).build();
33+
34+
private static final AttributeMap CROSS_REGION_HTTP_DEFAULTS = AttributeMap.builder()
35+
.put(SdkHttpConfigurationOption.CONNECTION_TIMEOUT, Duration.ofMillis(2800)).build();
36+
37+
private static final AttributeMap IN_REGION_DEFAULTS = AttributeMap.builder()
38+
.put(SdkClientOption.DEFAULT_RETRY_MODE, RetryMode.STANDARD).build();
39+
40+
private static final AttributeMap IN_REGION_HTTP_DEFAULTS = AttributeMap.builder()
41+
.put(SdkHttpConfigurationOption.CONNECTION_TIMEOUT, Duration.ofMillis(1000)).build();
42+
43+
private static final AttributeMap LEGACY_DEFAULTS = AttributeMap.empty();
44+
45+
private static final AttributeMap LEGACY_HTTP_DEFAULTS = AttributeMap.empty();
46+
47+
private static final Map<DefaultsMode, AttributeMap> DEFAULT_CONFIG_BY_MODE = new EnumMap<>(DefaultsMode.class);
48+
49+
private static final Map<DefaultsMode, AttributeMap> DEFAULT_HTTP_CONFIG_BY_MODE = new EnumMap<>(DefaultsMode.class);
50+
51+
static {
52+
DEFAULT_CONFIG_BY_MODE.put(DefaultsMode.STANDARD, STANDARD_DEFAULTS);
53+
DEFAULT_CONFIG_BY_MODE.put(DefaultsMode.MOBILE, MOBILE_DEFAULTS);
54+
DEFAULT_CONFIG_BY_MODE.put(DefaultsMode.CROSS_REGION, CROSS_REGION_DEFAULTS);
55+
DEFAULT_CONFIG_BY_MODE.put(DefaultsMode.IN_REGION, IN_REGION_DEFAULTS);
56+
DEFAULT_CONFIG_BY_MODE.put(DefaultsMode.LEGACY, LEGACY_DEFAULTS);
57+
DEFAULT_HTTP_CONFIG_BY_MODE.put(DefaultsMode.STANDARD, STANDARD_HTTP_DEFAULTS);
58+
DEFAULT_HTTP_CONFIG_BY_MODE.put(DefaultsMode.MOBILE, MOBILE_HTTP_DEFAULTS);
59+
DEFAULT_HTTP_CONFIG_BY_MODE.put(DefaultsMode.CROSS_REGION, CROSS_REGION_HTTP_DEFAULTS);
60+
DEFAULT_HTTP_CONFIG_BY_MODE.put(DefaultsMode.IN_REGION, IN_REGION_HTTP_DEFAULTS);
61+
DEFAULT_HTTP_CONFIG_BY_MODE.put(DefaultsMode.LEGACY, LEGACY_HTTP_DEFAULTS);
62+
}
63+
64+
private DefaultsModeConfiguration() {
65+
}
66+
67+
/**
68+
* Return the default config options for a given defaults mode
69+
*/
70+
public static AttributeMap defaultConfig(DefaultsMode mode) {
71+
return DEFAULT_CONFIG_BY_MODE.getOrDefault(mode, AttributeMap.empty());
72+
}
73+
74+
/**
75+
* Return the default config options for a given defaults mode
76+
*/
77+
public static AttributeMap defaultHttpConfig(DefaultsMode mode) {
78+
return DEFAULT_HTTP_CONFIG_BY_MODE.getOrDefault(mode, AttributeMap.empty());
79+
}
80+
}

0 commit comments

Comments
 (0)