Skip to content

Add customization.config support for setting default RetryMode #2637

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 3, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-36a3de6.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"category": "AWS SDK for Java v2",
"contributor": "",
"type": "feature",
"description": "Add customization.config support for setting default RetryMode"
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import software.amazon.awssdk.core.retry.RetryMode;
import software.amazon.awssdk.core.traits.PayloadTrait;
import software.amazon.awssdk.utils.AttributeMap;

/**
* {@code service-2.json} models can be manually modified via defining properties in an associated {@code customization.config}
* file. This class defines the Java bean representation that will be used to parse the JSON customization file. The bean can
* then be later queried in the misc. codegen steps.
*/
public class CustomizationConfig {

/**
Expand Down Expand Up @@ -188,6 +194,8 @@ public class CustomizationConfig {
private UnderscoresInNameBehavior underscoresInNameBehavior;

private String userAgent;

private RetryMode defaultRetryMode;

private CustomizationConfig() {
}
Expand Down Expand Up @@ -485,4 +493,12 @@ public CustomizationConfig withUserAgent(String userAgent) {
this.userAgent = userAgent;
return this;
}

public RetryMode getDefaultRetryMode() {
return defaultRetryMode;
}

public void setDefaultRetryMode(RetryMode defaultRetryMode) {
this.defaultRetryMode = defaultRetryMode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.squareup.javapoet.TypeVariableName;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.auth.signer.Aws4Signer;
Expand All @@ -45,6 +46,7 @@
import software.amazon.awssdk.core.endpointdiscovery.providers.DefaultEndpointDiscoveryProviderChain;
import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory;
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
import software.amazon.awssdk.core.retry.RetryMode;
import software.amazon.awssdk.core.signer.Signer;
import software.amazon.awssdk.http.Protocol;
import software.amazon.awssdk.http.SdkHttpConfigurationOption;
Expand Down Expand Up @@ -92,9 +94,7 @@ public TypeSpec poetSpec() {
builder.addMethod(serviceNameMethod());
builder.addMethod(mergeServiceDefaultsMethod());

if (model.getCustomizationConfig().getUserAgent() != null) {
builder.addMethod(mergeInternalDefaultsMethod());
}
mergeInternalDefaultsMethod().ifPresent(builder::addMethod);

builder.addMethod(finalizeServiceConfigurationMethod());
builder.addMethod(defaultSignerMethod());
Expand Down Expand Up @@ -175,19 +175,31 @@ private MethodSpec mergeServiceDefaultsMethod() {
return builder.build();
}

private MethodSpec mergeInternalDefaultsMethod() {
private Optional<MethodSpec> mergeInternalDefaultsMethod() {
String userAgent = model.getCustomizationConfig().getUserAgent();
RetryMode defaultRetryMode = model.getCustomizationConfig().getDefaultRetryMode();

// If none of the options are customized, then we do not need to bother overriding the method
if (userAgent == null && defaultRetryMode == null) {
return Optional.empty();
}

MethodSpec.Builder builder = MethodSpec.methodBuilder("mergeInternalDefaults")
.addAnnotation(Override.class)
.addModifiers(PROTECTED, FINAL)
.returns(SdkClientConfiguration.class)
.addParameter(SdkClientConfiguration.class, "config")
.addCode("return config.merge(c -> c.option($T.INTERNAL_USER_AGENT, $S)\n",
SdkClientOption.class, userAgent);

builder.addCode(");");
return builder.build();
.addCode("return config.merge(c -> {\n");
if (userAgent != null) {
builder.addCode("c.option($T.INTERNAL_USER_AGENT, $S);\n",
SdkClientOption.class, userAgent);
}
if (defaultRetryMode != null) {
builder.addCode("c.option($T.DEFAULT_RETRY_MODE, $T.$L);\n",
SdkClientOption.class, RetryMode.class, defaultRetryMode.name());
}
builder.addCode("});\n");
return Optional.of(builder.build());
}

private MethodSpec finalizeServiceConfigurationMethod() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public void baseClientBuilderClass() throws Exception {

@Test
public void baseClientBuilderClassWithInternalUserAgent() throws Exception {
assertThat(new BaseClientBuilderClass(ClientTestModels.internalConfigModels()), generatesTo("test-client-builder-internal-user-agent-class.java"));
assertThat(new BaseClientBuilderClass(ClientTestModels.internalConfigModels()), generatesTo("test-client-builder-internal-defaults-class.java"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import software.amazon.awssdk.core.client.config.SdkClientOption;
import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory;
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
import software.amazon.awssdk.core.retry.RetryMode;
import software.amazon.awssdk.core.signer.Signer;
import software.amazon.awssdk.utils.CollectionUtils;

Expand Down Expand Up @@ -37,7 +38,10 @@ protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfigurati

@Override
protected final SdkClientConfiguration mergeInternalDefaults(SdkClientConfiguration config) {
return config.merge(c -> c.option(SdkClientOption.INTERNAL_USER_AGENT, "md/foobar"));
return config.merge(c -> {
c.option(SdkClientOption.INTERNAL_USER_AGENT, "md/foobar");
c.option(SdkClientOption.DEFAULT_RETRY_MODE, RetryMode.STANDARD);
});
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"authPolicyActions" : {
"skip" : true
},
"userAgent": "md/foobar"
"userAgent": "md/foobar",
"defaultRetryMode": "STANDARD"
}
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ private RetryPolicy resolveAwsRetryPolicy(SdkClientConfiguration config) {
RetryMode retryMode = RetryMode.resolver()
.profileFile(() -> config.option(SdkClientOption.PROFILE_FILE))
.profileName(config.option(SdkClientOption.PROFILE_NAME))
.defaultRetryMode(config.option(SdkClientOption.DEFAULT_RETRY_MODE))
.resolve();
return AwsRetryPolicy.forRetryMode(retryMode);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ private RetryPolicy resolveRetryPolicy(SdkClientConfiguration config) {
RetryMode retryMode = RetryMode.resolver()
.profileFile(() -> config.option(SdkClientOption.PROFILE_FILE))
.profileName(config.option(SdkClientOption.PROFILE_NAME))
.defaultRetryMode(config.option(SdkClientOption.DEFAULT_RETRY_MODE))
.resolve();
return RetryPolicy.forRetryMode(retryMode);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import software.amazon.awssdk.core.ServiceConfiguration;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
import software.amazon.awssdk.core.retry.RetryMode;
import software.amazon.awssdk.core.retry.RetryPolicy;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
Expand Down Expand Up @@ -149,6 +150,13 @@ public final class SdkClientOption<T> extends ClientOption<T> {
*/
public static final SdkClientOption<String> INTERNAL_USER_AGENT = new SdkClientOption<>(String.class);

/**
* Option to specify the default retry mode.
*
* @see RetryMode.Resolver#defaultRetryMode(RetryMode)
*/
public static final SdkClientOption<RetryMode> DEFAULT_RETRY_MODE = new SdkClientOption<>(RetryMode.class);

private SdkClientOption(Class<T> valueClass) {
super(valueClass);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,11 @@ public static Resolver resolver() {
* Allows customizing the variables used during determination of a {@link RetryMode}. Created via {@link #resolver()}.
*/
public static class Resolver {
private static final RetryMode SDK_DEFAULT_RETRY_MODE = LEGACY;

private Supplier<ProfileFile> profileFile;
private String profileName;
private RetryMode defaultRetryMode;

private Resolver() {
}
Expand All @@ -114,12 +117,20 @@ public Resolver profileName(String profileName) {
return this;
}

/**
* Configure the {@link RetryMode} that should be used if the mode is not specified anywhere else.
*/
public Resolver defaultRetryMode(RetryMode defaultRetryMode) {
this.defaultRetryMode = defaultRetryMode;
return this;
}

/**
* Resolve which retry mode should be used, based on the configured values.
*/
public RetryMode resolve() {
return OptionalUtils.firstPresent(Resolver.fromSystemSettings(), () -> fromProfileFile(profileFile, profileName))
.orElse(RetryMode.LEGACY);
.orElseGet(this::fromDefaultMode);
}

private static Optional<RetryMode> fromSystemSettings() {
Expand Down Expand Up @@ -150,5 +161,9 @@ private static Optional<RetryMode> fromString(String string) {
throw new IllegalStateException("Unsupported retry policy mode configured: " + string);
}
}

private RetryMode fromDefaultMode() {
return defaultRetryMode != null ? defaultRetryMode : SDK_DEFAULT_RETRY_MODE;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.Callable;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
Expand All @@ -44,25 +44,26 @@ public class RetryModeTest {
public static Collection<Object> data() {
return Arrays.asList(new Object[] {
// Test defaults
new TestData(null, null, null, RetryMode.LEGACY),
new TestData(null, null, "PropertyNotSet", RetryMode.LEGACY),
new TestData(null, null, null, null, RetryMode.LEGACY),
new TestData(null, null, "PropertyNotSet", null, RetryMode.LEGACY),

// Test precedence
new TestData("standard", "legacy", "PropertySetToLegacy", RetryMode.STANDARD),
new TestData("standard", null, null, RetryMode.STANDARD),
new TestData(null, "standard", "PropertySetToLegacy", RetryMode.STANDARD),
new TestData(null, "standard", null, RetryMode.STANDARD),
new TestData(null, null, "PropertySetToStandard", RetryMode.STANDARD),
new TestData("standard", "legacy", "PropertySetToLegacy", RetryMode.LEGACY, RetryMode.STANDARD),
new TestData("standard", null, null, RetryMode.LEGACY, RetryMode.STANDARD),
new TestData(null, "standard", "PropertySetToLegacy", RetryMode.LEGACY, RetryMode.STANDARD),
new TestData(null, "standard", null, RetryMode.LEGACY, RetryMode.STANDARD),
new TestData(null, null, "PropertySetToStandard", RetryMode.LEGACY, RetryMode.STANDARD),
new TestData(null, null, null, RetryMode.STANDARD, RetryMode.STANDARD),

// Test invalid values
new TestData("wrongValue", null, null, null),
new TestData(null, "wrongValue", null, null),
new TestData(null, null, "PropertySetToUnsupportedValue", null),
new TestData("wrongValue", null, null, null, IllegalStateException.class),
new TestData(null, "wrongValue", null, null, IllegalStateException.class),
new TestData(null, null, "PropertySetToUnsupportedValue", null, IllegalStateException.class),

// Test capitalization standardization
new TestData("sTaNdArD", null, null, RetryMode.STANDARD),
new TestData(null, "sTaNdArD", null, RetryMode.STANDARD),
new TestData(null, null, "PropertyMixedCase", RetryMode.STANDARD),
new TestData("sTaNdArD", null, null, null, RetryMode.STANDARD),
new TestData(null, "sTaNdArD", null, null, RetryMode.STANDARD),
new TestData(null, null, "PropertyMixedCase", null, RetryMode.STANDARD),
});
}

Expand All @@ -76,7 +77,7 @@ public void methodSetup() {
}

@Test
public void differentCombinationOfConfigs_shouldResolveCorrectly() {
public void differentCombinationOfConfigs_shouldResolveCorrectly() throws Exception {
if (testData.envVarValue != null) {
ENVIRONMENT_VARIABLE_HELPER.set(SdkSystemSetting.AWS_RETRY_MODE.environmentVariable(), testData.envVarValue);
}
Expand All @@ -92,10 +93,12 @@ public void differentCombinationOfConfigs_shouldResolveCorrectly() {
System.setProperty(ProfileFileSystemSetting.AWS_CONFIG_FILE.property(), diskLocationForFile);
}

if (testData.expected == null) {
assertThatThrownBy(RetryMode::defaultRetryMode).isInstanceOf(RuntimeException.class);
Callable<RetryMode> result = RetryMode.resolver().defaultRetryMode(testData.defaultMode)::resolve;
if (testData.expected instanceof Class<?>) {
Class<?> expectedClassType = (Class<?>) testData.expected;
assertThatThrownBy(result::call).isInstanceOf(expectedClassType);
} else {
assertThat(RetryMode.defaultRetryMode()).isEqualTo(testData.expected);
assertThat(result.call()).isEqualTo(testData.expected);
}
}

Expand All @@ -108,12 +111,14 @@ private static class TestData {
private final String envVarValue;
private final String systemProperty;
private final String configFile;
private final RetryMode expected;
private final RetryMode defaultMode;
private final Object expected;

TestData(String systemProperty, String envVarValue, String configFile, RetryMode expected) {
TestData(String systemProperty, String envVarValue, String configFile, RetryMode defaultMode, Object expected) {
this.envVarValue = envVarValue;
this.systemProperty = systemProperty;
this.configFile = configFile;
this.defaultMode = defaultMode;
this.expected = expected;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public static RetryPolicy resolveRetryPolicy(SdkClientConfiguration config) {
RetryMode retryMode = RetryMode.resolver()
.profileFile(() -> config.option(SdkClientOption.PROFILE_FILE))
.profileName(config.option(SdkClientOption.PROFILE_NAME))
.defaultRetryMode(config.option(SdkClientOption.DEFAULT_RETRY_MODE))
.resolve();

switch (retryMode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public static RetryPolicy resolveRetryPolicy(SdkClientConfiguration config) {
RetryMode retryMode = RetryMode.resolver()
.profileFile(() -> config.option(SdkClientOption.PROFILE_FILE))
.profileName(config.option(SdkClientOption.PROFILE_NAME))
.defaultRetryMode(config.option(SdkClientOption.DEFAULT_RETRY_MODE))
.resolve();
return AwsRetryPolicy.forRetryMode(retryMode)
.toBuilder()
Expand Down