diff --git a/.changes/next-release/feature-AWSSDKforJavav2-eea40a4.json b/.changes/next-release/feature-AWSSDKforJavav2-eea40a4.json new file mode 100644 index 000000000000..452de0ebbd9e --- /dev/null +++ b/.changes/next-release/feature-AWSSDKforJavav2-eea40a4.json @@ -0,0 +1,6 @@ +{ + "type": "feature", + "category": "AWS SDK for Java v2", + "contributor": "", + "description": "Add support for specifying endpoint overrides using environment variables, system properties or profile files. More information about this feature is available here: https://docs.aws.amazon.com/sdkref/latest/guide/feature-ss-endpoints.html" +} diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/internal/Utils.java b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/Utils.java index 13703cbb61da..cf51e63148cb 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/internal/Utils.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/Utils.java @@ -16,6 +16,7 @@ package software.amazon.awssdk.codegen.internal; import static java.util.stream.Collectors.toList; +import static software.amazon.awssdk.utils.StringUtils.lowerCase; import java.io.Closeable; import java.io.File; @@ -133,7 +134,7 @@ public static String removeLeading(String str, String toRemove) { if (str == null) { return null; } - if (str.startsWith(toRemove)) { + if (lowerCase(str).startsWith(lowerCase(toRemove))) { return str.substring(toRemove.length()); } return str; @@ -143,7 +144,7 @@ public static String removeTrailing(String str, String toRemove) { if (str == null) { return null; } - if (str.endsWith(toRemove)) { + if (lowerCase(str).endsWith(lowerCase(toRemove))) { return str.substring(0, str.length() - toRemove.length()); } return str; diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java b/codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java index 721643f890fc..e5a4904f295f 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java @@ -114,19 +114,42 @@ private static boolean isJavaKeyword(String word) { @Override public String getServiceName() { - String baseName = Stream.of(serviceModel.getMetadata().getServiceId()) - .filter(Objects::nonNull) - .filter(s -> !s.trim().isEmpty()) - .findFirst() - .orElseThrow(() -> new IllegalStateException("ServiceId is missing in the c2j model.")); - + String baseName = serviceId(); baseName = pascalCase(baseName); + baseName = removeRedundantPrefixesAndSuffixes(baseName); + return baseName; + } - // Special cases - baseName = Utils.removeLeading(baseName, "Amazon"); - baseName = Utils.removeLeading(baseName, "Aws"); - baseName = Utils.removeTrailing(baseName, "Service"); + @Override + public String getServiceNameForEnvironmentVariables() { + String baseName = serviceId(); + baseName = baseName.replace(' ', '_'); + baseName = StringUtils.upperCase(baseName); + return baseName; + } + + @Override + public String getServiceNameForSystemProperties() { + return getServiceName(); + } + + @Override + public String getServiceNameForProfileFile() { + return StringUtils.lowerCase(getServiceNameForEnvironmentVariables()); + } + + private String serviceId() { + return Stream.of(serviceModel.getMetadata().getServiceId()) + .filter(Objects::nonNull) + .filter(s -> !s.trim().isEmpty()) + .findFirst() + .orElseThrow(() -> new IllegalStateException("ServiceId is missing in the c2j model.")); + } + private static String removeRedundantPrefixesAndSuffixes(String baseName) { + baseName = Utils.removeLeading(baseName, "amazon"); + baseName = Utils.removeLeading(baseName, "aws"); + baseName = Utils.removeTrailing(baseName, "service"); return baseName; } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/naming/NamingStrategy.java b/codegen/src/main/java/software/amazon/awssdk/codegen/naming/NamingStrategy.java index 5bb7c67ae147..1fe32773d71f 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/naming/NamingStrategy.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/naming/NamingStrategy.java @@ -29,6 +29,21 @@ public interface NamingStrategy { */ String getServiceName(); + /** + * Retrieve the service name that should be used for environment variables. + */ + String getServiceNameForEnvironmentVariables(); + + /** + * Retrieve the service name that should be used for system properties. + */ + String getServiceNameForSystemProperties(); + + /** + * Retrieve the service name that should be used for profile properties. + */ + String getServiceNameForProfileFile(); + /** * Retrieve the client package name that should be used based on the service name. */ diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 386f3b267887..d98b7556ae98 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -43,6 +43,7 @@ import software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.codegen.internal.Utils; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.model.intermediate.OperationModel; @@ -72,6 +73,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.CollectionUtils; import software.amazon.awssdk.utils.StringUtils; @@ -456,6 +458,27 @@ private MethodSpec finalizeServiceConfigurationMethod() { builder.addStatement("builder.option($T.$L, resolveAccountIdEndpointMode(config))", AwsClientOption.class, model.getNamingStrategy().getEnumValueName("accountIdEndpointMode")); } + + String serviceNameForEnvVar = model.getNamingStrategy().getServiceNameForEnvironmentVariables(); + String serviceNameForSystemProperty = model.getNamingStrategy().getServiceNameForSystemProperties(); + String serviceNameForProfileFile = model.getNamingStrategy().getServiceNameForProfileFile(); + + builder.addCode("builder.lazyOptionIfAbsent($T.CLIENT_ENDPOINT_PROVIDER, c ->", SdkClientOption.class) + .addCode(" $T.builder()", AwsClientEndpointProvider.class) + .addCode(" .serviceEndpointOverrideEnvironmentVariable($S)", "AWS_ENDPOINT_URL_" + serviceNameForEnvVar) + .addCode(" .serviceEndpointOverrideSystemProperty($S)", "aws.endpointUrl" + serviceNameForSystemProperty) + .addCode(" .serviceProfileProperty($S)", serviceNameForProfileFile) + .addCode(" .serviceEndpointPrefix(serviceEndpointPrefix())") + .addCode(" .defaultProtocol($S)", "https") + .addCode(" .region(c.get($T.AWS_REGION))", AwsClientOption.class) + .addCode(" .profileFile(c.get($T.PROFILE_FILE_SUPPLIER))", SdkClientOption.class) + .addCode(" .profileName(c.get($T.PROFILE_NAME))", SdkClientOption.class) + .addCode(" .putAdvancedOption($T.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT,", ServiceMetadataAdvancedOption.class) + .addCode(" c.get($T.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT))", ServiceMetadataAdvancedOption.class) + .addCode(" .dualstackEnabled(c.get($T.DUALSTACK_ENDPOINT_ENABLED))", AwsClientOption.class) + .addCode(" .fipsEnabled(c.get($T.FIPS_ENDPOINT_ENABLED))", AwsClientOption.class) + .addCode(" .build());"); + builder.addStatement("return builder.build()"); return builder.build(); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java index 1564af8b35d0..070dfb293404 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java @@ -254,8 +254,8 @@ private MethodSpec constructor(TypeSpec.Builder classBuilder) { "AsyncEndpointDiscoveryCacheLoader")); if (model.getCustomizationConfig().allowEndpointOverrideForEndpointDiscoveryRequiredOperations()) { - builder.beginControlFlow("if (clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN) == " - + "Boolean.TRUE)"); + builder.beginControlFlow("if (clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER)" + + ".isEndpointOverridden())"); builder.addStatement("log.warn($S)", "Endpoint discovery is enabled for this client, and an endpoint override was also " + "specified. This will disable endpoint discovery for methods that require it, instead " @@ -401,7 +401,8 @@ protected MethodSpec.Builder operationBody(MethodSpec.Builder builder, Operation builder.addStatement("boolean endpointDiscoveryEnabled = " + "clientConfiguration.option(SdkClientOption.ENDPOINT_DISCOVERY_ENABLED)"); builder.addStatement("boolean endpointOverridden = " - + "clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN) == Boolean.TRUE"); + + "clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER)" + + ".isEndpointOverridden()"); if (opModel.getEndpointDiscovery().isRequired()) { if (!model.getCustomizationConfig().allowEndpointOverrideForEndpointDiscoveryRequiredOperations()) { @@ -443,7 +444,8 @@ protected MethodSpec.Builder operationBody(MethodSpec.Builder builder, Operation builder.addCode("endpointFuture = identityFuture.thenCompose(credentials -> {") .addCode(" $1T endpointDiscoveryRequest = $1T.builder()", EndpointDiscoveryRequest.class) .addCode(" .required($L)", opModel.getInputShape().getEndpointDiscovery().isRequired()) - .addCode(" .defaultEndpoint(clientConfiguration.option($T.ENDPOINT))", SdkClientOption.class) + .addCode(" .defaultEndpoint(clientConfiguration.option($T.CLIENT_ENDPOINT_PROVIDER).clientEndpoint())", + SdkClientOption.class) .addCode(" .overrideConfiguration($N.overrideConfiguration().orElse(null))", opModel.getInput().getVariableName()) .addCode(" .build();") diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java index befb4b49bc28..d042f60e069f 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java @@ -219,8 +219,8 @@ private MethodSpec constructor() { "EndpointDiscoveryCacheLoader")); if (model.getCustomizationConfig().allowEndpointOverrideForEndpointDiscoveryRequiredOperations()) { - builder.beginControlFlow("if (clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN) == " - + "Boolean.TRUE)"); + builder.beginControlFlow("if (clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER)" + + ".isEndpointOverridden())"); builder.addStatement("log.warn(() -> $S)", "Endpoint discovery is enabled for this client, and an endpoint override was also " + "specified. This will disable endpoint discovery for methods that require it, instead " @@ -265,7 +265,8 @@ private MethodSpec traditionalMethod(OperationModel opModel) { method.addStatement("boolean endpointDiscoveryEnabled = " + "clientConfiguration.option(SdkClientOption.ENDPOINT_DISCOVERY_ENABLED)"); method.addStatement("boolean endpointOverridden = " - + "clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN) == Boolean.TRUE"); + + "clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER)" + + ".isEndpointOverridden()"); if (opModel.getEndpointDiscovery().isRequired()) { if (!model.getCustomizationConfig().allowEndpointOverrideForEndpointDiscoveryRequiredOperations()) { @@ -309,7 +310,8 @@ private MethodSpec traditionalMethod(OperationModel opModel) { method.addCode("$1T endpointDiscoveryRequest = $1T.builder()", EndpointDiscoveryRequest.class) .addCode(" .required($L)", opModel.getInputShape().getEndpointDiscovery().isRequired()) - .addCode(" .defaultEndpoint(clientConfiguration.option($T.ENDPOINT))", SdkClientOption.class) + .addCode(" .defaultEndpoint(clientConfiguration.option($T.CLIENT_ENDPOINT_PROVIDER).clientEndpoint())", + SdkClientOption.class) .addCode(" .overrideConfiguration($N.overrideConfiguration().orElse(null))", opModel.getInput().getVariableName()) .addCode(" .build();"); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationUtils.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationUtils.java index b4c325123332..efe1a90ae9f1 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationUtils.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationUtils.java @@ -33,6 +33,7 @@ import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.poet.auth.scheme.AuthSchemeSpecUtils; import software.amazon.awssdk.codegen.poet.rules.EndpointRulesSpecUtils; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.ClientOption; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; @@ -161,11 +162,10 @@ private Field endpointOverrideField() { private CodeBlock endpointOverrideConfigSetter() { return CodeBlock.builder() .beginControlFlow("if (endpointOverride != null)") - .addStatement("config.option($T.ENDPOINT, endpointOverride)", SdkClientOption.class) - .addStatement("config.option($T.ENDPOINT_OVERRIDDEN, true)", SdkClientOption.class) + .addStatement("config.option($T.CLIENT_ENDPOINT_PROVIDER, $T.forEndpointOverride(endpointOverride))", + SdkClientOption.class, ClientEndpointProvider.class) .nextControlFlow("else") - .addStatement("config.option($T.ENDPOINT, null)", SdkClientOption.class) - .addStatement("config.option($T.ENDPOINT_OVERRIDDEN, false)", SdkClientOption.class) + .addStatement("config.option($T.CLIENT_ENDPOINT_PROVIDER, null)", SdkClientOption.class) .endControlFlow() .addStatement("return this") .build(); @@ -173,9 +173,10 @@ private CodeBlock endpointOverrideConfigSetter() { private CodeBlock endpointOverrideConfigGetter() { return CodeBlock.builder() - .beginControlFlow("if (Boolean.TRUE.equals(config.option($T.ENDPOINT_OVERRIDDEN)))", - SdkClientOption.class) - .addStatement("return config.option($T.ENDPOINT)", SdkClientOption.class) + .addStatement("$T clientEndpoint = config.option($T.CLIENT_ENDPOINT_PROVIDER)", + ClientEndpointProvider.class, SdkClientOption.class) + .beginControlFlow("if (clientEndpoint != null && clientEndpoint.isEndpointOverridden())") + .addStatement("return clientEndpoint.clientEndpoint()") .endControlFlow() .addStatement("return null") .build(); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules/RequestEndpointInterceptorSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules/RequestEndpointInterceptorSpec.java index 9f7a9f647828..63b5133f180e 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules/RequestEndpointInterceptorSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules/RequestEndpointInterceptorSpec.java @@ -26,7 +26,6 @@ import software.amazon.awssdk.core.interceptor.Context; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; -import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute; import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute; import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.SdkHttpRequest; @@ -71,14 +70,14 @@ private MethodSpec modifyHttpRequestMethod() { .addStatement("return context.httpRequest()") .endControlFlow().build(); - b.addStatement("$1T endpoint = ($1T) executionAttributes.getAttribute($2T.RESOLVED_ENDPOINT)", + b.addStatement("$T endpoint = executionAttributes.getAttribute($T.RESOLVED_ENDPOINT)", Endpoint.class, SdkInternalExecutionAttribute.class); b.addStatement("return $T.setUri(context.httpRequest()," - + "executionAttributes.getAttribute($T.CLIENT_ENDPOINT)," + + "executionAttributes.getAttribute($T.CLIENT_ENDPOINT_PROVIDER).clientEndpoint()," + "endpoint.url())", endpointRulesSpecUtils.rulesRuntimeClassName("AwsEndpointProviderUtils"), - SdkExecutionAttribute.class); + SdkInternalExecutionAttribute.class); return b.build(); } diff --git a/codegen/src/main/resources/software/amazon/awssdk/codegen/rules/AwsEndpointProviderUtils.java.resource b/codegen/src/main/resources/software/amazon/awssdk/codegen/rules/AwsEndpointProviderUtils.java.resource index 2859989b3716..ad2242d6af82 100644 --- a/codegen/src/main/resources/software/amazon/awssdk/codegen/rules/AwsEndpointProviderUtils.java.resource +++ b/codegen/src/main/resources/software/amazon/awssdk/codegen/rules/AwsEndpointProviderUtils.java.resource @@ -44,7 +44,8 @@ public final class AwsEndpointProviderUtils { public static String endpointBuiltIn(ExecutionAttributes executionAttributes) { if (endpointIsOverridden(executionAttributes)) { return invokeSafely(() -> { - URI endpointOverride = executionAttributes.getAttribute(SdkExecutionAttribute.CLIENT_ENDPOINT); + URI endpointOverride = executionAttributes.getAttribute(SdkInternalExecutionAttribute.CLIENT_ENDPOINT_PROVIDER) + .clientEndpoint(); return new URI(endpointOverride.getScheme(), null, endpointOverride.getHost(), endpointOverride.getPort(), endpointOverride.getPath(), null, endpointOverride.getFragment()).toString(); }); @@ -53,11 +54,10 @@ public final class AwsEndpointProviderUtils { } /** - * True if the the {@link SdkExecutionAttribute#ENDPOINT_OVERRIDDEN} attribute is present and its value is - * {@code true}, {@code false} otherwise. + * Read {@link SdkExecutionAttribute#CLIENT_ENDPOINT_PROVIDER}'s isEndpointOverridden attribute. */ public static boolean endpointIsOverridden(ExecutionAttributes attrs) { - return attrs.getOptionalAttribute(SdkExecutionAttribute.ENDPOINT_OVERRIDDEN).orElse(false); + return attrs.getAttribute(SdkInternalExecutionAttribute.CLIENT_ENDPOINT_PROVIDER).isEndpointOverridden(); } /** diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategyTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategyTest.java index 064e662e95cd..6b8756474405 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategyTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategyTest.java @@ -31,6 +31,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig; import software.amazon.awssdk.codegen.model.config.customization.UnderscoresInNameBehavior; @@ -336,6 +337,412 @@ public void validateAllowsUnderscoresWithCustomization() { strategy.validateCustomerVisibleNaming(model); } + @Test + public void validateServiceIdentifiersForEnvVarsAndProfileProperty() { + when(serviceModel.getMetadata()).thenReturn(serviceMetadata); + + validateServiceIdSetting("AccessAnalyzer", "accessanalyzer", "ACCESSANALYZER", "AccessAnalyzer"); + validateServiceIdSetting("Account", "account", "ACCOUNT", "Account"); + validateServiceIdSetting("ACM", "acm", "ACM", "Acm"); + validateServiceIdSetting("ACM PCA", "acm_pca", "ACM_PCA", "AcmPca"); + validateServiceIdSetting("Alexa For Business", "alexa_for_business", "ALEXA_FOR_BUSINESS", "AlexaForBusiness"); + validateServiceIdSetting("amp", "amp", "AMP", "Amp"); + validateServiceIdSetting("Amplify", "amplify", "AMPLIFY", "Amplify"); + validateServiceIdSetting("AmplifyBackend", "amplifybackend", "AMPLIFYBACKEND", "AmplifyBackend"); + validateServiceIdSetting("AmplifyUIBuilder", "amplifyuibuilder", "AMPLIFYUIBUILDER", "AmplifyUiBuilder"); + validateServiceIdSetting("API Gateway", "api_gateway", "API_GATEWAY", "ApiGateway"); + // Kotlin uses ApiGatewayManagement + validateServiceIdSetting("ApiGatewayManagementApi", "apigatewaymanagementapi", "APIGATEWAYMANAGEMENTAPI", + "ApiGatewayManagementApi"); + validateServiceIdSetting("ApiGatewayV2", "apigatewayv2", "APIGATEWAYV2", "ApiGatewayV2"); + validateServiceIdSetting("AppConfig", "appconfig", "APPCONFIG", "AppConfig"); + validateServiceIdSetting("AppConfigData", "appconfigdata", "APPCONFIGDATA", "AppConfigData"); + validateServiceIdSetting("AppFabric", "appfabric", "APPFABRIC", "AppFabric"); + validateServiceIdSetting("Appflow", "appflow", "APPFLOW", "Appflow"); + validateServiceIdSetting("AppIntegrations", "appintegrations", "APPINTEGRATIONS", "AppIntegrations"); + validateServiceIdSetting("Application Auto Scaling", "application_auto_scaling", "APPLICATION_AUTO_SCALING", "ApplicationAutoScaling"); + validateServiceIdSetting("Application Insights", "application_insights", "APPLICATION_INSIGHTS", "ApplicationInsights"); + validateServiceIdSetting("ApplicationCostProfiler", "applicationcostprofiler", "APPLICATIONCOSTPROFILER", "ApplicationCostProfiler"); + validateServiceIdSetting("App Mesh", "app_mesh", "APP_MESH", "AppMesh"); + validateServiceIdSetting("AppRunner", "apprunner", "APPRUNNER", "AppRunner"); + validateServiceIdSetting("AppStream", "appstream", "APPSTREAM", "AppStream"); + validateServiceIdSetting("AppSync", "appsync", "APPSYNC", "AppSync"); + validateServiceIdSetting("ARC Zonal Shift", "arc_zonal_shift", "ARC_ZONAL_SHIFT", "ArcZonalShift"); + validateServiceIdSetting("Artifact", "artifact", "ARTIFACT", "Artifact"); + validateServiceIdSetting("Athena", "athena", "ATHENA", "Athena"); + validateServiceIdSetting("AuditManager", "auditmanager", "AUDITMANAGER", "AuditManager"); + validateServiceIdSetting("Auto Scaling", "auto_scaling", "AUTO_SCALING", "AutoScaling"); + validateServiceIdSetting("Auto Scaling Plans", "auto_scaling_plans", "AUTO_SCALING_PLANS", "AutoScalingPlans"); + validateServiceIdSetting("b2bi", "b2bi", "B2BI", "B2Bi"); + validateServiceIdSetting("Backup", "backup", "BACKUP", "Backup"); + validateServiceIdSetting("Backup Gateway", "backup_gateway", "BACKUP_GATEWAY", "BackupGateway"); + validateServiceIdSetting("BackupStorage", "backupstorage", "BACKUPSTORAGE", "BackupStorage"); + validateServiceIdSetting("Batch", "batch", "BATCH", "Batch"); + validateServiceIdSetting("BCM Data Exports", "bcm_data_exports", "BCM_DATA_EXPORTS", "BcmDataExports"); + validateServiceIdSetting("Bedrock", "bedrock", "BEDROCK", "Bedrock"); + validateServiceIdSetting("Bedrock Agent", "bedrock_agent", "BEDROCK_AGENT", "BedrockAgent"); + validateServiceIdSetting("Bedrock Agent Runtime", "bedrock_agent_runtime", "BEDROCK_AGENT_RUNTIME", "BedrockAgentRuntime"); + validateServiceIdSetting("Bedrock Runtime", "bedrock_runtime", "BEDROCK_RUNTIME", "BedrockRuntime"); + validateServiceIdSetting("billingconductor", "billingconductor", "BILLINGCONDUCTOR", "Billingconductor"); + validateServiceIdSetting("Braket", "braket", "BRAKET", "Braket"); + validateServiceIdSetting("Budgets", "budgets", "BUDGETS", "Budgets"); + validateServiceIdSetting("Cost Explorer", "cost_explorer", "COST_EXPLORER", "CostExplorer"); + validateServiceIdSetting("chatbot", "chatbot", "CHATBOT", "Chatbot"); + validateServiceIdSetting("Chime", "chime", "CHIME", "Chime"); + validateServiceIdSetting("Chime SDK Identity", "chime_sdk_identity", "CHIME_SDK_IDENTITY", "ChimeSdkIdentity"); + validateServiceIdSetting("Chime SDK Media Pipelines", "chime_sdk_media_pipelines", "CHIME_SDK_MEDIA_PIPELINES", "ChimeSdkMediaPipelines"); + validateServiceIdSetting("Chime SDK Meetings", "chime_sdk_meetings", "CHIME_SDK_MEETINGS", "ChimeSdkMeetings"); + validateServiceIdSetting("Chime SDK Messaging", "chime_sdk_messaging", "CHIME_SDK_MESSAGING", "ChimeSdkMessaging"); + validateServiceIdSetting("Chime SDK Voice", "chime_sdk_voice", "CHIME_SDK_VOICE", "ChimeSdkVoice"); + validateServiceIdSetting("CleanRooms", "cleanrooms", "CLEANROOMS", "CleanRooms"); + validateServiceIdSetting("CleanRoomsML", "cleanroomsml", "CLEANROOMSML", "CleanRoomsMl"); + validateServiceIdSetting("Cloud9", "cloud9", "CLOUD9", "Cloud9"); + validateServiceIdSetting("CloudControl", "cloudcontrol", "CLOUDCONTROL", "CloudControl"); + validateServiceIdSetting("CloudDirectory", "clouddirectory", "CLOUDDIRECTORY", "CloudDirectory"); + validateServiceIdSetting("CloudFormation", "cloudformation", "CLOUDFORMATION", "CloudFormation"); + validateServiceIdSetting("CloudFront", "cloudfront", "CLOUDFRONT", "CloudFront"); + validateServiceIdSetting("CloudFront KeyValueStore", "cloudfront_keyvaluestore", "CLOUDFRONT_KEYVALUESTORE", "CloudFrontKeyValueStore"); + validateServiceIdSetting("CloudHSM", "cloudhsm", "CLOUDHSM", "CloudHsm"); + validateServiceIdSetting("CloudHSM V2", "cloudhsm_v2", "CLOUDHSM_V2", "CloudHsmV2"); + validateServiceIdSetting("CloudSearch", "cloudsearch", "CLOUDSEARCH", "CloudSearch"); + validateServiceIdSetting("CloudSearch Domain", "cloudsearch_domain", "CLOUDSEARCH_DOMAIN", "CloudSearchDomain"); + validateServiceIdSetting("CloudTrail", "cloudtrail", "CLOUDTRAIL", "CloudTrail"); + validateServiceIdSetting("CloudTrail Data", "cloudtrail_data", "CLOUDTRAIL_DATA", "CloudTrailData"); + validateServiceIdSetting("CloudWatch", "cloudwatch", "CLOUDWATCH", "CloudWatch"); + validateServiceIdSetting("codeartifact", "codeartifact", "CODEARTIFACT", "Codeartifact"); + validateServiceIdSetting("CodeBuild", "codebuild", "CODEBUILD", "CodeBuild"); + validateServiceIdSetting("CodeCatalyst", "codecatalyst", "CODECATALYST", "CodeCatalyst"); + validateServiceIdSetting("CodeCommit", "codecommit", "CODECOMMIT", "CodeCommit"); + validateServiceIdSetting("CodeDeploy", "codedeploy", "CODEDEPLOY", "CodeDeploy"); + validateServiceIdSetting("CodeGuru Reviewer", "codeguru_reviewer", "CODEGURU_REVIEWER", "CodeGuruReviewer"); + validateServiceIdSetting("CodeGuru Security", "codeguru_security", "CODEGURU_SECURITY", "CodeGuruSecurity"); + validateServiceIdSetting("CodeGuruProfiler", "codeguruprofiler", "CODEGURUPROFILER", "CodeGuruProfiler"); + validateServiceIdSetting("CodePipeline", "codepipeline", "CODEPIPELINE", "CodePipeline"); + validateServiceIdSetting("CodeStar", "codestar", "CODESTAR", "CodeStar"); + validateServiceIdSetting("CodeStar connections", "codestar_connections", "CODESTAR_CONNECTIONS", "CodeStarConnections"); + validateServiceIdSetting("codestar notifications", "codestar_notifications", "CODESTAR_NOTIFICATIONS", "CodestarNotifications"); + validateServiceIdSetting("Cognito Identity", "cognito_identity", "COGNITO_IDENTITY", "CognitoIdentity"); + validateServiceIdSetting("Cognito Identity Provider", "cognito_identity_provider", "COGNITO_IDENTITY_PROVIDER", "CognitoIdentityProvider"); + validateServiceIdSetting("Cognito Sync", "cognito_sync", "COGNITO_SYNC", "CognitoSync"); + validateServiceIdSetting("Comprehend", "comprehend", "COMPREHEND", "Comprehend"); + validateServiceIdSetting("ComprehendMedical", "comprehendmedical", "COMPREHENDMEDICAL", "ComprehendMedical"); + validateServiceIdSetting("Compute Optimizer", "compute_optimizer", "COMPUTE_OPTIMIZER", "ComputeOptimizer"); + validateServiceIdSetting("Config Service", "config_service", "CONFIG_SERVICE", "Config"); + validateServiceIdSetting("Connect", "connect", "CONNECT", "Connect"); + validateServiceIdSetting("Connect Contact Lens", "connect_contact_lens", "CONNECT_CONTACT_LENS", "ConnectContactLens"); + validateServiceIdSetting("ConnectCampaigns", "connectcampaigns", "CONNECTCAMPAIGNS", "ConnectCampaigns"); + validateServiceIdSetting("ConnectCases", "connectcases", "CONNECTCASES", "ConnectCases"); + validateServiceIdSetting("ConnectParticipant", "connectparticipant", "CONNECTPARTICIPANT", "ConnectParticipant"); + validateServiceIdSetting("ControlTower", "controltower", "CONTROLTOWER", "ControlTower"); + validateServiceIdSetting("Cost Optimization Hub", "cost_optimization_hub", "COST_OPTIMIZATION_HUB", "CostOptimizationHub"); + validateServiceIdSetting("Cost and Usage Report Service", "cost_and_usage_report_service", "COST_AND_USAGE_REPORT_SERVICE", "CostAndUsageReport"); + validateServiceIdSetting("Customer Profiles", "customer_profiles", "CUSTOMER_PROFILES", "CustomerProfiles"); + validateServiceIdSetting("DataBrew", "databrew", "DATABREW", "DataBrew"); + validateServiceIdSetting("DataExchange", "dataexchange", "DATAEXCHANGE", "DataExchange"); + validateServiceIdSetting("Data Pipeline", "data_pipeline", "DATA_PIPELINE", "DataPipeline"); + validateServiceIdSetting("DataSync", "datasync", "DATASYNC", "DataSync"); + validateServiceIdSetting("DataZone", "datazone", "DATAZONE", "DataZone"); + validateServiceIdSetting("DAX", "dax", "DAX", "Dax"); + validateServiceIdSetting("Detective", "detective", "DETECTIVE", "Detective"); + validateServiceIdSetting("Device Farm", "device_farm", "DEVICE_FARM", "DeviceFarm"); + validateServiceIdSetting("DevOps Guru", "devops_guru", "DEVOPS_GURU", "DevOpsGuru"); + validateServiceIdSetting("Direct Connect", "direct_connect", "DIRECT_CONNECT", "DirectConnect"); + validateServiceIdSetting("Application Discovery Service", "application_discovery_service", "APPLICATION_DISCOVERY_SERVICE", "ApplicationDiscovery"); + validateServiceIdSetting("DLM", "dlm", "DLM", "Dlm"); + validateServiceIdSetting("Database Migration Service", "database_migration_service", "DATABASE_MIGRATION_SERVICE", "DatabaseMigration"); + validateServiceIdSetting("DocDB", "docdb", "DOCDB", "DocDb"); + validateServiceIdSetting("DocDB Elastic", "docdb_elastic", "DOCDB_ELASTIC", "DocDbElastic"); + validateServiceIdSetting("drs", "drs", "DRS", "Drs"); + validateServiceIdSetting("Directory Service", "directory_service", "DIRECTORY_SERVICE", "Directory"); + validateServiceIdSetting("DynamoDB", "dynamodb", "DYNAMODB", "DynamoDb"); + validateServiceIdSetting("DynamoDB Streams", "dynamodb_streams", "DYNAMODB_STREAMS", "DynamoDbStreams"); + validateServiceIdSetting("EBS", "ebs", "EBS", "Ebs"); + validateServiceIdSetting("EC2", "ec2", "EC2", "Ec2"); + validateServiceIdSetting("EC2 Instance Connect", "ec2_instance_connect", "EC2_INSTANCE_CONNECT", "Ec2InstanceConnect"); + validateServiceIdSetting("ECR", "ecr", "ECR", "Ecr"); + validateServiceIdSetting("ECR PUBLIC", "ecr_public", "ECR_PUBLIC", "EcrPublic"); + validateServiceIdSetting("ECS", "ecs", "ECS", "Ecs"); + validateServiceIdSetting("EFS", "efs", "EFS", "Efs"); + validateServiceIdSetting("EKS", "eks", "EKS", "Eks"); + validateServiceIdSetting("EKS Auth", "eks_auth", "EKS_AUTH", "EksAuth"); + validateServiceIdSetting("Elastic Inference", "elastic_inference", "ELASTIC_INFERENCE", "ElasticInference"); + validateServiceIdSetting("ElastiCache", "elasticache", "ELASTICACHE", "ElastiCache"); + validateServiceIdSetting("Elastic Beanstalk", "elastic_beanstalk", "ELASTIC_BEANSTALK", "ElasticBeanstalk"); + validateServiceIdSetting("Elastic Transcoder", "elastic_transcoder", "ELASTIC_TRANSCODER", "ElasticTranscoder"); + validateServiceIdSetting("Elastic Load Balancing", "elastic_load_balancing", "ELASTIC_LOAD_BALANCING", "ElasticLoadBalancing"); + validateServiceIdSetting("Elastic Load Balancing v2", "elastic_load_balancing_v2", "ELASTIC_LOAD_BALANCING_V2", "ElasticLoadBalancingV2"); + validateServiceIdSetting("EMR", "emr", "EMR", "Emr"); + validateServiceIdSetting("EMR containers", "emr_containers", "EMR_CONTAINERS", "EmrContainers"); + validateServiceIdSetting("EMR Serverless", "emr_serverless", "EMR_SERVERLESS", "EmrServerless"); + validateServiceIdSetting("EntityResolution", "entityresolution", "ENTITYRESOLUTION", "EntityResolution"); + validateServiceIdSetting("Elasticsearch Service", "elasticsearch_service", "ELASTICSEARCH_SERVICE", "Elasticsearch"); + validateServiceIdSetting("EventBridge", "eventbridge", "EVENTBRIDGE", "EventBridge"); + validateServiceIdSetting("Evidently", "evidently", "EVIDENTLY", "Evidently"); + validateServiceIdSetting("finspace", "finspace", "FINSPACE", "Finspace"); + validateServiceIdSetting("finspace data", "finspace_data", "FINSPACE_DATA", "FinspaceData"); + validateServiceIdSetting("Firehose", "firehose", "FIREHOSE", "Firehose"); + validateServiceIdSetting("fis", "fis", "FIS", "Fis"); + validateServiceIdSetting("FMS", "fms", "FMS", "Fms"); + validateServiceIdSetting("forecast", "forecast", "FORECAST", "Forecast"); + validateServiceIdSetting("forecastquery", "forecastquery", "FORECASTQUERY", "Forecastquery"); + validateServiceIdSetting("FraudDetector", "frauddetector", "FRAUDDETECTOR", "FraudDetector"); + validateServiceIdSetting("FreeTier", "freetier", "FREETIER", "FreeTier"); + validateServiceIdSetting("FSx", "fsx", "FSX", "FSx"); + validateServiceIdSetting("GameLift", "gamelift", "GAMELIFT", "GameLift"); + validateServiceIdSetting("Glacier", "glacier", "GLACIER", "Glacier"); + validateServiceIdSetting("Global Accelerator", "global_accelerator", "GLOBAL_ACCELERATOR", "GlobalAccelerator"); + validateServiceIdSetting("Glue", "glue", "GLUE", "Glue"); + validateServiceIdSetting("grafana", "grafana", "GRAFANA", "Grafana"); + validateServiceIdSetting("Greengrass", "greengrass", "GREENGRASS", "Greengrass"); + validateServiceIdSetting("GreengrassV2", "greengrassv2", "GREENGRASSV2", "GreengrassV2"); + validateServiceIdSetting("GroundStation", "groundstation", "GROUNDSTATION", "GroundStation"); + validateServiceIdSetting("GuardDuty", "guardduty", "GUARDDUTY", "GuardDuty"); + validateServiceIdSetting("Health", "health", "HEALTH", "Health"); + validateServiceIdSetting("HealthLake", "healthlake", "HEALTHLAKE", "HealthLake"); + validateServiceIdSetting("Honeycode", "honeycode", "HONEYCODE", "Honeycode"); + validateServiceIdSetting("IAM", "iam", "IAM", "Iam"); + validateServiceIdSetting("identitystore", "identitystore", "IDENTITYSTORE", "Identitystore"); + validateServiceIdSetting("imagebuilder", "imagebuilder", "IMAGEBUILDER", "Imagebuilder"); + validateServiceIdSetting("ImportExport", "importexport", "IMPORTEXPORT", "ImportExport"); + validateServiceIdSetting("Inspector", "inspector", "INSPECTOR", "Inspector"); + validateServiceIdSetting("Inspector Scan", "inspector_scan", "INSPECTOR_SCAN", "InspectorScan"); + validateServiceIdSetting("Inspector2", "inspector2", "INSPECTOR2", "Inspector2"); + validateServiceIdSetting("InternetMonitor", "internetmonitor", "INTERNETMONITOR", "InternetMonitor"); + validateServiceIdSetting("IoT", "iot", "IOT", "Iot"); + validateServiceIdSetting("IoT Data Plane", "iot_data_plane", "IOT_DATA_PLANE", "IotDataPlane"); + validateServiceIdSetting("IoT Jobs Data Plane", "iot_jobs_data_plane", "IOT_JOBS_DATA_PLANE", "IotJobsDataPlane"); + validateServiceIdSetting("IoT 1Click Devices Service", "iot_1click_devices_service", "IOT_1CLICK_DEVICES_SERVICE", "Iot1ClickDevices"); + validateServiceIdSetting("IoT 1Click Projects", "iot_1click_projects", "IOT_1CLICK_PROJECTS", "Iot1ClickProjects"); + // Kotlin uses Iot instead of IoT, wherever that appears + validateServiceIdSetting("IoTAnalytics", "iotanalytics", "IOTANALYTICS", "IoTAnalytics"); + validateServiceIdSetting("IotDeviceAdvisor", "iotdeviceadvisor", "IOTDEVICEADVISOR", "IotDeviceAdvisor"); + validateServiceIdSetting("IoT Events", "iot_events", "IOT_EVENTS", "IotEvents"); + validateServiceIdSetting("IoT Events Data", "iot_events_data", "IOT_EVENTS_DATA", "IotEventsData"); + validateServiceIdSetting("IoTFleetHub", "iotfleethub", "IOTFLEETHUB", "IoTFleetHub"); + validateServiceIdSetting("IoTFleetWise", "iotfleetwise", "IOTFLEETWISE", "IoTFleetWise"); + validateServiceIdSetting("IoTSecureTunneling", "iotsecuretunneling", "IOTSECURETUNNELING", "IoTSecureTunneling"); + validateServiceIdSetting("IoTSiteWise", "iotsitewise", "IOTSITEWISE", "IoTSiteWise"); + validateServiceIdSetting("IoTThingsGraph", "iotthingsgraph", "IOTTHINGSGRAPH", "IoTThingsGraph"); + validateServiceIdSetting("IoTTwinMaker", "iottwinmaker", "IOTTWINMAKER", "IoTTwinMaker"); + validateServiceIdSetting("IoT Wireless", "iot_wireless", "IOT_WIRELESS", "IotWireless"); + validateServiceIdSetting("ivs", "ivs", "IVS", "Ivs"); + validateServiceIdSetting("IVS RealTime", "ivs_realtime", "IVS_REALTIME", "IvsRealTime"); + validateServiceIdSetting("ivschat", "ivschat", "IVSCHAT", "Ivschat"); + validateServiceIdSetting("Kafka", "kafka", "KAFKA", "Kafka"); + validateServiceIdSetting("KafkaConnect", "kafkaconnect", "KAFKACONNECT", "KafkaConnect"); + validateServiceIdSetting("kendra", "kendra", "KENDRA", "Kendra"); + validateServiceIdSetting("Kendra Ranking", "kendra_ranking", "KENDRA_RANKING", "KendraRanking"); + validateServiceIdSetting("Keyspaces", "keyspaces", "KEYSPACES", "Keyspaces"); + validateServiceIdSetting("Kinesis", "kinesis", "KINESIS", "Kinesis"); + validateServiceIdSetting("Kinesis Video Archived Media", "kinesis_video_archived_media", "KINESIS_VIDEO_ARCHIVED_MEDIA", "KinesisVideoArchivedMedia"); + validateServiceIdSetting("Kinesis Video Media", "kinesis_video_media", "KINESIS_VIDEO_MEDIA", "KinesisVideoMedia"); + validateServiceIdSetting("Kinesis Video Signaling", "kinesis_video_signaling", "KINESIS_VIDEO_SIGNALING", "KinesisVideoSignaling"); + validateServiceIdSetting("Kinesis Video WebRTC Storage", "kinesis_video_webrtc_storage", "KINESIS_VIDEO_WEBRTC_STORAGE", "KinesisVideoWebRtcStorage"); + validateServiceIdSetting("Kinesis Analytics", "kinesis_analytics", "KINESIS_ANALYTICS", "KinesisAnalytics"); + validateServiceIdSetting("Kinesis Analytics V2", "kinesis_analytics_v2", "KINESIS_ANALYTICS_V2", "KinesisAnalyticsV2"); + validateServiceIdSetting("Kinesis Video", "kinesis_video", "KINESIS_VIDEO", "KinesisVideo"); + validateServiceIdSetting("KMS", "kms", "KMS", "Kms"); + validateServiceIdSetting("LakeFormation", "lakeformation", "LAKEFORMATION", "LakeFormation"); + validateServiceIdSetting("Lambda", "lambda", "LAMBDA", "Lambda"); + validateServiceIdSetting("Launch Wizard", "launch_wizard", "LAUNCH_WIZARD", "LaunchWizard"); + validateServiceIdSetting("Lex Model Building Service", "lex_model_building_service", "LEX_MODEL_BUILDING_SERVICE", "LexModelBuilding"); + validateServiceIdSetting("Lex Runtime Service", "lex_runtime_service", "LEX_RUNTIME_SERVICE", "LexRuntime"); + validateServiceIdSetting("Lex Models V2", "lex_models_v2", "LEX_MODELS_V2", "LexModelsV2"); + validateServiceIdSetting("Lex Runtime V2", "lex_runtime_v2", "LEX_RUNTIME_V2", "LexRuntimeV2"); + validateServiceIdSetting("License Manager", "license_manager", "LICENSE_MANAGER", "LicenseManager"); + validateServiceIdSetting("License Manager Linux Subscriptions", "license_manager_linux_subscriptions", "LICENSE_MANAGER_LINUX_SUBSCRIPTIONS", "LicenseManagerLinuxSubscriptions"); + validateServiceIdSetting("License Manager User Subscriptions", "license_manager_user_subscriptions", "LICENSE_MANAGER_USER_SUBSCRIPTIONS", "LicenseManagerUserSubscriptions"); + validateServiceIdSetting("Lightsail", "lightsail", "LIGHTSAIL", "Lightsail"); + validateServiceIdSetting("Location", "location", "LOCATION", "Location"); + validateServiceIdSetting("CloudWatch Logs", "cloudwatch_logs", "CLOUDWATCH_LOGS", "CloudWatchLogs"); + validateServiceIdSetting("CloudWatch Logs", "cloudwatch_logs", "CLOUDWATCH_LOGS", "CloudWatchLogs"); + validateServiceIdSetting("LookoutEquipment", "lookoutequipment", "LOOKOUTEQUIPMENT", "LookoutEquipment"); + validateServiceIdSetting("LookoutMetrics", "lookoutmetrics", "LOOKOUTMETRICS", "LookoutMetrics"); + validateServiceIdSetting("LookoutVision", "lookoutvision", "LOOKOUTVISION", "LookoutVision"); + validateServiceIdSetting("m2", "m2", "M2", "M2"); + validateServiceIdSetting("Machine Learning", "machine_learning", "MACHINE_LEARNING", "MachineLearning"); + validateServiceIdSetting("Macie2", "macie2", "MACIE2", "Macie2"); + validateServiceIdSetting("ManagedBlockchain", "managedblockchain", "MANAGEDBLOCKCHAIN", "ManagedBlockchain"); + validateServiceIdSetting("ManagedBlockchain Query", "managedblockchain_query", "MANAGEDBLOCKCHAIN_QUERY", "ManagedBlockchainQuery"); + validateServiceIdSetting("Marketplace Agreement", "marketplace_agreement", "MARKETPLACE_AGREEMENT", "MarketplaceAgreement"); + validateServiceIdSetting("Marketplace Catalog", "marketplace_catalog", "MARKETPLACE_CATALOG", "MarketplaceCatalog"); + validateServiceIdSetting("Marketplace Deployment", "marketplace_deployment", "MARKETPLACE_DEPLOYMENT", "MarketplaceDeployment"); + validateServiceIdSetting("Marketplace Entitlement Service", "marketplace_entitlement_service", "MARKETPLACE_ENTITLEMENT_SERVICE", "MarketplaceEntitlement"); + validateServiceIdSetting("Marketplace Commerce Analytics", "marketplace_commerce_analytics", "MARKETPLACE_COMMERCE_ANALYTICS", "MarketplaceCommerceAnalytics"); + validateServiceIdSetting("MediaConnect", "mediaconnect", "MEDIACONNECT", "MediaConnect"); + validateServiceIdSetting("MediaConvert", "mediaconvert", "MEDIACONVERT", "MediaConvert"); + validateServiceIdSetting("MediaLive", "medialive", "MEDIALIVE", "MediaLive"); + validateServiceIdSetting("MediaPackage", "mediapackage", "MEDIAPACKAGE", "MediaPackage"); + validateServiceIdSetting("MediaPackage Vod", "mediapackage_vod", "MEDIAPACKAGE_VOD", "MediaPackageVod"); + validateServiceIdSetting("MediaPackageV2", "mediapackagev2", "MEDIAPACKAGEV2", "MediaPackageV2"); + validateServiceIdSetting("MediaStore", "mediastore", "MEDIASTORE", "MediaStore"); + validateServiceIdSetting("MediaStore Data", "mediastore_data", "MEDIASTORE_DATA", "MediaStoreData"); + validateServiceIdSetting("MediaTailor", "mediatailor", "MEDIATAILOR", "MediaTailor"); + validateServiceIdSetting("Medical Imaging", "medical_imaging", "MEDICAL_IMAGING", "MedicalImaging"); + validateServiceIdSetting("MemoryDB", "memorydb", "MEMORYDB", "MemoryDb"); + validateServiceIdSetting("Marketplace Metering", "marketplace_metering", "MARKETPLACE_METERING", "MarketplaceMetering"); + validateServiceIdSetting("Migration Hub", "migration_hub", "MIGRATION_HUB", "MigrationHub"); + validateServiceIdSetting("mgn", "mgn", "MGN", "Mgn"); + validateServiceIdSetting("Migration Hub Refactor Spaces", "migration_hub_refactor_spaces", "MIGRATION_HUB_REFACTOR_SPACES", "MigrationHubRefactorSpaces"); + validateServiceIdSetting("MigrationHub Config", "migrationhub_config", "MIGRATIONHUB_CONFIG", "MigrationHubConfig"); + validateServiceIdSetting("MigrationHubOrchestrator", "migrationhuborchestrator", "MIGRATIONHUBORCHESTRATOR", "MigrationHubOrchestrator"); + validateServiceIdSetting("MigrationHubStrategy", "migrationhubstrategy", "MIGRATIONHUBSTRATEGY", "MigrationHubStrategy"); + validateServiceIdSetting("Mobile", "mobile", "MOBILE", "Mobile"); + validateServiceIdSetting("mq", "mq", "MQ", "Mq"); + validateServiceIdSetting("MTurk", "mturk", "MTURK", "MTurk"); + validateServiceIdSetting("MWAA", "mwaa", "MWAA", "Mwaa"); + validateServiceIdSetting("Neptune", "neptune", "NEPTUNE", "Neptune"); + validateServiceIdSetting("Neptune Graph", "neptune_graph", "NEPTUNE_GRAPH", "NeptuneGraph"); + validateServiceIdSetting("neptunedata", "neptunedata", "NEPTUNEDATA", "Neptunedata"); + validateServiceIdSetting("Network Firewall", "network_firewall", "NETWORK_FIREWALL", "NetworkFirewall"); + validateServiceIdSetting("NetworkManager", "networkmanager", "NETWORKMANAGER", "NetworkManager"); + validateServiceIdSetting("NetworkMonitor", "networkmonitor", "NETWORKMONITOR", "NetworkMonitor"); + validateServiceIdSetting("nimble", "nimble", "NIMBLE", "Nimble"); + validateServiceIdSetting("OAM", "oam", "OAM", "Oam"); + validateServiceIdSetting("Omics", "omics", "OMICS", "Omics"); + validateServiceIdSetting("OpenSearch", "opensearch", "OPENSEARCH", "OpenSearch"); + validateServiceIdSetting("OpenSearchServerless", "opensearchserverless", "OPENSEARCHSERVERLESS", "OpenSearchServerless"); + validateServiceIdSetting("OpsWorks", "opsworks", "OPSWORKS", "OpsWorks"); + validateServiceIdSetting("OpsWorksCM", "opsworkscm", "OPSWORKSCM", "OpsWorksCm"); + validateServiceIdSetting("Organizations", "organizations", "ORGANIZATIONS", "Organizations"); + validateServiceIdSetting("OSIS", "osis", "OSIS", "Osis"); + validateServiceIdSetting("Outposts", "outposts", "OUTPOSTS", "Outposts"); + validateServiceIdSetting("p8data", "p8data", "P8DATA", "P8Data"); + validateServiceIdSetting("Panorama", "panorama", "PANORAMA", "Panorama"); + validateServiceIdSetting("Payment Cryptography", "payment_cryptography", "PAYMENT_CRYPTOGRAPHY", "PaymentCryptography"); + validateServiceIdSetting("Payment Cryptography Data", "payment_cryptography_data", "PAYMENT_CRYPTOGRAPHY_DATA", "PaymentCryptographyData"); + validateServiceIdSetting("Pca Connector Ad", "pca_connector_ad", "PCA_CONNECTOR_AD", "PcaConnectorAd"); + validateServiceIdSetting("Personalize", "personalize", "PERSONALIZE", "Personalize"); + validateServiceIdSetting("Personalize Events", "personalize_events", "PERSONALIZE_EVENTS", "PersonalizeEvents"); + validateServiceIdSetting("Personalize Runtime", "personalize_runtime", "PERSONALIZE_RUNTIME", "PersonalizeRuntime"); + validateServiceIdSetting("PI", "pi", "PI", "Pi"); + validateServiceIdSetting("Pinpoint", "pinpoint", "PINPOINT", "Pinpoint"); + validateServiceIdSetting("Pinpoint Email", "pinpoint_email", "PINPOINT_EMAIL", "PinpointEmail"); + validateServiceIdSetting("Pinpoint SMS Voice", "pinpoint_sms_voice", "PINPOINT_SMS_VOICE", "PinpointSmsVoice"); + validateServiceIdSetting("Pinpoint SMS Voice V2", "pinpoint_sms_voice_v2", "PINPOINT_SMS_VOICE_V2", "PinpointSmsVoiceV2"); + validateServiceIdSetting("Pipes", "pipes", "PIPES", "Pipes"); + validateServiceIdSetting("Polly", "polly", "POLLY", "Polly"); + validateServiceIdSetting("Pricing", "pricing", "PRICING", "Pricing"); + validateServiceIdSetting("PrivateNetworks", "privatenetworks", "PRIVATENETWORKS", "PrivateNetworks"); + validateServiceIdSetting("Proton", "proton", "PROTON", "Proton"); + validateServiceIdSetting("QBusiness", "qbusiness", "QBUSINESS", "QBusiness"); + validateServiceIdSetting("QConnect", "qconnect", "QCONNECT", "QConnect"); + validateServiceIdSetting("QLDB", "qldb", "QLDB", "Qldb"); + validateServiceIdSetting("QLDB Session", "qldb_session", "QLDB_SESSION", "QldbSession"); + validateServiceIdSetting("QuickSight", "quicksight", "QUICKSIGHT", "QuickSight"); + validateServiceIdSetting("RAM", "ram", "RAM", "Ram"); + validateServiceIdSetting("rbin", "rbin", "RBIN", "Rbin"); + validateServiceIdSetting("RDS", "rds", "RDS", "Rds"); + validateServiceIdSetting("RDS Data", "rds_data", "RDS_DATA", "RdsData"); + validateServiceIdSetting("Redshift", "redshift", "REDSHIFT", "Redshift"); + validateServiceIdSetting("Redshift Data", "redshift_data", "REDSHIFT_DATA", "RedshiftData"); + validateServiceIdSetting("Redshift Serverless", "redshift_serverless", "REDSHIFT_SERVERLESS", "RedshiftServerless"); + validateServiceIdSetting("Rekognition", "rekognition", "REKOGNITION", "Rekognition"); + validateServiceIdSetting("repostspace", "repostspace", "REPOSTSPACE", "Repostspace"); + validateServiceIdSetting("resiliencehub", "resiliencehub", "RESILIENCEHUB", "Resiliencehub"); + validateServiceIdSetting("Resource Explorer 2", "resource_explorer_2", "RESOURCE_EXPLORER_2", "ResourceExplorer2"); + validateServiceIdSetting("Resource Groups", "resource_groups", "RESOURCE_GROUPS", "ResourceGroups"); + // Kotlin uses ResourceGroupsTagging + validateServiceIdSetting("Resource Groups Tagging API", "resource_groups_tagging_api", "RESOURCE_GROUPS_TAGGING_API", "ResourceGroupsTaggingApi"); + validateServiceIdSetting("RoboMaker", "robomaker", "ROBOMAKER", "RoboMaker"); + validateServiceIdSetting("RolesAnywhere", "rolesanywhere", "ROLESANYWHERE", "RolesAnywhere"); + validateServiceIdSetting("Route 53", "route_53", "ROUTE_53", "Route53"); + validateServiceIdSetting("Route53 Recovery Cluster", "route53_recovery_cluster", "ROUTE53_RECOVERY_CLUSTER", "Route53RecoveryCluster"); + validateServiceIdSetting("Route53 Recovery Control Config", "route53_recovery_control_config", "ROUTE53_RECOVERY_CONTROL_CONFIG", "Route53RecoveryControlConfig"); + validateServiceIdSetting("Route53 Recovery Readiness", "route53_recovery_readiness", "ROUTE53_RECOVERY_READINESS", "Route53RecoveryReadiness"); + validateServiceIdSetting("Route 53 Domains", "route_53_domains", "ROUTE_53_DOMAINS", "Route53Domains"); + validateServiceIdSetting("Route53Resolver", "route53resolver", "ROUTE53RESOLVER", "Route53Resolver"); + validateServiceIdSetting("RUM", "rum", "RUM", "Rum"); + validateServiceIdSetting("S3", "s3", "S3", "S3"); + validateServiceIdSetting("S3 Control", "s3_control", "S3_CONTROL", "S3Control"); + validateServiceIdSetting("S3Outposts", "s3outposts", "S3OUTPOSTS", "S3Outposts"); + validateServiceIdSetting("SageMaker", "sagemaker", "SAGEMAKER", "SageMaker"); + validateServiceIdSetting("SageMaker A2I Runtime", "sagemaker_a2i_runtime", "SAGEMAKER_A2I_RUNTIME", "SageMakerA2IRuntime"); + validateServiceIdSetting("Sagemaker Edge", "sagemaker_edge", "SAGEMAKER_EDGE", "SagemakerEdge"); + validateServiceIdSetting("SageMaker FeatureStore Runtime", "sagemaker_featurestore_runtime", "SAGEMAKER_FEATURESTORE_RUNTIME", "SageMakerFeatureStoreRuntime"); + validateServiceIdSetting("SageMaker Geospatial", "sagemaker_geospatial", "SAGEMAKER_GEOSPATIAL", "SageMakerGeospatial"); + validateServiceIdSetting("SageMaker Metrics", "sagemaker_metrics", "SAGEMAKER_METRICS", "SageMakerMetrics"); + validateServiceIdSetting("SageMaker Runtime", "sagemaker_runtime", "SAGEMAKER_RUNTIME", "SageMakerRuntime"); + validateServiceIdSetting("savingsplans", "savingsplans", "SAVINGSPLANS", "Savingsplans"); + validateServiceIdSetting("Scheduler", "scheduler", "SCHEDULER", "Scheduler"); + validateServiceIdSetting("schemas", "schemas", "SCHEMAS", "Schemas"); + validateServiceIdSetting("SimpleDB", "simpledb", "SIMPLEDB", "SimpleDb"); + validateServiceIdSetting("Secrets Manager", "secrets_manager", "SECRETS_MANAGER", "SecretsManager"); + validateServiceIdSetting("SecurityHub", "securityhub", "SECURITYHUB", "SecurityHub"); + validateServiceIdSetting("SecurityLake", "securitylake", "SECURITYLAKE", "SecurityLake"); + validateServiceIdSetting("ServerlessApplicationRepository", "serverlessapplicationrepository", "SERVERLESSAPPLICATIONREPOSITORY", "ServerlessApplicationRepository"); + validateServiceIdSetting("Service Quotas", "service_quotas", "SERVICE_QUOTAS", "ServiceQuotas"); + validateServiceIdSetting("Service Catalog", "service_catalog", "SERVICE_CATALOG", "ServiceCatalog"); + validateServiceIdSetting("Service Catalog AppRegistry", "service_catalog_appregistry", "SERVICE_CATALOG_APPREGISTRY", "ServiceCatalogAppRegistry"); + validateServiceIdSetting("ServiceDiscovery", "servicediscovery", "SERVICEDISCOVERY", "ServiceDiscovery"); + validateServiceIdSetting("SES", "ses", "SES", "Ses"); + validateServiceIdSetting("SESv2", "sesv2", "SESV2", "SesV2"); + validateServiceIdSetting("Shield", "shield", "SHIELD", "Shield"); + validateServiceIdSetting("signer", "signer", "SIGNER", "Signer"); + validateServiceIdSetting("SimSpaceWeaver", "simspaceweaver", "SIMSPACEWEAVER", "SimSpaceWeaver"); + validateServiceIdSetting("SMS", "sms", "SMS", "Sms"); + validateServiceIdSetting("Snow Device Management", "snow_device_management", "SNOW_DEVICE_MANAGEMENT", "SnowDeviceManagement"); + validateServiceIdSetting("Snowball", "snowball", "SNOWBALL", "Snowball"); + validateServiceIdSetting("SNS", "sns", "SNS", "Sns"); + validateServiceIdSetting("SQS", "sqs", "SQS", "Sqs"); + validateServiceIdSetting("SSM", "ssm", "SSM", "Ssm"); + validateServiceIdSetting("SSM Contacts", "ssm_contacts", "SSM_CONTACTS", "SsmContacts"); + validateServiceIdSetting("SSM Incidents", "ssm_incidents", "SSM_INCIDENTS", "SsmIncidents"); + validateServiceIdSetting("Ssm Sap", "ssm_sap", "SSM_SAP", "SsmSap"); + validateServiceIdSetting("SSO", "sso", "SSO", "Sso"); + validateServiceIdSetting("SSO Admin", "sso_admin", "SSO_ADMIN", "SsoAdmin"); + validateServiceIdSetting("SSO OIDC", "sso_oidc", "SSO_OIDC", "SsoOidc"); + validateServiceIdSetting("SFN", "sfn", "SFN", "Sfn"); + validateServiceIdSetting("Storage Gateway", "storage_gateway", "STORAGE_GATEWAY", "StorageGateway"); + validateServiceIdSetting("STS", "sts", "STS", "Sts"); + validateServiceIdSetting("SupplyChain", "supplychain", "SUPPLYCHAIN", "SupplyChain"); + validateServiceIdSetting("Support", "support", "SUPPORT", "Support"); + validateServiceIdSetting("Support App", "support_app", "SUPPORT_APP", "SupportApp"); + validateServiceIdSetting("SWF", "swf", "SWF", "Swf"); + validateServiceIdSetting("synthetics", "synthetics", "SYNTHETICS", "Synthetics"); + validateServiceIdSetting("Textract", "textract", "TEXTRACT", "Textract"); + validateServiceIdSetting("Timestream InfluxDB", "timestream_influxdb", "TIMESTREAM_INFLUXDB", "TimestreamInfluxDb"); + validateServiceIdSetting("Timestream Query", "timestream_query", "TIMESTREAM_QUERY", "TimestreamQuery"); + validateServiceIdSetting("Timestream Write", "timestream_write", "TIMESTREAM_WRITE", "TimestreamWrite"); + validateServiceIdSetting("tnb", "tnb", "TNB", "Tnb"); + validateServiceIdSetting("Transcribe", "transcribe", "TRANSCRIBE", "Transcribe"); + validateServiceIdSetting("Transfer", "transfer", "TRANSFER", "Transfer"); + validateServiceIdSetting("Translate", "translate", "TRANSLATE", "Translate"); + validateServiceIdSetting("TrustedAdvisor", "trustedadvisor", "TRUSTEDADVISOR", "TrustedAdvisor"); + validateServiceIdSetting("VerifiedPermissions", "verifiedpermissions", "VERIFIEDPERMISSIONS", "VerifiedPermissions"); + validateServiceIdSetting("Voice ID", "voice_id", "VOICE_ID", "VoiceId"); + validateServiceIdSetting("VPC Lattice", "vpc_lattice", "VPC_LATTICE", "VpcLattice"); + validateServiceIdSetting("WAF", "waf", "WAF", "Waf"); + validateServiceIdSetting("WAF Regional", "waf_regional", "WAF_REGIONAL", "WafRegional"); + validateServiceIdSetting("WAFV2", "wafv2", "WAFV2", "Wafv2"); + validateServiceIdSetting("WellArchitected", "wellarchitected", "WELLARCHITECTED", "WellArchitected"); + validateServiceIdSetting("Wisdom", "wisdom", "WISDOM", "Wisdom"); + validateServiceIdSetting("WorkDocs", "workdocs", "WORKDOCS", "WorkDocs"); + validateServiceIdSetting("WorkLink", "worklink", "WORKLINK", "WorkLink"); + validateServiceIdSetting("WorkMail", "workmail", "WORKMAIL", "WorkMail"); + validateServiceIdSetting("WorkMailMessageFlow", "workmailmessageflow", "WORKMAILMESSAGEFLOW", "WorkMailMessageFlow"); + validateServiceIdSetting("WorkSpaces", "workspaces", "WORKSPACES", "WorkSpaces"); + validateServiceIdSetting("WorkSpaces Thin Client", "workspaces_thin_client", "WORKSPACES_THIN_CLIENT", "WorkSpacesThinClient"); + validateServiceIdSetting("WorkSpaces Web", "workspaces_web", "WORKSPACES_WEB", "WorkSpacesWeb"); + } + + private void validateServiceIdSetting(String serviceId, + String profileProperty, + String environmentVariable, + String systemProperty) { + when(serviceMetadata.getServiceId()).thenReturn(serviceId); + assertThat(strat.getServiceNameForProfileFile()) + .as(() -> serviceId + " uses profile property " + profileProperty) + .isEqualTo(profileProperty); + assertThat(strat.getServiceNameForEnvironmentVariables()) + .as(() -> serviceId + " uses environment variable service name " + environmentVariable) + .isEqualTo(environmentVariable); + assertThat(strat.getServiceNameForSystemProperties()) + .as(() -> serviceId + " uses system property service name " + systemProperty) + .isEqualTo(systemProperty); + + } + private void verifyFailure(Consumer modelModifier) { IntermediateModel model = new IntermediateModel(); model.setMetadata(new Metadata()); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java index 8e732257bf2f..92a36dc95428 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java @@ -12,6 +12,7 @@ import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -26,6 +27,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; @@ -57,13 +59,13 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); } @Override @@ -74,7 +76,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -89,6 +91,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return result.build(); }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -176,6 +194,6 @@ private List internalPlugins(SdkClientConfiguration config) { protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java index 95d364ad82a6..550968449ff0 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java @@ -14,6 +14,7 @@ import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.codegen.poet.plugins.InternalTestPlugin1; import software.amazon.awssdk.codegen.poet.plugins.InternalTestPlugin2; @@ -31,6 +32,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; @@ -163,6 +165,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.RETRY_POLICY, MyServiceRetryPolicy.resolveRetryPolicy(config)); } builder.option(SdkClientOption.SERVICE_CONFIGURATION, finalServiceConfig); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java index 1e8c9bf8af8c..abf3132c7518 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java @@ -12,6 +12,7 @@ import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointMode; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointModeResolver; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; @@ -30,6 +31,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.query.auth.scheme.QueryAuthSchemeProvider; import software.amazon.awssdk.services.query.auth.scheme.internal.QueryAuthSchemeInterceptor; @@ -62,13 +64,13 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); } @Override @@ -79,7 +81,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new QueryRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/query/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/query/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -100,6 +102,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.option(SdkClientOption.CLIENT_CONTEXT_PARAMS, clientContextParams.build()); builder.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE, resolveAccountIdEndpointMode(config)); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") + .serviceProfileProperty("query_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -208,15 +226,15 @@ private AccountIdEndpointMode resolveAccountIdEndpointMode(SdkClientConfiguratio AccountIdEndpointMode configuredMode = config.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE); if (configuredMode == null) { configuredMode = AccountIdEndpointModeResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)).defaultMode(AccountIdEndpointMode.PREFERRED) - .resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).defaultMode(AccountIdEndpointMode.PREFERRED) + .resolve(); } return configuredMode; } protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java index fb59451ec0f9..21854bd71571 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java @@ -10,6 +10,7 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -23,6 +24,7 @@ import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; @@ -53,9 +55,9 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); } @Override @@ -74,7 +76,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -89,6 +91,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return result.build(); }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java index 8dc2cc4702ca..f001f47d6824 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java @@ -12,6 +12,7 @@ import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -27,6 +28,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; @@ -59,14 +61,14 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); } @Override @@ -77,17 +79,17 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); interceptors = CollectionUtils.mergeLists(interceptors, config.option(SdkClientOption.EXECUTION_INTERCEPTORS)); ServiceConfiguration.Builder serviceConfigBuilder = ((ServiceConfiguration) config - .option(SdkClientOption.SERVICE_CONFIGURATION)).toBuilder(); + .option(SdkClientOption.SERVICE_CONFIGURATION)).toBuilder(); serviceConfigBuilder.profileFile(serviceConfigBuilder.profileFileSupplier() != null ? serviceConfigBuilder - .profileFileSupplier() : config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)); + .profileFileSupplier() : config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)); serviceConfigBuilder.profileName(serviceConfigBuilder.profileName() != null ? serviceConfigBuilder.profileName() : config - .option(SdkClientOption.PROFILE_NAME)); + .option(SdkClientOption.PROFILE_NAME)); ServiceConfiguration finalServiceConfig = serviceConfigBuilder.build(); SdkClientConfiguration.Builder builder = config.toBuilder(); builder.lazyOption(SdkClientOption.IDENTITY_PROVIDERS, c -> { @@ -104,6 +106,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.option(SdkClientOption.SERVICE_CONFIGURATION, finalServiceConfig); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -207,6 +225,6 @@ private List internalPlugins(SdkClientConfiguration config) { protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java index 15fd9fd8c702..5552d96a771f 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java @@ -10,6 +10,7 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -24,6 +25,7 @@ import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.database.auth.scheme.DatabaseAuthSchemeProvider; import software.amazon.awssdk.services.database.auth.scheme.internal.DatabaseAuthSchemeInterceptor; @@ -39,7 +41,7 @@ @Generated("software.amazon.awssdk:codegen") @SdkInternalApi abstract class DefaultDatabaseBaseClientBuilder, C> extends - AwsDefaultClientBuilder { + AwsDefaultClientBuilder { private final Map> additionalAuthSchemes = new HashMap<>(); @Override @@ -55,9 +57,9 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); } @Override @@ -68,7 +70,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new DatabaseRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -83,6 +85,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return result.build(); }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") + .serviceProfileProperty("database_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -132,7 +150,7 @@ protected SdkClientConfiguration invokePlugins(SdkClientConfiguration config) { List plugins = CollectionUtils.mergeLists(internalPlugins, externalPlugins); SdkClientConfiguration.Builder configuration = config.toBuilder(); DatabaseServiceClientConfigurationBuilder serviceConfigBuilder = new DatabaseServiceClientConfigurationBuilder( - configuration); + configuration); for (SdkPlugin plugin : plugins) { plugin.configureClient(serviceConfigBuilder); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java index 67ab4f471b17..9f49074aa7d7 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java @@ -9,6 +9,8 @@ import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; +import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -20,6 +22,7 @@ import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme; import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.identity.spi.IdentityProviders; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.database.auth.scheme.DatabaseAuthSchemeProvider; import software.amazon.awssdk.services.database.auth.scheme.internal.DatabaseAuthSchemeInterceptor; @@ -35,7 +38,7 @@ @Generated("software.amazon.awssdk:codegen") @SdkInternalApi abstract class DefaultDatabaseBaseClientBuilder, C> extends - AwsDefaultClientBuilder { + AwsDefaultClientBuilder { private final Map> additionalAuthSchemes = new HashMap<>(); @Override @@ -51,9 +54,9 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); } @Override @@ -64,7 +67,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new DatabaseRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -75,6 +78,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return result.build(); }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") + .serviceProfileProperty("database_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -120,7 +139,7 @@ protected SdkClientConfiguration invokePlugins(SdkClientConfiguration config) { List plugins = CollectionUtils.mergeLists(internalPlugins, externalPlugins); SdkClientConfiguration.Builder configuration = config.toBuilder(); DatabaseServiceClientConfigurationBuilder serviceConfigBuilder = new DatabaseServiceClientConfigurationBuilder( - configuration); + configuration); for (SdkPlugin plugin : plugins) { plugin.configureClient(serviceConfigBuilder); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java index 0c2fe0783f3a..6f11b3364aba 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java @@ -12,6 +12,7 @@ import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointMode; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointModeResolver; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; @@ -29,6 +30,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.query.auth.scheme.QueryAuthSchemeProvider; import software.amazon.awssdk.services.query.auth.scheme.internal.QueryAuthSchemeInterceptor; @@ -61,13 +63,13 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); } @Override @@ -78,7 +80,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new QueryRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/query/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/query/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -99,6 +101,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.option(SdkClientOption.CLIENT_CONTEXT_PARAMS, clientContextParams.build()); builder.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE, resolveAccountIdEndpointMode(config)); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") + .serviceProfileProperty("query_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -205,15 +223,15 @@ private AccountIdEndpointMode resolveAccountIdEndpointMode(SdkClientConfiguratio AccountIdEndpointMode configuredMode = config.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE); if (configuredMode == null) { configuredMode = AccountIdEndpointModeResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)).defaultMode(AccountIdEndpointMode.PREFERRED) - .resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).defaultMode(AccountIdEndpointMode.PREFERRED) + .resolve(); } return configuredMode; } protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java index 0caf3454a83d..e280e29cdc88 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java @@ -11,6 +11,7 @@ import software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -24,6 +25,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; import software.amazon.awssdk.services.json.endpoints.internal.JsonRequestSetEndpointInterceptor; @@ -51,12 +53,12 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) - .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) + .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); } @Override @@ -66,7 +68,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -81,6 +83,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return result.build(); }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -147,8 +165,8 @@ private List internalPlugins(SdkClientConfiguration config) { protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(SdkAdvancedClientOption.TOKEN_SIGNER), - "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java index a43c9c8548b2..ca26f0321aec 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java @@ -14,6 +14,7 @@ import software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.codegen.poet.plugins.InternalTestPlugin1; import software.amazon.awssdk.codegen.poet.plugins.InternalTestPlugin2; @@ -29,6 +30,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.endpoints.JsonClientContextParams; import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; @@ -156,6 +158,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.RETRY_POLICY, MyServiceRetryPolicy.resolveRetryPolicy(config)); } builder.option(SdkClientOption.SERVICE_CONFIGURATION, finalServiceConfig); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java index 0b78fc371faa..ef0dce52a8ce 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java @@ -12,6 +12,7 @@ import software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointMode; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointModeResolver; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; @@ -27,6 +28,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.query.endpoints.QueryClientContextParams; import software.amazon.awssdk.services.query.endpoints.QueryEndpointProvider; @@ -55,13 +57,13 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) - .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) + .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); } @Override @@ -71,7 +73,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new QueryRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/query/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/query/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -92,6 +94,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.option(SdkClientOption.CLIENT_CONTEXT_PARAMS, clientContextParams.build()); builder.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE, resolveAccountIdEndpointMode(config)); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") + .serviceProfileProperty("query_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -179,19 +197,19 @@ private AccountIdEndpointMode resolveAccountIdEndpointMode(SdkClientConfiguratio AccountIdEndpointMode configuredMode = config.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE); if (configuredMode == null) { configuredMode = AccountIdEndpointModeResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)).defaultMode(AccountIdEndpointMode.PREFERRED) - .resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).defaultMode(AccountIdEndpointMode.PREFERRED) + .resolve(); } return configuredMode; } protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(SdkAdvancedClientOption.SIGNER), - "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); Validate.notNull(c.option(SdkAdvancedClientOption.TOKEN_SIGNER), - "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java index 876781cacfbf..420c33dd84cf 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java @@ -9,6 +9,7 @@ import software.amazon.awssdk.auth.signer.Aws4Signer; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -21,6 +22,7 @@ import software.amazon.awssdk.core.signer.Signer; import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; import software.amazon.awssdk.services.json.endpoints.internal.JsonRequestSetEndpointInterceptor; @@ -48,8 +50,8 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); } @Override @@ -67,7 +69,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -82,6 +84,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return result.build(); }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -144,6 +162,6 @@ private List internalPlugins(SdkClientConfiguration config) { protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(SdkAdvancedClientOption.SIGNER), - "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java index e40ce4895c21..848dc95f7a0a 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java @@ -12,6 +12,7 @@ import software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -25,6 +26,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.endpoints.JsonClientContextParams; import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; @@ -53,14 +55,14 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) - .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) + .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); } @Override @@ -70,17 +72,17 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); interceptors = CollectionUtils.mergeLists(interceptors, config.option(SdkClientOption.EXECUTION_INTERCEPTORS)); ServiceConfiguration.Builder serviceConfigBuilder = ((ServiceConfiguration) config - .option(SdkClientOption.SERVICE_CONFIGURATION)).toBuilder(); + .option(SdkClientOption.SERVICE_CONFIGURATION)).toBuilder(); serviceConfigBuilder.profileFile(serviceConfigBuilder.profileFileSupplier() != null ? serviceConfigBuilder - .profileFileSupplier() : config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)); + .profileFileSupplier() : config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)); serviceConfigBuilder.profileName(serviceConfigBuilder.profileName() != null ? serviceConfigBuilder.profileName() : config - .option(SdkClientOption.PROFILE_NAME)); + .option(SdkClientOption.PROFILE_NAME)); ServiceConfiguration finalServiceConfig = serviceConfigBuilder.build(); SdkClientConfiguration.Builder builder = config.toBuilder(); builder.lazyOption(SdkClientOption.IDENTITY_PROVIDERS, c -> { @@ -97,6 +99,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.option(SdkClientOption.SERVICE_CONFIGURATION, finalServiceConfig); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -181,10 +199,10 @@ private List internalPlugins(SdkClientConfiguration config) { protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(SdkAdvancedClientOption.SIGNER), - "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); Validate.notNull(c.option(SdkAdvancedClientOption.TOKEN_SIGNER), - "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java index 7e24e6b8df5c..4d892e050a7d 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java @@ -9,6 +9,7 @@ import software.amazon.awssdk.auth.signer.Aws4Signer; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -21,6 +22,7 @@ import software.amazon.awssdk.core.signer.Signer; import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.database.endpoints.DatabaseEndpointProvider; import software.amazon.awssdk.services.database.endpoints.internal.DatabaseRequestSetEndpointInterceptor; @@ -35,7 +37,7 @@ @Generated("software.amazon.awssdk:codegen") @SdkInternalApi abstract class DefaultDatabaseBaseClientBuilder, C> extends - AwsDefaultClientBuilder { + AwsDefaultClientBuilder { @Override protected final String serviceEndpointPrefix() { return "database-service-endpoint"; @@ -49,8 +51,8 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); } @Override @@ -60,7 +62,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new DatabaseRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -75,6 +77,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return result.build(); }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") + .serviceProfileProperty("database_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -101,7 +119,7 @@ protected SdkClientConfiguration invokePlugins(SdkClientConfiguration config) { List plugins = CollectionUtils.mergeLists(internalPlugins, externalPlugins); SdkClientConfiguration.Builder configuration = config.toBuilder(); DatabaseServiceClientConfigurationBuilder serviceConfigBuilder = new DatabaseServiceClientConfigurationBuilder( - configuration); + configuration); for (SdkPlugin plugin : plugins) { plugin.configureClient(serviceConfigBuilder); } @@ -138,6 +156,6 @@ private List internalPlugins(SdkClientConfiguration config) { protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(SdkAdvancedClientOption.SIGNER), - "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java index 2c982b340df2..18e5f525da85 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java @@ -7,6 +7,8 @@ import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; +import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -16,6 +18,7 @@ import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.retry.RetryMode; import software.amazon.awssdk.identity.spi.IdentityProviders; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.database.endpoints.DatabaseEndpointProvider; import software.amazon.awssdk.services.database.endpoints.internal.DatabaseRequestSetEndpointInterceptor; @@ -29,7 +32,7 @@ @Generated("software.amazon.awssdk:codegen") @SdkInternalApi abstract class DefaultDatabaseBaseClientBuilder, C> extends - AwsDefaultClientBuilder { + AwsDefaultClientBuilder { @Override protected final String serviceEndpointPrefix() { return "database-service-endpoint"; @@ -43,7 +46,7 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()).option( - SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); } @Override @@ -53,7 +56,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new DatabaseRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -64,6 +67,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return result.build(); }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") + .serviceProfileProperty("database_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -86,7 +105,7 @@ protected SdkClientConfiguration invokePlugins(SdkClientConfiguration config) { List plugins = CollectionUtils.mergeLists(internalPlugins, externalPlugins); SdkClientConfiguration.Builder configuration = config.toBuilder(); DatabaseServiceClientConfigurationBuilder serviceConfigBuilder = new DatabaseServiceClientConfigurationBuilder( - configuration); + configuration); for (SdkPlugin plugin : plugins) { plugin.configureClient(serviceConfigBuilder); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java index 0b78fc371faa..ef0dce52a8ce 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java @@ -12,6 +12,7 @@ import software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointMode; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointModeResolver; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; @@ -27,6 +28,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.query.endpoints.QueryClientContextParams; import software.amazon.awssdk.services.query.endpoints.QueryEndpointProvider; @@ -55,13 +57,13 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) - .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) + .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); } @Override @@ -71,7 +73,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new QueryRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/query/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/query/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -92,6 +94,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.option(SdkClientOption.CLIENT_CONTEXT_PARAMS, clientContextParams.build()); builder.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE, resolveAccountIdEndpointMode(config)); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") + .serviceProfileProperty("query_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -179,19 +197,19 @@ private AccountIdEndpointMode resolveAccountIdEndpointMode(SdkClientConfiguratio AccountIdEndpointMode configuredMode = config.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE); if (configuredMode == null) { configuredMode = AccountIdEndpointModeResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)).defaultMode(AccountIdEndpointMode.PREFERRED) - .resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).defaultMode(AccountIdEndpointMode.PREFERRED) + .resolve(); } return configuredMode; } protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(SdkAdvancedClientOption.SIGNER), - "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); Validate.notNull(c.option(SdkAdvancedClientOption.TOKEN_SIGNER), - "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java index 70c9e4f08369..16949a93d770 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java @@ -67,7 +67,7 @@ final class DefaultEndpointDiscoveryTestAsyncClient implements EndpointDiscovery private static final Logger log = LoggerFactory.getLogger(DefaultEndpointDiscoveryTestAsyncClient.class); private static final AwsProtocolMetadata protocolMetadata = AwsProtocolMetadata.builder() - .serviceProtocol(AwsServiceProtocol.AWS_JSON).build(); + .serviceProtocol(AwsServiceProtocol.AWS_JSON).build(); private final AsyncClientHandler clientHandler; @@ -83,7 +83,7 @@ protected DefaultEndpointDiscoveryTestAsyncClient(SdkClientConfiguration clientC this.protocolFactory = init(AwsJsonProtocolFactory.builder()).build(); if (clientConfiguration.option(SdkClientOption.ENDPOINT_DISCOVERY_ENABLED)) { this.endpointDiscoveryCache = EndpointDiscoveryRefreshCache - .create(EndpointDiscoveryTestAsyncEndpointDiscoveryCacheLoader.create(this)); + .create(EndpointDiscoveryTestAsyncEndpointDiscoveryCacheLoader.create(this)); } } @@ -108,30 +108,30 @@ protected DefaultEndpointDiscoveryTestAsyncClient(SdkClientConfiguration clientC @Override public CompletableFuture describeEndpoints(DescribeEndpointsRequest describeEndpointsRequest) { SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(describeEndpointsRequest, - this.clientConfiguration); + this.clientConfiguration); List metricPublishers = resolveMetricPublishers(clientConfiguration, describeEndpointsRequest - .overrideConfiguration().orElse(null)); + .overrideConfiguration().orElse(null)); MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector - .create("ApiCall"); + .create("ApiCall"); try { apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "AwsEndpointDiscoveryTest"); apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "DescribeEndpoints"); JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( - operationMetadata, DescribeEndpointsResponse::builder); + operationMetadata, DescribeEndpointsResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); + operationMetadata); CompletableFuture executeFuture = clientHandler - .execute(new ClientExecutionParams() - .withOperationName("DescribeEndpoints").withProtocolMetadata(protocolMetadata) - .withMarshaller(new DescribeEndpointsRequestMarshaller(protocolFactory)) - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) - .withInput(describeEndpointsRequest)); + .execute(new ClientExecutionParams() + .withOperationName("DescribeEndpoints").withProtocolMetadata(protocolMetadata) + .withMarshaller(new DescribeEndpointsRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(describeEndpointsRequest)); CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); }); @@ -164,57 +164,61 @@ public CompletableFuture describeEndpoints(DescribeEn */ @Override public CompletableFuture testDiscoveryIdentifiersRequired( - TestDiscoveryIdentifiersRequiredRequest testDiscoveryIdentifiersRequiredRequest) { + TestDiscoveryIdentifiersRequiredRequest testDiscoveryIdentifiersRequiredRequest) { SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(testDiscoveryIdentifiersRequiredRequest, - this.clientConfiguration); + this.clientConfiguration); List metricPublishers = resolveMetricPublishers(clientConfiguration, - testDiscoveryIdentifiersRequiredRequest.overrideConfiguration().orElse(null)); + testDiscoveryIdentifiersRequiredRequest.overrideConfiguration().orElse(null)); MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector - .create("ApiCall"); + .create("ApiCall"); try { apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "AwsEndpointDiscoveryTest"); apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "TestDiscoveryIdentifiersRequired"); JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = protocolFactory - .createResponseHandler(operationMetadata, TestDiscoveryIdentifiersRequiredResponse::builder); + .createResponseHandler(operationMetadata, TestDiscoveryIdentifiersRequiredResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); + operationMetadata); boolean endpointDiscoveryEnabled = clientConfiguration.option(SdkClientOption.ENDPOINT_DISCOVERY_ENABLED); - boolean endpointOverridden = clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN) == Boolean.TRUE; + boolean endpointOverridden = clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER) + .isEndpointOverridden(); if (endpointOverridden) { throw new IllegalStateException( - "This operation requires endpoint discovery, but an endpoint override was specified when the client was created. This is not supported."); + "This operation requires endpoint discovery, but an endpoint override was specified when the client was created. This is not supported."); } if (!endpointDiscoveryEnabled) { throw new IllegalStateException( - "This operation requires endpoint discovery, but endpoint discovery was disabled on the client."); + "This operation requires endpoint discovery, but endpoint discovery was disabled on the client."); } CompletableFuture endpointFuture = CompletableFuture.completedFuture(null); if (endpointDiscoveryEnabled) { CompletableFuture identityFuture = testDiscoveryIdentifiersRequiredRequest - .overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) - .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) - .resolveIdentity(); + .overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) + .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) + .resolveIdentity(); endpointFuture = identityFuture.thenCompose(credentials -> { - EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(true) - .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) - .overrideConfiguration(testDiscoveryIdentifiersRequiredRequest.overrideConfiguration().orElse(null)) - .build(); + EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest + .builder() + .required(true) + .defaultEndpoint( + clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).clientEndpoint()) + .overrideConfiguration(testDiscoveryIdentifiersRequiredRequest.overrideConfiguration().orElse(null)) + .build(); return endpointDiscoveryCache.getAsync(credentials.accessKeyId(), endpointDiscoveryRequest); }); } CompletableFuture executeFuture = endpointFuture - .thenCompose(cachedEndpoint -> clientHandler - .execute(new ClientExecutionParams() - .withOperationName("TestDiscoveryIdentifiersRequired").withProtocolMetadata(protocolMetadata) - .withMarshaller(new TestDiscoveryIdentifiersRequiredRequestMarshaller(protocolFactory)) - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) - .discoveredEndpoint(cachedEndpoint).withInput(testDiscoveryIdentifiersRequiredRequest))); + .thenCompose(cachedEndpoint -> clientHandler + .execute(new ClientExecutionParams() + .withOperationName("TestDiscoveryIdentifiersRequired").withProtocolMetadata(protocolMetadata) + .withMarshaller(new TestDiscoveryIdentifiersRequiredRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .discoveredEndpoint(cachedEndpoint).withInput(testDiscoveryIdentifiersRequiredRequest))); CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); }); @@ -246,48 +250,52 @@ public CompletableFuture testDiscovery */ @Override public CompletableFuture testDiscoveryOptional( - TestDiscoveryOptionalRequest testDiscoveryOptionalRequest) { + TestDiscoveryOptionalRequest testDiscoveryOptionalRequest) { SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(testDiscoveryOptionalRequest, - this.clientConfiguration); + this.clientConfiguration); List metricPublishers = resolveMetricPublishers(clientConfiguration, testDiscoveryOptionalRequest - .overrideConfiguration().orElse(null)); + .overrideConfiguration().orElse(null)); MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector - .create("ApiCall"); + .create("ApiCall"); try { apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "AwsEndpointDiscoveryTest"); apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "TestDiscoveryOptional"); JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( - operationMetadata, TestDiscoveryOptionalResponse::builder); + operationMetadata, TestDiscoveryOptionalResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); + operationMetadata); boolean endpointDiscoveryEnabled = clientConfiguration.option(SdkClientOption.ENDPOINT_DISCOVERY_ENABLED); - boolean endpointOverridden = clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN) == Boolean.TRUE; + boolean endpointOverridden = clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER) + .isEndpointOverridden(); CompletableFuture endpointFuture = CompletableFuture.completedFuture(null); if (endpointDiscoveryEnabled) { CompletableFuture identityFuture = testDiscoveryOptionalRequest - .overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) - .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) - .resolveIdentity(); + .overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) + .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) + .resolveIdentity(); endpointFuture = identityFuture.thenCompose(credentials -> { - EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(false) - .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) - .overrideConfiguration(testDiscoveryOptionalRequest.overrideConfiguration().orElse(null)).build(); + EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest + .builder() + .required(false) + .defaultEndpoint( + clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).clientEndpoint()) + .overrideConfiguration(testDiscoveryOptionalRequest.overrideConfiguration().orElse(null)).build(); return endpointDiscoveryCache.getAsync(credentials.accessKeyId(), endpointDiscoveryRequest); }); } CompletableFuture executeFuture = endpointFuture - .thenCompose(cachedEndpoint -> clientHandler - .execute(new ClientExecutionParams() - .withOperationName("TestDiscoveryOptional").withProtocolMetadata(protocolMetadata) - .withMarshaller(new TestDiscoveryOptionalRequestMarshaller(protocolFactory)) - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) - .discoveredEndpoint(cachedEndpoint).withInput(testDiscoveryOptionalRequest))); + .thenCompose(cachedEndpoint -> clientHandler + .execute(new ClientExecutionParams() + .withOperationName("TestDiscoveryOptional").withProtocolMetadata(protocolMetadata) + .withMarshaller(new TestDiscoveryOptionalRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .discoveredEndpoint(cachedEndpoint).withInput(testDiscoveryOptionalRequest))); CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); }); @@ -319,56 +327,60 @@ public CompletableFuture testDiscoveryOptional( */ @Override public CompletableFuture testDiscoveryRequired( - TestDiscoveryRequiredRequest testDiscoveryRequiredRequest) { + TestDiscoveryRequiredRequest testDiscoveryRequiredRequest) { SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(testDiscoveryRequiredRequest, - this.clientConfiguration); + this.clientConfiguration); List metricPublishers = resolveMetricPublishers(clientConfiguration, testDiscoveryRequiredRequest - .overrideConfiguration().orElse(null)); + .overrideConfiguration().orElse(null)); MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector - .create("ApiCall"); + .create("ApiCall"); try { apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "AwsEndpointDiscoveryTest"); apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "TestDiscoveryRequired"); JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( - operationMetadata, TestDiscoveryRequiredResponse::builder); + operationMetadata, TestDiscoveryRequiredResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); + operationMetadata); boolean endpointDiscoveryEnabled = clientConfiguration.option(SdkClientOption.ENDPOINT_DISCOVERY_ENABLED); - boolean endpointOverridden = clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN) == Boolean.TRUE; + boolean endpointOverridden = clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER) + .isEndpointOverridden(); if (endpointOverridden) { throw new IllegalStateException( - "This operation requires endpoint discovery, but an endpoint override was specified when the client was created. This is not supported."); + "This operation requires endpoint discovery, but an endpoint override was specified when the client was created. This is not supported."); } if (!endpointDiscoveryEnabled) { throw new IllegalStateException( - "This operation requires endpoint discovery, but endpoint discovery was disabled on the client."); + "This operation requires endpoint discovery, but endpoint discovery was disabled on the client."); } CompletableFuture endpointFuture = CompletableFuture.completedFuture(null); if (endpointDiscoveryEnabled) { CompletableFuture identityFuture = testDiscoveryRequiredRequest - .overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) - .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) - .resolveIdentity(); + .overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) + .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) + .resolveIdentity(); endpointFuture = identityFuture.thenCompose(credentials -> { - EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(true) - .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) - .overrideConfiguration(testDiscoveryRequiredRequest.overrideConfiguration().orElse(null)).build(); + EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest + .builder() + .required(true) + .defaultEndpoint( + clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).clientEndpoint()) + .overrideConfiguration(testDiscoveryRequiredRequest.overrideConfiguration().orElse(null)).build(); return endpointDiscoveryCache.getAsync(credentials.accessKeyId(), endpointDiscoveryRequest); }); } CompletableFuture executeFuture = endpointFuture - .thenCompose(cachedEndpoint -> clientHandler - .execute(new ClientExecutionParams() - .withOperationName("TestDiscoveryRequired").withProtocolMetadata(protocolMetadata) - .withMarshaller(new TestDiscoveryRequiredRequestMarshaller(protocolFactory)) - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) - .discoveredEndpoint(cachedEndpoint).withInput(testDiscoveryRequiredRequest))); + .thenCompose(cachedEndpoint -> clientHandler + .execute(new ClientExecutionParams() + .withOperationName("TestDiscoveryRequired").withProtocolMetadata(protocolMetadata) + .withMarshaller(new TestDiscoveryRequiredRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .discoveredEndpoint(cachedEndpoint).withInput(testDiscoveryRequiredRequest))); CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); }); @@ -392,12 +404,12 @@ public final String serviceName() { private > T init(T builder) { return builder.clientConfiguration(clientConfiguration) - .defaultServiceExceptionSupplier(EndpointDiscoveryTestException::builder).protocol(AwsJsonProtocol.AWS_JSON) - .protocolVersion("1.1"); + .defaultServiceExceptionSupplier(EndpointDiscoveryTestException::builder).protocol(AwsJsonProtocol.AWS_JSON) + .protocolVersion("1.1"); } private static List resolveMetricPublishers(SdkClientConfiguration clientConfiguration, - RequestOverrideConfiguration requestOverrideConfiguration) { + RequestOverrideConfiguration requestOverrideConfiguration) { List publishers = null; if (requestOverrideConfiguration != null) { publishers = requestOverrideConfiguration.metricPublishers(); @@ -441,7 +453,7 @@ private SdkClientConfiguration updateSdkClientConfiguration(SdkRequest request, return configuration.build(); } EndpointDiscoveryTestServiceClientConfigurationBuilder serviceConfigBuilder = new EndpointDiscoveryTestServiceClientConfigurationBuilder( - configuration); + configuration); for (SdkPlugin plugin : plugins) { plugin.configureClient(serviceConfigBuilder); } @@ -450,7 +462,7 @@ private SdkClientConfiguration updateSdkClientConfiguration(SdkRequest request, } private HttpResponseHandler createErrorResponseHandler(BaseAwsJsonProtocolFactory protocolFactory, - JsonOperationMetadata operationMetadata) { + JsonOperationMetadata operationMetadata) { return protocolFactory.createErrorResponseHandler(operationMetadata); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-sync.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-sync.java index 981f5cf1893f..ba55ae6d349f 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-sync.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-sync.java @@ -65,7 +65,7 @@ final class DefaultEndpointDiscoveryTestClient implements EndpointDiscoveryTestC private static final Logger log = Logger.loggerFor(DefaultEndpointDiscoveryTestClient.class); private static final AwsProtocolMetadata protocolMetadata = AwsProtocolMetadata.builder() - .serviceProtocol(AwsServiceProtocol.AWS_JSON).build(); + .serviceProtocol(AwsServiceProtocol.AWS_JSON).build(); private final SyncClientHandler clientHandler; @@ -81,7 +81,7 @@ protected DefaultEndpointDiscoveryTestClient(SdkClientConfiguration clientConfig this.protocolFactory = init(AwsJsonProtocolFactory.builder()).build(); if (clientConfiguration.option(SdkClientOption.ENDPOINT_DISCOVERY_ENABLED)) { this.endpointDiscoveryCache = EndpointDiscoveryRefreshCache.create(EndpointDiscoveryTestEndpointDiscoveryCacheLoader - .create(this)); + .create(this)); } } @@ -101,31 +101,31 @@ protected DefaultEndpointDiscoveryTestClient(SdkClientConfiguration clientConfig */ @Override public DescribeEndpointsResponse describeEndpoints(DescribeEndpointsRequest describeEndpointsRequest) - throws AwsServiceException, SdkClientException, EndpointDiscoveryTestException { + throws AwsServiceException, SdkClientException, EndpointDiscoveryTestException { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(operationMetadata, - DescribeEndpointsResponse::builder); + DescribeEndpointsResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); + operationMetadata); SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(describeEndpointsRequest, - this.clientConfiguration); + this.clientConfiguration); List metricPublishers = resolveMetricPublishers(clientConfiguration, describeEndpointsRequest - .overrideConfiguration().orElse(null)); + .overrideConfiguration().orElse(null)); MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector - .create("ApiCall"); + .create("ApiCall"); try { apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "AwsEndpointDiscoveryTest"); apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "DescribeEndpoints"); return clientHandler.execute(new ClientExecutionParams() - .withOperationName("DescribeEndpoints").withProtocolMetadata(protocolMetadata) - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .withRequestConfiguration(clientConfiguration).withInput(describeEndpointsRequest) - .withMetricCollector(apiCallMetricCollector) - .withMarshaller(new DescribeEndpointsRequestMarshaller(protocolFactory))); + .withOperationName("DescribeEndpoints").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withInput(describeEndpointsRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new DescribeEndpointsRequestMarshaller(protocolFactory))); } finally { metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); } @@ -147,54 +147,54 @@ public DescribeEndpointsResponse describeEndpoints(DescribeEndpointsRequest desc */ @Override public TestDiscoveryIdentifiersRequiredResponse testDiscoveryIdentifiersRequired( - TestDiscoveryIdentifiersRequiredRequest testDiscoveryIdentifiersRequiredRequest) throws AwsServiceException, - SdkClientException, EndpointDiscoveryTestException { + TestDiscoveryIdentifiersRequiredRequest testDiscoveryIdentifiersRequiredRequest) throws AwsServiceException, + SdkClientException, EndpointDiscoveryTestException { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( - operationMetadata, TestDiscoveryIdentifiersRequiredResponse::builder); + operationMetadata, TestDiscoveryIdentifiersRequiredResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); + operationMetadata); boolean endpointDiscoveryEnabled = clientConfiguration.option(SdkClientOption.ENDPOINT_DISCOVERY_ENABLED); - boolean endpointOverridden = clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN) == Boolean.TRUE; + boolean endpointOverridden = clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).isEndpointOverridden(); if (endpointOverridden) { throw new IllegalStateException( - "This operation requires endpoint discovery, but an endpoint override was specified when the client was created. This is not supported."); + "This operation requires endpoint discovery, but an endpoint override was specified when the client was created. This is not supported."); } if (!endpointDiscoveryEnabled) { throw new IllegalStateException( - "This operation requires endpoint discovery, but endpoint discovery was disabled on the client."); + "This operation requires endpoint discovery, but endpoint discovery was disabled on the client."); } URI cachedEndpoint = null; if (endpointDiscoveryEnabled) { CompletableFuture identityFuture = testDiscoveryIdentifiersRequiredRequest - .overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) - .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)).resolveIdentity(); + .overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) + .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)).resolveIdentity(); String key = CompletableFutureUtils.joinLikeSync(identityFuture).accessKeyId(); EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(true) - .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) - .overrideConfiguration(testDiscoveryIdentifiersRequiredRequest.overrideConfiguration().orElse(null)).build(); + .defaultEndpoint(clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).clientEndpoint()) + .overrideConfiguration(testDiscoveryIdentifiersRequiredRequest.overrideConfiguration().orElse(null)).build(); cachedEndpoint = endpointDiscoveryCache.get(key, endpointDiscoveryRequest); } SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(testDiscoveryIdentifiersRequiredRequest, - this.clientConfiguration); + this.clientConfiguration); List metricPublishers = resolveMetricPublishers(clientConfiguration, - testDiscoveryIdentifiersRequiredRequest.overrideConfiguration().orElse(null)); + testDiscoveryIdentifiersRequiredRequest.overrideConfiguration().orElse(null)); MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector - .create("ApiCall"); + .create("ApiCall"); try { apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "AwsEndpointDiscoveryTest"); apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "TestDiscoveryIdentifiersRequired"); return clientHandler - .execute(new ClientExecutionParams() - .withOperationName("TestDiscoveryIdentifiersRequired").withProtocolMetadata(protocolMetadata) - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .discoveredEndpoint(cachedEndpoint).withRequestConfiguration(clientConfiguration) - .withInput(testDiscoveryIdentifiersRequiredRequest).withMetricCollector(apiCallMetricCollector) - .withMarshaller(new TestDiscoveryIdentifiersRequiredRequestMarshaller(protocolFactory))); + .execute(new ClientExecutionParams() + .withOperationName("TestDiscoveryIdentifiersRequired").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .discoveredEndpoint(cachedEndpoint).withRequestConfiguration(clientConfiguration) + .withInput(testDiscoveryIdentifiersRequiredRequest).withMetricCollector(apiCallMetricCollector) + .withMarshaller(new TestDiscoveryIdentifiersRequiredRequestMarshaller(protocolFactory))); } finally { metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); } @@ -216,44 +216,44 @@ public TestDiscoveryIdentifiersRequiredResponse testDiscoveryIdentifiersRequired */ @Override public TestDiscoveryOptionalResponse testDiscoveryOptional(TestDiscoveryOptionalRequest testDiscoveryOptionalRequest) - throws AwsServiceException, SdkClientException, EndpointDiscoveryTestException { + throws AwsServiceException, SdkClientException, EndpointDiscoveryTestException { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( - operationMetadata, TestDiscoveryOptionalResponse::builder); + operationMetadata, TestDiscoveryOptionalResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); + operationMetadata); boolean endpointDiscoveryEnabled = clientConfiguration.option(SdkClientOption.ENDPOINT_DISCOVERY_ENABLED); - boolean endpointOverridden = clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN) == Boolean.TRUE; + boolean endpointOverridden = clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).isEndpointOverridden(); URI cachedEndpoint = null; if (endpointDiscoveryEnabled) { CompletableFuture identityFuture = testDiscoveryOptionalRequest - .overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) - .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)).resolveIdentity(); + .overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) + .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)).resolveIdentity(); String key = CompletableFutureUtils.joinLikeSync(identityFuture).accessKeyId(); EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(false) - .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) - .overrideConfiguration(testDiscoveryOptionalRequest.overrideConfiguration().orElse(null)).build(); + .defaultEndpoint(clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).clientEndpoint()) + .overrideConfiguration(testDiscoveryOptionalRequest.overrideConfiguration().orElse(null)).build(); cachedEndpoint = endpointDiscoveryCache.get(key, endpointDiscoveryRequest); } SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(testDiscoveryOptionalRequest, - this.clientConfiguration); + this.clientConfiguration); List metricPublishers = resolveMetricPublishers(clientConfiguration, testDiscoveryOptionalRequest - .overrideConfiguration().orElse(null)); + .overrideConfiguration().orElse(null)); MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector - .create("ApiCall"); + .create("ApiCall"); try { apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "AwsEndpointDiscoveryTest"); apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "TestDiscoveryOptional"); return clientHandler.execute(new ClientExecutionParams() - .withOperationName("TestDiscoveryOptional").withProtocolMetadata(protocolMetadata) - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .discoveredEndpoint(cachedEndpoint).withRequestConfiguration(clientConfiguration) - .withInput(testDiscoveryOptionalRequest).withMetricCollector(apiCallMetricCollector) - .withMarshaller(new TestDiscoveryOptionalRequestMarshaller(protocolFactory))); + .withOperationName("TestDiscoveryOptional").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .discoveredEndpoint(cachedEndpoint).withRequestConfiguration(clientConfiguration) + .withInput(testDiscoveryOptionalRequest).withMetricCollector(apiCallMetricCollector) + .withMarshaller(new TestDiscoveryOptionalRequestMarshaller(protocolFactory))); } finally { metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); } @@ -275,52 +275,52 @@ public TestDiscoveryOptionalResponse testDiscoveryOptional(TestDiscoveryOptional */ @Override public TestDiscoveryRequiredResponse testDiscoveryRequired(TestDiscoveryRequiredRequest testDiscoveryRequiredRequest) - throws AwsServiceException, SdkClientException, EndpointDiscoveryTestException { + throws AwsServiceException, SdkClientException, EndpointDiscoveryTestException { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( - operationMetadata, TestDiscoveryRequiredResponse::builder); + operationMetadata, TestDiscoveryRequiredResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); + operationMetadata); boolean endpointDiscoveryEnabled = clientConfiguration.option(SdkClientOption.ENDPOINT_DISCOVERY_ENABLED); - boolean endpointOverridden = clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN) == Boolean.TRUE; + boolean endpointOverridden = clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).isEndpointOverridden(); if (endpointOverridden) { throw new IllegalStateException( - "This operation requires endpoint discovery, but an endpoint override was specified when the client was created. This is not supported."); + "This operation requires endpoint discovery, but an endpoint override was specified when the client was created. This is not supported."); } if (!endpointDiscoveryEnabled) { throw new IllegalStateException( - "This operation requires endpoint discovery, but endpoint discovery was disabled on the client."); + "This operation requires endpoint discovery, but endpoint discovery was disabled on the client."); } URI cachedEndpoint = null; if (endpointDiscoveryEnabled) { CompletableFuture identityFuture = testDiscoveryRequiredRequest - .overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) - .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)).resolveIdentity(); + .overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) + .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)).resolveIdentity(); String key = CompletableFutureUtils.joinLikeSync(identityFuture).accessKeyId(); EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(true) - .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) - .overrideConfiguration(testDiscoveryRequiredRequest.overrideConfiguration().orElse(null)).build(); + .defaultEndpoint(clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).clientEndpoint()) + .overrideConfiguration(testDiscoveryRequiredRequest.overrideConfiguration().orElse(null)).build(); cachedEndpoint = endpointDiscoveryCache.get(key, endpointDiscoveryRequest); } SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(testDiscoveryRequiredRequest, - this.clientConfiguration); + this.clientConfiguration); List metricPublishers = resolveMetricPublishers(clientConfiguration, testDiscoveryRequiredRequest - .overrideConfiguration().orElse(null)); + .overrideConfiguration().orElse(null)); MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector - .create("ApiCall"); + .create("ApiCall"); try { apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "AwsEndpointDiscoveryTest"); apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "TestDiscoveryRequired"); return clientHandler.execute(new ClientExecutionParams() - .withOperationName("TestDiscoveryRequired").withProtocolMetadata(protocolMetadata) - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .discoveredEndpoint(cachedEndpoint).withRequestConfiguration(clientConfiguration) - .withInput(testDiscoveryRequiredRequest).withMetricCollector(apiCallMetricCollector) - .withMarshaller(new TestDiscoveryRequiredRequestMarshaller(protocolFactory))); + .withOperationName("TestDiscoveryRequired").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .discoveredEndpoint(cachedEndpoint).withRequestConfiguration(clientConfiguration) + .withInput(testDiscoveryRequiredRequest).withMetricCollector(apiCallMetricCollector) + .withMarshaller(new TestDiscoveryRequiredRequestMarshaller(protocolFactory))); } finally { metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); } @@ -332,7 +332,7 @@ public final String serviceName() { } private static List resolveMetricPublishers(SdkClientConfiguration clientConfiguration, - RequestOverrideConfiguration requestOverrideConfiguration) { + RequestOverrideConfiguration requestOverrideConfiguration) { List publishers = null; if (requestOverrideConfiguration != null) { publishers = requestOverrideConfiguration.metricPublishers(); @@ -347,7 +347,7 @@ private static List resolveMetricPublishers(SdkClientConfigurat } private HttpResponseHandler createErrorResponseHandler(BaseAwsJsonProtocolFactory protocolFactory, - JsonOperationMetadata operationMetadata) { + JsonOperationMetadata operationMetadata) { return protocolFactory.createErrorResponseHandler(operationMetadata); } @@ -381,7 +381,7 @@ private SdkClientConfiguration updateSdkClientConfiguration(SdkRequest request, return configuration.build(); } EndpointDiscoveryTestServiceClientConfigurationBuilder serviceConfigBuilder = new EndpointDiscoveryTestServiceClientConfigurationBuilder( - configuration); + configuration); for (SdkPlugin plugin : plugins) { plugin.configureClient(serviceConfigBuilder); } @@ -391,8 +391,8 @@ private SdkClientConfiguration updateSdkClientConfiguration(SdkRequest request, private > T init(T builder) { return builder.clientConfiguration(clientConfiguration) - .defaultServiceExceptionSupplier(EndpointDiscoveryTestException::builder).protocol(AwsJsonProtocol.AWS_JSON) - .protocolVersion("1.1"); + .defaultServiceExceptionSupplier(EndpointDiscoveryTestException::builder).protocol(AwsJsonProtocol.AWS_JSON) + .protocolVersion("1.1"); } @Override diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/serviceclientconfiguration-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/serviceclientconfiguration-builder.java index 1fa344e072e4..9c81cdf0a6f9 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/serviceclientconfiguration-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/serviceclientconfiguration-builder.java @@ -7,6 +7,7 @@ import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; @@ -57,11 +58,9 @@ public ClientOverrideConfiguration overrideConfiguration() { @Override public JsonProtocolTestsServiceClientConfiguration.Builder endpointOverride(URI endpointOverride) { if (endpointOverride != null) { - config.option(SdkClientOption.ENDPOINT, endpointOverride); - config.option(SdkClientOption.ENDPOINT_OVERRIDDEN, true); + config.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, ClientEndpointProvider.forEndpointOverride(endpointOverride)); } else { - config.option(SdkClientOption.ENDPOINT, null); - config.option(SdkClientOption.ENDPOINT_OVERRIDDEN, false); + config.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, null); } return this; } @@ -71,8 +70,9 @@ public JsonProtocolTestsServiceClientConfiguration.Builder endpointOverride(URI */ @Override public URI endpointOverride() { - if (Boolean.TRUE.equals(config.option(SdkClientOption.ENDPOINT_OVERRIDDEN))) { - return config.option(SdkClientOption.ENDPOINT); + ClientEndpointProvider clientEndpoint = config.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER); + if (clientEndpoint != null && clientEndpoint.isEndpointOverridden()) { + return clientEndpoint.clientEndpoint(); } return null; } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/request-set-endpoint-interceptor.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/request-set-endpoint-interceptor.java index d936eca5ec8d..4cfeedb59e46 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/request-set-endpoint-interceptor.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/request-set-endpoint-interceptor.java @@ -5,7 +5,6 @@ import software.amazon.awssdk.core.interceptor.Context; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; -import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute; import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute; import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.SdkHttpRequest; @@ -18,8 +17,9 @@ public SdkHttpRequest modifyHttpRequest(Context.ModifyHttpRequest context, Execu if (AwsEndpointProviderUtils.endpointIsDiscovered(executionAttributes)) { return context.httpRequest(); } - Endpoint endpoint = (Endpoint) executionAttributes.getAttribute(SdkInternalExecutionAttribute.RESOLVED_ENDPOINT); + Endpoint endpoint = executionAttributes.getAttribute(SdkInternalExecutionAttribute.RESOLVED_ENDPOINT); return AwsEndpointProviderUtils.setUri(context.httpRequest(), - executionAttributes.getAttribute(SdkExecutionAttribute.CLIENT_ENDPOINT), endpoint.url()); + executionAttributes.getAttribute(SdkInternalExecutionAttribute.CLIENT_ENDPOINT_PROVIDER).clientEndpoint(), + endpoint.url()); } } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java index 8c3a1a6b612d..44e7bdd46a0b 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java @@ -33,7 +33,7 @@ import software.amazon.awssdk.awscore.client.config.AwsAdvancedClientOption; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.defaultsmode.DefaultsMode; -import software.amazon.awssdk.awscore.endpoint.DefaultServiceEndpointBuilder; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.endpoint.DualstackEnabledProvider; import software.amazon.awssdk.awscore.endpoint.FipsEnabledProvider; import software.amazon.awssdk.awscore.eventstream.EventStreamInitialRequestInterceptor; @@ -44,11 +44,13 @@ import software.amazon.awssdk.awscore.internal.defaultsmode.DefaultsModeResolver; import software.amazon.awssdk.awscore.retry.AwsRetryPolicy; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.builder.SdkDefaultClientBuilder; import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.awssdk.core.internal.SdkInternalTestAdvancedClientOption; import software.amazon.awssdk.core.retry.RetryMode; import software.amazon.awssdk.core.retry.RetryPolicy; import software.amazon.awssdk.http.SdkHttpClient; @@ -181,9 +183,12 @@ private SdkClientConfiguration finalizeAwsConfiguration(SdkClientConfiguration c this::resolveDefaultS3UsEast1RegionalEndpoint) .lazyOptionIfAbsent(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER, this::resolveCredentialsIdentityProvider) - // CREDENTIALS_PROVIDER is also set, since older clients may be relying on it + // Set CREDENTIALS_PROVIDER, because older clients may be relying on it .lazyOptionIfAbsent(AwsClientOption.CREDENTIALS_PROVIDER, this::resolveCredentialsProvider) + .lazyOptionIfAbsent(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, this::resolveClientEndpointProvider) + // Set ENDPOINT and ENDPOINT_OVERRIDDEN, because older clients may be relying on it .lazyOptionIfAbsent(SdkClientOption.ENDPOINT, this::resolveEndpoint) + .lazyOptionIfAbsent(SdkClientOption.ENDPOINT_OVERRIDDEN, this::resolveEndpointOverridden) .lazyOption(AwsClientOption.SIGNING_REGION, this::resolveSigningRegion) .lazyOption(SdkClientOption.HTTP_CLIENT_CONFIG, this::resolveHttpClientConfig) .applyMutation(this::configureRetryPolicy) @@ -210,6 +215,9 @@ protected final SdkClientConfiguration setOverrides(SdkClientConfiguration confi builder.option(RETRY_STRATEGY, defaultBuilder.build()); }); builder.putAll(overrideConfig); + + checkEndpointOverriddenOverride(configuration, builder); + // Forget anything we configured in the override configuration else it might be re-applied. builder.option(CONFIGURED_RETRY_MODE, null); builder.option(CONFIGURED_RETRY_STRATEGY, null); @@ -217,6 +225,20 @@ protected final SdkClientConfiguration setOverrides(SdkClientConfiguration confi return builder.build(); } + /** + * Check {@link SdkInternalTestAdvancedClientOption#ENDPOINT_OVERRIDDEN_OVERRIDE} to see if we should override the + * value returned by {@link SdkClientOption#CLIENT_ENDPOINT_PROVIDER}'s isEndpointOverridden. + */ + private void checkEndpointOverriddenOverride(SdkClientConfiguration configuration, SdkClientConfiguration.Builder builder) { + Optional endpointOverriddenOverride = + overrideConfig.advancedOption(SdkInternalTestAdvancedClientOption.ENDPOINT_OVERRIDDEN_OVERRIDE); + endpointOverriddenOverride.ifPresent(override -> { + ClientEndpointProvider clientEndpoint = configuration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER); + builder.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.create(clientEndpoint.clientEndpoint(), override)); + }); + } + /** * Return HTTP related defaults with the following chain of priorities. *
    @@ -294,18 +316,40 @@ private Region resolveSigningRegion(LazyValueSource config) { } /** - * Resolve the endpoint from the default-applied configuration. + * Specify the client endpoint provider to use for the client, if the client didn't specify one itself. + *

    + * This is only used for older client versions. Newer clients specify this value themselves. + */ + private ClientEndpointProvider resolveClientEndpointProvider(LazyValueSource config) { + ServiceMetadataAdvancedOption useGlobalS3EndpointProperty = + ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT; + return AwsClientEndpointProvider.builder() + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol(DEFAULT_ENDPOINT_PROTOCOL) + .region(config.get(AwsClientOption.AWS_REGION)) + .profileFile(config.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(useGlobalS3EndpointProperty, + config.get(useGlobalS3EndpointProperty)) + .dualstackEnabled(config.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(config.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)) + .build(); + } + + /** + * Resolve the client endpoint. This code is only needed by old SDK client versions. Newer SDK client versions + * resolve this information from the client endpoint provider. */ private URI resolveEndpoint(LazyValueSource config) { - return new DefaultServiceEndpointBuilder(serviceEndpointPrefix(), DEFAULT_ENDPOINT_PROTOCOL) - .withRegion(config.get(AwsClientOption.AWS_REGION)) - .withProfileFile(config.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .withProfileName(config.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - config.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .withDualstackEnabled(config.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .withFipsEnabled(config.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)) - .getServiceEndpoint(); + return config.get(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).clientEndpoint(); + } + + /** + * Resolve whether the endpoint was overridden by the customer. This code is only needed by old SDK client + * versions. Newer SDK client versions resolve this information from the client endpoint provider. + */ + private boolean resolveEndpointOverridden(LazyValueSource config) { + return config.get(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).isEndpointOverridden(); } /** diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java new file mode 100644 index 000000000000..2257666f3324 --- /dev/null +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java @@ -0,0 +1,461 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.awscore.endpoint; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; +import software.amazon.awssdk.annotations.SdkProtectedApi; +import software.amazon.awssdk.core.ClientEndpointProvider; +import software.amazon.awssdk.core.client.builder.SdkClientBuilder; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.profiles.ProfileFile; +import software.amazon.awssdk.profiles.ProfileFileSystemSetting; +import software.amazon.awssdk.profiles.ProfileProperty; +import software.amazon.awssdk.regions.EndpointTag; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.regions.ServiceEndpointKey; +import software.amazon.awssdk.regions.ServiceMetadata; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; +import software.amazon.awssdk.utils.Lazy; +import software.amazon.awssdk.utils.Logger; +import software.amazon.awssdk.utils.OptionalUtils; +import software.amazon.awssdk.utils.ToString; +import software.amazon.awssdk.utils.Validate; +import software.amazon.awssdk.utils.internal.SystemSettingUtils; + +/** + * An implementation of {@link ClientEndpointProvider} that loads the default client endpoint from: + *

      + *
    1. The client-level endpoint override
    2. + *
    3. The service-specific endpoint override system property (e.g. 'aws.endpointUrlS3')
    4. + *
    5. The service-agnostic endpoint override system property (i.e. 'aws.endpointUrl')
    6. + *
    7. The service-specific endpoint override environment variable (e.g. 'AWS_ENDPOINT_URL_S3')
    8. + *
    9. The service-agnostic endpoint override environment variable (i.e. 'AWS_ENDPOINT_URL')
    10. + *
    11. The service-specific endpoint override profile property (e.g. 's3.endpoint_url')
    12. + *
    13. The service-agnostic endpoint override profile property (i.e. 'endpoint_url')
    14. + *
    15. The {@link ServiceMetadata} for the service
    16. + *
    + */ +@SdkProtectedApi +public final class AwsClientEndpointProvider implements ClientEndpointProvider { + private static final Logger log = Logger.loggerFor(AwsClientEndpointProvider.class); + + private static final String GLOBAL_ENDPOINT_OVERRIDE_ENVIRONMENT_VARIABLE = "AWS_ENDPOINT_URL"; + private static final String GLOBAL_ENDPOINT_OVERRIDE_SYSTEM_PROPERTY = "aws.endpointUrl"; + + /** + * A pairing of the client endpoint (URI) and whether it was an endpoint override from the customer (true) or a + * default endpoint (false). + */ + private final Lazy clientEndpoint; + + private AwsClientEndpointProvider(Builder builder) { + this.clientEndpoint = new Lazy<>(() -> resolveClientEndpoint(new Builder(builder))); + } + + public static Builder builder() { + return new Builder(); + } + + /** + * Retrieve the endpoint to be used by the client. + * @throws SdkClientException If the endpoint could not be loaded or was invalid + */ + public URI clientEndpoint() { + return clientEndpoint.getValue().clientEndpoint; + } + + /** + * Return true if the endpoint was overridden by the customer, or false if it was loaded from the + * {@link ServiceMetadata}. + * @throws SdkClientException If the endpoint could not be loaded or was invalid + */ + public boolean isEndpointOverridden() { + return clientEndpoint.getValue().isEndpointOverridden; + } + + private ClientEndpoint resolveClientEndpoint(Builder builder) { + return OptionalUtils.firstPresent(clientEndpointFromClientOverride(builder), + () -> clientEndpointFromEnvironment(builder), + () -> clientEndpointFromServiceMetadata(builder)) + .orElseThrow(AwsClientEndpointProvider::failToLoadEndpointException); + } + + private static SdkClientException failToLoadEndpointException() { + return SdkClientException.create("Unable to determine the default client endpoint. Enable TRACE logging on " + + AwsClientEndpointProvider.class.getName() + " for more information."); + } + + private Optional clientEndpointFromClientOverride(Builder builder) { + Optional result = Optional.ofNullable(builder.clientEndpointOverride) + .map(uri -> new ClientEndpoint(uri, true)); + result.ifPresent(e -> log.trace(() -> "Client was configured with endpoint override: " + e.clientEndpoint)); + return result; + } + + private Optional clientEndpointFromEnvironment(Builder builder) { + if (builder.serviceEndpointOverrideEnvironmentVariable == null || + builder.serviceEndpointOverrideSystemProperty == null || + builder.serviceProfileProperty == null) { + Validate.isTrue(builder.serviceEndpointOverrideEnvironmentVariable == null && + builder.serviceEndpointOverrideSystemProperty == null && + builder.serviceProfileProperty == null , + "If any of the service endpoint override environment variable, system property or profile " + + "property are configured, they must all be configured."); + log.trace(() -> "Environment was not checked for client endpoint."); + return Optional.empty(); + } + + return OptionalUtils.firstPresent(systemProperty(builder.serviceEndpointOverrideSystemProperty), + () -> systemProperty(GLOBAL_ENDPOINT_OVERRIDE_SYSTEM_PROPERTY), + () -> environmentVariable(builder.serviceEndpointOverrideEnvironmentVariable), + () -> environmentVariable(GLOBAL_ENDPOINT_OVERRIDE_ENVIRONMENT_VARIABLE), + () -> profileProperty(builder, + builder.serviceProfileProperty + "." + + ProfileProperty.ENDPOINT_URL), + () -> profileProperty(builder, ProfileProperty.ENDPOINT_URL)) + .map(uri -> new ClientEndpoint(uri, true)); + } + + private Optional systemProperty(String systemProperty) { + // CHECKSTYLE:OFF - We have to read system properties directly here to match the load order of the other SDKs + return createUri("system property " + systemProperty, + Optional.ofNullable(System.getProperty(systemProperty))); + // CHECKSTYLE:ON + } + + private Optional environmentVariable(String environmentVariable) { + return createUri("environment variable " + environmentVariable, + SystemSettingUtils.resolveEnvironmentVariable(environmentVariable)); + } + + private Optional profileProperty(Builder builder, String profileProperty) { + initializeProfileFileDefaults(builder); + return createUri("profile property " + profileProperty, + Optional.ofNullable(builder.profileFile.get()) + .flatMap(pf -> pf.profile(builder.profileName)) + .flatMap(p -> p.property(profileProperty))); + } + + private Optional clientEndpointFromServiceMetadata(Builder builder) { + // This value is generally overridden after endpoints 2.0. It seems to exist for backwards-compatibility + // with older client versions or interceptors. + + if (builder.serviceEndpointPrefix == null || + builder.region == null || + builder.protocol == null) { + // Make sure that people didn't set just one value and expect it to be used. + Validate.isTrue(builder.serviceEndpointPrefix == null && + builder.region == null && + builder.protocol == null, + "If any of the service endpoint prefix, region or protocol are configured, they must all " + + "be configured."); + log.trace(() -> "Service metadata was not checked for client endpoint."); + return Optional.empty(); + } + + Validate.paramNotNull(builder.serviceEndpointPrefix, "serviceName"); + Validate.paramNotNull(builder.region, "region"); + Validate.paramNotNull(builder.protocol, "protocol"); + + initializeProfileFileDefaults(builder); + + if (builder.dualstackEnabled == null) { + builder.dualstackEnabled = DualstackEnabledProvider.builder() + .profileFile(builder.profileFile) + .profileName(builder.profileName) + .build() + .isDualstackEnabled() + .orElse(false); + } + + if (builder.fipsEnabled == null) { + builder.fipsEnabled = FipsEnabledProvider.builder() + .profileFile(builder.profileFile) + .profileName(builder.profileName) + .build() + .isFipsEnabled() + .orElse(false); + } + + List endpointTags = new ArrayList<>(); + if (builder.dualstackEnabled) { + endpointTags.add(EndpointTag.DUALSTACK); + } + if (builder.fipsEnabled) { + endpointTags.add(EndpointTag.FIPS); + } + + ServiceMetadata serviceMetadata = ServiceMetadata.of(builder.serviceEndpointPrefix) + .reconfigure(c -> c.profileFile(builder.profileFile) + .profileName(builder.profileName) + .advancedOptions(builder.advancedOptions)); + URI endpointWithoutProtocol = + serviceMetadata.endpointFor(ServiceEndpointKey.builder() + .region(builder.region) + .tags(endpointTags) + .build()); + URI endpoint = URI.create(builder.protocol + "://" + endpointWithoutProtocol); + if (endpoint.getHost() == null) { + String error = "Configured region (" + builder.region + ") and tags (" + endpointTags + ") resulted in " + + "an invalid URI: " + endpoint + ". This is usually caused by an invalid region " + + "configuration."; + + List exampleRegions = serviceMetadata.regions(); + if (!exampleRegions.isEmpty()) { + error += " Valid regions: " + exampleRegions; + } + + throw SdkClientException.create(error); + } + + log.trace(() -> "Client endpoint was loaded from service metadata, but this endpoint will likely be overridden " + + "at the request-level by the endpoint resolver: " + endpoint); + return Optional.of(new ClientEndpoint(endpoint, false)); + } + + private Optional createUri(String source, Optional uri) { + return uri.map(u -> { + try { + URI parsedUri = new URI(uri.get()); + log.trace(() -> "Client endpoint was loaded from the " + source + ": " + parsedUri); + return parsedUri; + } catch (URISyntaxException e) { + throw SdkClientException.create("An invalid URI was configured in " + source, e); + } + }); + } + + private void initializeProfileFileDefaults(Builder builder) { + if (builder.profileFile == null) { + builder.profileFile = new Lazy<>(ProfileFile::defaultProfileFile)::getValue; + } + + if (builder.profileName == null) { + builder.profileName = ProfileFileSystemSetting.AWS_PROFILE.getStringValueOrThrow(); + } + } + + private static final class ClientEndpoint { + private final URI clientEndpoint; + private final boolean isEndpointOverridden; + + private ClientEndpoint(URI clientEndpoint, boolean isEndpointOverridden) { + this.clientEndpoint = clientEndpoint; + this.isEndpointOverridden = isEndpointOverridden; + } + + @Override + public String toString() { + return ToString.builder("ClientEndpoint") + .add("clientEndpoint", clientEndpoint) + .add("isEndpointOverridden", isEndpointOverridden) + .build(); + } + } + + public static final class Builder { + private URI clientEndpointOverride; + private String serviceEndpointPrefix; + private String protocol; + private Region region; + private Supplier profileFile; + private String profileName; + private final Map, Object> advancedOptions = new HashMap<>(); + private Boolean dualstackEnabled; + private Boolean fipsEnabled; + private String serviceEndpointOverrideEnvironmentVariable; + private String serviceEndpointOverrideSystemProperty; + private String serviceProfileProperty; + + private Builder() { + } + + private Builder(Builder src) { + this.clientEndpointOverride = src.clientEndpointOverride; + this.serviceEndpointPrefix = src.serviceEndpointPrefix; + this.protocol = src.protocol; + this.region = src.region; + this.profileFile = src.profileFile; + this.profileName = src.profileName; + this.advancedOptions.putAll(src.advancedOptions); + this.dualstackEnabled = src.dualstackEnabled; + this.fipsEnabled = src.fipsEnabled; + this.serviceEndpointOverrideEnvironmentVariable = src.serviceEndpointOverrideEnvironmentVariable; + this.serviceEndpointOverrideSystemProperty = src.serviceEndpointOverrideSystemProperty; + this.serviceProfileProperty = src.serviceProfileProperty; + } + + /** + * Set the endpoint that was overridden by the customer using {@link SdkClientBuilder#endpointOverride(URI)}. + *

    + * If specified, this provider will behave the same as + * {@link ClientEndpointProvider#forEndpointOverride(URI)}. Other configured values will not be used. + */ + public Builder clientEndpointOverride(URI clientEndpointOverride) { + if (clientEndpointOverride != null) { + Validate.paramNotNull(clientEndpointOverride.getScheme(), "The scheme of the endpoint override"); + } + this.clientEndpointOverride = clientEndpointOverride; + return this; + } + + /** + * Set the service-specific environment variable that should be used to load the endpoint override for this + * service. + *

    + * If this value is set, {@link #serviceEndpointOverrideSystemProperty} and {@link #serviceProfileProperty} must + * also be set. + *

    + * If this value is not set, loading the service endpoint from the environment is skipped. + */ + public Builder serviceEndpointOverrideEnvironmentVariable(String serviceEndpointOverrideEnvironmentVariable) { + this.serviceEndpointOverrideEnvironmentVariable = serviceEndpointOverrideEnvironmentVariable; + return this; + } + + /** + * Set the service-specific system property that should be used to load the endpoint override for this service. + *

    + * If this value is set, {@link #serviceEndpointOverrideEnvironmentVariable} and {@link #serviceProfileProperty} + * must also be set. + *

    + * If this value is not set, loading the service endpoint from the environment is skipped. + */ + public Builder serviceEndpointOverrideSystemProperty(String serviceEndpointOverrideSystemProperty) { + this.serviceEndpointOverrideSystemProperty = serviceEndpointOverrideSystemProperty; + return this; + } + + /** + * Set the service-specific profile property that should be used to load the endpoint override for this service. + *

    + * If this value is set, {@link #serviceEndpointOverrideEnvironmentVariable} and + * {@link #serviceEndpointOverrideSystemProperty} must also be set. + *

    + * If this value is not set, loading the service endpoint from the environment is skipped. + */ + public Builder serviceProfileProperty(String serviceProfileProperty) { + this.serviceProfileProperty = serviceProfileProperty; + return this; + } + + /** + * Set the profile file supplier that will supply the customer's profile file. This profile file is used both + * for checking for the endpoint override and when resolving the endpoint from {@link ServiceMetadata}. + *

    + * If this value is not set, the {@link ProfileFile#defaultProfileFile()} is used. + */ + public Builder profileFile(Supplier profileFile) { + this.profileFile = profileFile; + return this; + } + + /** + * Set the profile name for the profile that should be used . This profile is used both + * for checking for the endpoint override and when resolving the endpoint from {@link ServiceMetadata}. + *

    + * If this value is not set, {@link ProfileFileSystemSetting#AWS_PROFILE} is used. + */ + public Builder profileName(String profileName) { + this.profileName = profileName; + return this; + } + + /** + * Set the service endpoint prefix, as it is expected by {@link ServiceMetadata#of(String)}. + *

    + * This value will only be used if the endpoint is loaded from service metadata. + *

    + * If this value is set, {@link #defaultProtocol} and {@link #region} must also be set. If this value is not + * set, loading the service endpoint from service metadata is skipped. + */ + public Builder serviceEndpointPrefix(String serviceEndpointPrefix) { + this.serviceEndpointPrefix = serviceEndpointPrefix; + return this; + } + + /** + * Set the protocol to be used for endpoints returned by {@link ServiceMetadata#of(String)}. + *

    + * This value will only be used if the endpoint is loaded from service metadata. + *

    + * If this value is set, {@link #serviceEndpointPrefix} and {@link #region} must also be set. If this value is + * not set, loading the service endpoint from service metadata is skipped. + */ + public Builder defaultProtocol(String protocol) { + this.protocol = protocol; + return this; + } + + /** + * The region to use when resolving with {@link ServiceMetadata#of(String)}. + *

    + * This value will only be used if the region is loaded from service metadata. + *

    + * If this value is set, {@link #serviceEndpointPrefix} and {@link #defaultProtocol} must also be set. If this + * value is not set, loading the service endpoint from service metadata is skipped. + */ + public Builder region(Region region) { + this.region = region; + return this; + } + + /** + * Whether dualstack endpoints should be used when resolving with {@link ServiceMetadata#of(String)}. + *

    + * This value will only be used if the endpoint is loaded from service metadata. + *

    + * If this value is not set, the {@link DualstackEnabledProvider} will be used. + */ + public Builder dualstackEnabled(Boolean dualstackEnabled) { + this.dualstackEnabled = dualstackEnabled; + return this; + } + + /** + * Whether FIPS endpoints should be used when resolving with {@link ServiceMetadata#of(String)}. + *

    + * This value will only be used if the endpoint is loaded from service metadata. + *

    + * If this value is not set, the {@link FipsEnabledProvider} will be used. + */ + public Builder fipsEnabled(Boolean fipsEnabled) { + this.fipsEnabled = fipsEnabled; + return this; + } + + /** + * Specify advanced options that should be passed on to the {@link ServiceMetadata}. + *

    + * This value will only be used if the endpoint is loaded from service metadata. + */ + public Builder putAdvancedOption(ServiceMetadataAdvancedOption option, T value) { + this.advancedOptions.put(option, value); + return this; + } + + public AwsClientEndpointProvider build() { + return new AwsClientEndpointProvider(this); + } + } +} diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/DefaultServiceEndpointBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/DefaultServiceEndpointBuilder.java index a0113969a810..005fa0ea1b35 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/DefaultServiceEndpointBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/DefaultServiceEndpointBuilder.java @@ -16,156 +16,71 @@ package software.amazon.awssdk.awscore.endpoint; import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.function.Supplier; import software.amazon.awssdk.annotations.NotThreadSafe; import software.amazon.awssdk.annotations.SdkProtectedApi; -import software.amazon.awssdk.core.exception.SdkClientException; import software.amazon.awssdk.profiles.ProfileFile; -import software.amazon.awssdk.profiles.ProfileFileSystemSetting; -import software.amazon.awssdk.regions.EndpointTag; import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.regions.ServiceEndpointKey; -import software.amazon.awssdk.regions.ServiceMetadata; import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; -import software.amazon.awssdk.utils.Lazy; -import software.amazon.awssdk.utils.Validate; /** - * Uses service metadata and the request region to construct an endpoint for a specific service + * Uses service metadata and the request region to construct an endpoint for a specific service. + * + * @deprecated Use {@link AwsClientEndpointProvider}. This is only used by old client versions. */ @NotThreadSafe @SdkProtectedApi -// TODO We may not need this anymore, we should default to AWS partition when resolving -// a region we don't know about yet. +@Deprecated public final class DefaultServiceEndpointBuilder { - private final String serviceName; - private final String protocol; - + private final AwsClientEndpointProvider.Builder endpointResolver = AwsClientEndpointProvider.builder(); private Region region; - private Supplier profileFile; - private String profileName; - private final Map, Object> advancedOptions = new HashMap<>(); - private Boolean dualstackEnabled; - private Boolean fipsEnabled; public DefaultServiceEndpointBuilder(String serviceName, String protocol) { - this.serviceName = Validate.paramNotNull(serviceName, "serviceName"); - this.protocol = Validate.paramNotNull(protocol, "protocol"); + endpointResolver.serviceEndpointPrefix(serviceName) + .defaultProtocol(protocol); + } + + public Region getRegion() { + return region; } public DefaultServiceEndpointBuilder withRegion(Region region) { - if (region == null) { - throw new IllegalArgumentException("Region cannot be null"); - } this.region = region; + endpointResolver.region(region); return this; } public DefaultServiceEndpointBuilder withProfileFile(Supplier profileFile) { - this.profileFile = profileFile; + endpointResolver.profileFile(profileFile); return this; } public DefaultServiceEndpointBuilder withProfileFile(ProfileFile profileFile) { - this.profileFile = () -> profileFile; + endpointResolver.profileFile(() -> profileFile); return this; } public DefaultServiceEndpointBuilder withProfileName(String profileName) { - this.profileName = profileName; + endpointResolver.profileName(profileName); return this; } public DefaultServiceEndpointBuilder putAdvancedOption(ServiceMetadataAdvancedOption option, T value) { - advancedOptions.put(option, value); + endpointResolver.putAdvancedOption(option, value); return this; } public DefaultServiceEndpointBuilder withDualstackEnabled(Boolean dualstackEnabled) { - this.dualstackEnabled = dualstackEnabled; + endpointResolver.dualstackEnabled(dualstackEnabled); return this; } public DefaultServiceEndpointBuilder withFipsEnabled(Boolean fipsEnabled) { - this.fipsEnabled = fipsEnabled; + endpointResolver.fipsEnabled(fipsEnabled); return this; } public URI getServiceEndpoint() { - if (profileFile == null) { - profileFile = new Lazy<>(ProfileFile::defaultProfileFile)::getValue; - } - - if (profileName == null) { - profileName = ProfileFileSystemSetting.AWS_PROFILE.getStringValueOrThrow(); - } - - if (dualstackEnabled == null) { - dualstackEnabled = DualstackEnabledProvider.builder() - .profileFile(profileFile) - .profileName(profileName) - .build() - .isDualstackEnabled() - .orElse(false); - } - - if (fipsEnabled == null) { - fipsEnabled = FipsEnabledProvider.builder() - .profileFile(profileFile) - .profileName(profileName) - .build() - .isFipsEnabled() - .orElse(false); - } - - - - List endpointTags = new ArrayList<>(); - if (dualstackEnabled) { - endpointTags.add(EndpointTag.DUALSTACK); - } - if (fipsEnabled) { - endpointTags.add(EndpointTag.FIPS); - } - - ServiceMetadata serviceMetadata = ServiceMetadata.of(serviceName) - .reconfigure(c -> c.profileFile(profileFile) - .profileName(profileName) - .advancedOptions(advancedOptions)); - URI endpoint = addProtocolToServiceEndpoint(serviceMetadata.endpointFor(ServiceEndpointKey.builder() - .region(region) - .tags(endpointTags) - .build())); - - if (endpoint.getHost() == null) { - String error = "Configured region (" + region + ") and tags (" + endpointTags + ") resulted in an invalid URI: " - + endpoint + ". This is usually caused by an invalid region configuration."; - - List exampleRegions = serviceMetadata.regions(); - if (!exampleRegions.isEmpty()) { - error += " Valid regions: " + exampleRegions; - } - - throw SdkClientException.create(error); - } - - return endpoint; - } - - private URI addProtocolToServiceEndpoint(URI endpointWithoutProtocol) throws IllegalArgumentException { - try { - return new URI(protocol + "://" + endpointWithoutProtocol); - } catch (URISyntaxException e) { - throw new IllegalArgumentException(e); - } - } - - public Region getRegion() { - return region; + return endpointResolver.build().clientEndpoint(); } } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java index e3e273aa03d7..3d570ce13bf0 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java @@ -102,8 +102,8 @@ private AwsExecutionContextBuilder() { .putAttribute(AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED, clientConfig.option(AwsClientOption.FIPS_ENDPOINT_ENABLED)) .putAttribute(SdkExecutionAttribute.OPERATION_NAME, executionParams.getOperationName()) - .putAttribute(SdkExecutionAttribute.CLIENT_ENDPOINT, clientConfig.option(SdkClientOption.ENDPOINT)) - .putAttribute(SdkExecutionAttribute.ENDPOINT_OVERRIDDEN, clientConfig.option(SdkClientOption.ENDPOINT_OVERRIDDEN)) + .putAttribute(SdkInternalExecutionAttribute.CLIENT_ENDPOINT_PROVIDER, + clientConfig.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER)) .putAttribute(SdkInternalExecutionAttribute.ENDPOINT_PROVIDER, resolveEndpointProvider(originalRequest, clientConfig)) .putAttribute(SdkInternalExecutionAttribute.CLIENT_CONTEXT_PARAMS, diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java index ba04424fee93..ca3061cca171 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java @@ -98,8 +98,14 @@ public void buildIncludesServiceDefaults() { public void buildWithRegionShouldHaveCorrectEndpointAndSigningRegion() { TestClient client = testClientBuilder().region(Region.US_WEST_1).build(); + assertThat(client.clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).clientEndpoint()) + .hasToString("https://" + ENDPOINT_PREFIX + ".us-west-1.amazonaws.com"); + assertThat(client.clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).isEndpointOverridden()) + .isEqualTo(false); assertThat(client.clientConfiguration.option(SdkClientOption.ENDPOINT)) .hasToString("https://" + ENDPOINT_PREFIX + ".us-west-1.amazonaws.com"); + assertThat(client.clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN)) + .isEqualTo(false); assertThat(client.clientConfiguration.option(SIGNING_REGION)).isEqualTo(Region.US_WEST_1); assertThat(client.clientConfiguration.option(SERVICE_SIGNING_NAME)).isEqualTo(SIGNING_NAME); } @@ -130,7 +136,13 @@ public void buildWithSetFipsTrueAndNonFipsRegionFipsEnabledRemainsSet() { public void buildWithEndpointShouldHaveCorrectEndpointAndSigningRegion() { TestClient client = testClientBuilder().region(Region.US_WEST_1).endpointOverride(ENDPOINT).build(); + assertThat(client.clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).clientEndpoint()) + .isEqualTo(ENDPOINT); + assertThat(client.clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).isEndpointOverridden()) + .isEqualTo(true); assertThat(client.clientConfiguration.option(SdkClientOption.ENDPOINT)).isEqualTo(ENDPOINT); + assertThat(client.clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN)) + .isEqualTo(true); assertThat(client.clientConfiguration.option(SIGNING_REGION)).isEqualTo(Region.US_WEST_1); assertThat(client.clientConfiguration.option(SERVICE_SIGNING_NAME)).isEqualTo(SIGNING_NAME); } diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/utils/HttpTestUtils.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/utils/HttpTestUtils.java index 463ceded2d85..de9e72eedefc 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/utils/HttpTestUtils.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/utils/HttpTestUtils.java @@ -22,6 +22,7 @@ import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.SdkAdvancedAsyncClientOption; import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; @@ -50,7 +51,8 @@ public static TestClientBuilder testClientBuilder() { public static SdkClientConfiguration testClientConfiguration() { return SdkClientConfiguration.builder() .option(SdkClientOption.EXECUTION_INTERCEPTORS, new ArrayList<>()) - .option(SdkClientOption.ENDPOINT, URI.create("http://localhost:8080")) + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(URI.create("http://localhost:8080"))) .option(SdkClientOption.RETRY_STRATEGY, AwsRetryStrategy.defaultRetryStrategy()) .option(SdkClientOption.ADDITIONAL_HTTP_HEADERS, new HashMap<>()) .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java index 2fa813a5a330..a36326392738 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java @@ -17,6 +17,7 @@ import static java.util.Collections.unmodifiableList; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.EnumMap; @@ -27,6 +28,7 @@ import software.amazon.awssdk.annotations.SdkProtectedApi; import software.amazon.awssdk.annotations.SdkTestInternalApi; import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPojo; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; @@ -183,7 +185,7 @@ protected Map getDefaultTimestamp public final ProtocolMarshaller createProtocolMarshaller(OperationInfo operationInfo) { return JsonProtocolMarshallerBuilder.create() - .endpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) + .endpoint(endpoint(clientConfiguration)) .jsonGenerator(createGenerator(operationInfo)) .contentType(getContentType()) .operationInfo(operationInfo) @@ -192,6 +194,16 @@ public final ProtocolMarshaller createProtocolMarshaller(Ope .build(); } + private URI endpoint(SdkClientConfiguration clientConfiguration) { + ClientEndpointProvider endpointProvider = clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER); + if (endpointProvider != null) { + return endpointProvider.clientEndpoint(); + } + + // Some old client versions may not use the endpoint provider. In that case, use the legacy endpoint field. + return clientConfiguration.option(SdkClientOption.ENDPOINT); + } + /** * Builder for {@link AwsJsonProtocolFactory}. */ diff --git a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/AwsQueryProtocolFactory.java b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/AwsQueryProtocolFactory.java index e7e791f555a9..e23ea4c59cb7 100644 --- a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/AwsQueryProtocolFactory.java +++ b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/AwsQueryProtocolFactory.java @@ -17,6 +17,7 @@ import static java.util.Collections.unmodifiableList; +import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -24,6 +25,7 @@ import software.amazon.awssdk.annotations.SdkProtectedApi; import software.amazon.awssdk.awscore.AwsResponse; import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPojo; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; @@ -74,12 +76,22 @@ public class AwsQueryProtocolFactory { public final ProtocolMarshaller createProtocolMarshaller( OperationInfo operationInfo) { return QueryProtocolMarshaller.builder() - .endpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) + .endpoint(endpoint(clientConfiguration)) .operationInfo(operationInfo) .isEc2(isEc2()) .build(); } + private URI endpoint(SdkClientConfiguration clientConfiguration) { + ClientEndpointProvider endpointProvider = clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER); + if (endpointProvider != null) { + return endpointProvider.clientEndpoint(); + } + + // Some old client versions may not use the endpoint provider. In that case, use the legacy endpoint field. + return clientConfiguration.option(SdkClientOption.ENDPOINT); + } + /** * Creates the success response handler to unmarshall the response into a POJO. * diff --git a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/AwsXmlProtocolFactory.java b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/AwsXmlProtocolFactory.java index 4fa73a1aeabd..7a0dc0c64707 100644 --- a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/AwsXmlProtocolFactory.java +++ b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/AwsXmlProtocolFactory.java @@ -17,6 +17,7 @@ import static java.util.Collections.unmodifiableList; +import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -25,6 +26,7 @@ import software.amazon.awssdk.annotations.SdkProtectedApi; import software.amazon.awssdk.awscore.AwsResponse; import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.Response; import software.amazon.awssdk.core.SdkPojo; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; @@ -100,12 +102,22 @@ public class AwsXmlProtocolFactory { */ public ProtocolMarshaller createProtocolMarshaller(OperationInfo operationInfo) { return XmlProtocolMarshaller.builder() - .endpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) + .endpoint(endpoint(clientConfiguration)) .xmlGenerator(createGenerator(operationInfo)) .operationInfo(operationInfo) .build(); } + private URI endpoint(SdkClientConfiguration clientConfiguration) { + ClientEndpointProvider endpointProvider = clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER); + if (endpointProvider != null) { + return endpointProvider.clientEndpoint(); + } + + // Some old client versions may not use the endpoint provider. In that case, use the legacy endpoint field. + return clientConfiguration.option(SdkClientOption.ENDPOINT); + } + public HttpResponseHandler createResponseHandler(Supplier pojoSupplier, XmlOperationMetadata staxOperationMetadata) { return createResponseHandler(r -> pojoSupplier.get(), staxOperationMetadata); diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/ClientEndpointProvider.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/ClientEndpointProvider.java new file mode 100644 index 000000000000..500dd446af4d --- /dev/null +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/ClientEndpointProvider.java @@ -0,0 +1,56 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.core; + +import java.net.URI; +import software.amazon.awssdk.annotations.SdkProtectedApi; +import software.amazon.awssdk.core.internal.StaticClientEndpointProvider; +import software.amazon.awssdk.endpoints.EndpointProvider; + +/** + * Client endpoint providers are responsible for resolving client-level endpoints. {@link EndpointProvider}s are + * ultimately responsible for resolving the endpoint used for a request. + *

    + * {@link EndpointProvider}s may choose to honor or completely ignore the client-level endpoint. Default endpoint + * providers will ignore the client-level endpoint, unless {@link #isEndpointOverridden()} is true. + */ +@SdkProtectedApi +public interface ClientEndpointProvider { + /** + * Create a client endpoint provider that uses the provided URI and returns true from {@link #isEndpointOverridden()}. + */ + static ClientEndpointProvider forEndpointOverride(URI uri) { + return new StaticClientEndpointProvider(uri, true); + } + + /** + * Create a client endpoint provider that uses the provided static URI and override settings. + */ + static ClientEndpointProvider create(URI uri, boolean isEndpointOverridden) { + return new StaticClientEndpointProvider(uri, isEndpointOverridden); + } + + /** + * Retrieve the client endpoint from this provider. + */ + URI clientEndpoint(); + + /** + * Returns true if this endpoint was specified as an override by the customer, or false if it was determined + * automatically by the SDK. + */ + boolean isEndpointOverridden(); +} diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/builder/SdkDefaultClientBuilder.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/builder/SdkDefaultClientBuilder.java index f24b9b996a19..44847e35c1da 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/builder/SdkDefaultClientBuilder.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/builder/SdkDefaultClientBuilder.java @@ -70,6 +70,7 @@ import software.amazon.awssdk.annotations.SdkPreviewApi; import software.amazon.awssdk.annotations.SdkProtectedApi; import software.amazon.awssdk.annotations.SdkTestInternalApi; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.CompressionConfiguration; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.SdkSystemSetting; @@ -534,12 +535,10 @@ private List sdkInterceptors() { @Override public final B endpointOverride(URI endpointOverride) { if (endpointOverride == null) { - clientConfiguration.option(SdkClientOption.ENDPOINT, null); - clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN, false); + clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, null); } else { - Validate.paramNotNull(endpointOverride.getScheme(), "The URI scheme of endpointOverride"); - clientConfiguration.option(SdkClientOption.ENDPOINT, endpointOverride); - clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN, true); + clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(endpointOverride)); } return thisBuilder(); } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientConfiguration.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientConfiguration.java index 401dded53e75..b20ada64d34b 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientConfiguration.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientConfiguration.java @@ -15,14 +15,12 @@ package software.amazon.awssdk.core.client.config; -import static software.amazon.awssdk.core.client.config.SdkClientOption.ENDPOINT_OVERRIDDEN; import static software.amazon.awssdk.core.client.config.SdkClientOption.SIGNER_OVERRIDDEN; import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; import software.amazon.awssdk.annotations.SdkProtectedApi; -import software.amazon.awssdk.core.internal.SdkInternalTestAdvancedClientOption; import software.amazon.awssdk.core.signer.Signer; import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.SdkAutoCloseable; @@ -64,21 +62,15 @@ public static SdkClientConfiguration.Builder builder() { public static SdkClientConfiguration fromOverrideConfiguration(ClientOverrideConfiguration configuration) { SdkClientConfiguration result = configuration.asSdkClientConfiguration(); - Boolean endpointOverriddenOverride = result.option(SdkInternalTestAdvancedClientOption.ENDPOINT_OVERRIDDEN_OVERRIDE); Signer signerFromOverride = result.option(SdkAdvancedClientOption.SIGNER); - if (endpointOverriddenOverride == null && signerFromOverride == null) { + if (signerFromOverride == null) { return result; } - SdkClientConfiguration.Builder resultBuilder = result.toBuilder(); - if (signerFromOverride != null) { - resultBuilder.option(SIGNER_OVERRIDDEN, true); - } - if (endpointOverriddenOverride != null) { - resultBuilder.option(ENDPOINT_OVERRIDDEN, endpointOverriddenOverride); - } - return resultBuilder.build(); + return result.toBuilder() + .option(SIGNER_OVERRIDDEN, true) + .build(); } /** diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOption.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOption.java index b05f700e3be9..5c740cd7b01a 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOption.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOption.java @@ -23,6 +23,7 @@ import java.util.function.Consumer; import java.util.function.Supplier; import software.amazon.awssdk.annotations.SdkProtectedApi; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.ClientType; import software.amazon.awssdk.core.CompressionConfiguration; import software.amazon.awssdk.core.SdkClient; @@ -100,15 +101,31 @@ public final class SdkClientOption extends ClientOption { /** * The effective endpoint the client is configured to make requests to. If the client has been configured with * an endpoint override then this value will be the provided endpoint value. + * + * @deprecated Use {@link #CLIENT_ENDPOINT_PROVIDER} for client-level endpoint configuration, or + * {@link #ENDPOINT_PROVIDER} for deriving the request-level endpoint. */ + @Deprecated public static final SdkClientOption ENDPOINT = new SdkClientOption<>(URI.class); /** * A flag that when set to true indicates the endpoint stored in {@link SdkClientOption#ENDPOINT} was a customer * supplied value and not generated by the client based on Region metadata. + * + * @deprecated Use {@link #CLIENT_ENDPOINT_PROVIDER}'s {@link ClientEndpointProvider#isEndpointOverridden()}. */ + @Deprecated public static final SdkClientOption ENDPOINT_OVERRIDDEN = new SdkClientOption<>(Boolean.class); + /** + * A provider for the client-level endpoint configuration. This includes the default endpoint determined by the + * endpoint metadata or endpoint overrides specified by the customer. + *

    + * {@link #ENDPOINT_PROVIDER} determines the request-level endpoint configuration. + */ + public static final SdkClientOption CLIENT_ENDPOINT_PROVIDER = + new SdkClientOption<>(ClientEndpointProvider.class); + /** * Service-specific configuration used by some services, like S3. */ diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOptionValidation.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOptionValidation.java index 638baf938217..aab55738c828 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOptionValidation.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOptionValidation.java @@ -42,8 +42,6 @@ public static void validateSyncClientOptions(SdkClientConfiguration c) { } private static void validateClientOptions(SdkClientConfiguration c) { - require("endpoint", c.option(SdkClientOption.ENDPOINT)); - require("overrideConfiguration.additionalHttpHeaders", c.option(SdkClientOption.ADDITIONAL_HTTP_HEADERS)); require("overrideConfiguration.executionInterceptors", c.option(SdkClientOption.EXECUTION_INTERCEPTORS)); require("overrideConfiguration.retryStrategy", c.option(SdkClientOption.RETRY_STRATEGY)); diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/ExecutionAttribute.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/ExecutionAttribute.java index d53c0e99410b..d585df2ea460 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/ExecutionAttribute.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/ExecutionAttribute.java @@ -87,6 +87,17 @@ private ExecutionAttribute(String name, ValueStorage storage) { public static DerivedAttributeBuilder derivedBuilder(String name, @SuppressWarnings("unused") Class attributeType, ExecutionAttribute realAttribute) { + return new DerivedAttributeBuilder<>(name, () -> realAttribute); + } + + /** + * This is the same as {@link #derivedBuilder(String, Class, ExecutionAttribute)}, but the real attribute is loaded + * lazily at runtime. This is useful when the real attribute is in the same class hierarchy, to avoid initialization + * order problems. + */ + public static DerivedAttributeBuilder derivedBuilder(String name, + @SuppressWarnings("unused") Class attributeType, + Supplier> realAttribute) { return new DerivedAttributeBuilder<>(name, realAttribute); } @@ -164,11 +175,11 @@ ValueStorage storage() { public static final class DerivedAttributeBuilder { private final String name; - private final ExecutionAttribute realAttribute; + private final Supplier> realAttribute; private Function readMapping; private BiFunction writeMapping; - private DerivedAttributeBuilder(String name, ExecutionAttribute realAttribute) { + private DerivedAttributeBuilder(String name, Supplier> realAttribute) { this.name = name; this.realAttribute = realAttribute; } @@ -244,7 +255,7 @@ public void setIfAbsent(Map, Object> attributes, T value) * attributes map. */ private static final class DerivationValueStorage implements ValueStorage { - private final ExecutionAttribute realAttribute; + private final Supplier> realAttribute; private final Function readMapping; private final BiFunction writeMapping; @@ -257,13 +268,13 @@ private DerivationValueStorage(DerivedAttributeBuilder builder) { @SuppressWarnings("unchecked") // Safe because of the implementation of set @Override public T get(Map, Object> attributes) { - return readMapping.apply((U) attributes.get(realAttribute)); + return readMapping.apply((U) attributes.get(realAttribute.get())); } @SuppressWarnings("unchecked") // Safe because of the implementation of set @Override public void set(Map, Object> attributes, T value) { - attributes.compute(realAttribute, (k, real) -> writeMapping.apply((U) real, value)); + attributes.compute(realAttribute.get(), (k, real) -> writeMapping.apply((U) real, value)); } @Override diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkExecutionAttribute.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkExecutionAttribute.java index 57836e042d6a..83bfb111def8 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkExecutionAttribute.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkExecutionAttribute.java @@ -26,6 +26,7 @@ import java.util.function.Supplier; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.checksums.spi.ChecksumAlgorithm; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.ClientType; import software.amazon.awssdk.core.SelectedAuthScheme; import software.amazon.awssdk.core.ServiceConfiguration; @@ -33,6 +34,8 @@ import software.amazon.awssdk.core.checksums.ChecksumSpecs; import software.amazon.awssdk.core.checksums.ChecksumValidation; import software.amazon.awssdk.core.signer.Signer; +import software.amazon.awssdk.endpoints.EndpointProvider; +import software.amazon.awssdk.http.SdkHttpRequest; import software.amazon.awssdk.http.auth.aws.signer.AwsV4FamilyHttpSigner; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; import software.amazon.awssdk.http.auth.spi.signer.AsyncSignRequest; @@ -86,16 +89,38 @@ public class SdkExecutionAttribute { new ExecutionAttribute<>("ApiCallAttemptMetricCollector"); /** - * If true indicates that the configured endpoint of the client is a value that was supplied as an override and not + * True indicates that the configured endpoint of the client is a value that was supplied as an override and not * generated from regional metadata. + * + * @deprecated This value should not be trusted. To modify the endpoint used for requests, you should decorate the + * {@link EndpointProvider} of the client. This value can be determined there, by checking for the existence of an + * override endpoint. */ - public static final ExecutionAttribute ENDPOINT_OVERRIDDEN = new ExecutionAttribute<>("EndpointOverridden"); + @Deprecated + public static final ExecutionAttribute ENDPOINT_OVERRIDDEN = + ExecutionAttribute.derivedBuilder("EndpointOverridden", + Boolean.class, + () -> SdkInternalExecutionAttribute.CLIENT_ENDPOINT_PROVIDER) + .readMapping(ClientEndpointProvider::isEndpointOverridden) + .writeMapping((ep, overridden) -> ClientEndpointProvider.create(ep.clientEndpoint(), overridden)) + .build(); /** - * This is the endpointOverride (if {@link #ENDPOINT_OVERRIDDEN} is true), otherwise the endpoint generated from regional - * metadata. + * This is the endpointOverride (if {@link #ENDPOINT_OVERRIDDEN} is true), otherwise the endpoint generated from + * regional metadata. + * + * @deprecated This value is not usually accurate, now that the endpoint is almost entirely determined by the + * service's endpoint rules. Use {@link SdkHttpRequest#getUri()} from interceptors, to get or modify the actual + * endpoint. */ - public static final ExecutionAttribute CLIENT_ENDPOINT = new ExecutionAttribute<>("EndpointOverride"); + @Deprecated + public static final ExecutionAttribute CLIENT_ENDPOINT = + ExecutionAttribute.derivedBuilder("EndpointOverride", + URI.class, + () -> SdkInternalExecutionAttribute.CLIENT_ENDPOINT_PROVIDER) + .readMapping(ClientEndpointProvider::clientEndpoint) + .writeMapping((ep, uri) -> ClientEndpointProvider.create(uri, ep.isEndpointOverridden())) + .build(); /** * If the client signer value has been overridden. diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java index 2ae0dc904d64..37ef66a5d717 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java @@ -18,6 +18,7 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicLong; import software.amazon.awssdk.annotations.SdkProtectedApi; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkClient; import software.amazon.awssdk.core.SdkProtocolMetadata; import software.amazon.awssdk.core.SelectedAuthScheme; @@ -77,6 +78,13 @@ public final class SdkInternalExecutionAttribute extends SdkExecutionAttribute { public static final ExecutionAttribute IS_NONE_AUTH_TYPE_REQUEST = new ExecutionAttribute<>("IsNoneAuthTypeRequest"); + /** + * The endpoint provider used to resolve the endpoint of the client. This will be overridden during the request + * pipeline by the {@link #ENDPOINT_PROVIDER}. + */ + public static final ExecutionAttribute CLIENT_ENDPOINT_PROVIDER = + new ExecutionAttribute<>("ClientEndpointProvider"); + /** * The endpoint provider used to resolve the destination endpoint for a request. */ diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/SdkInternalTestAdvancedClientOption.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/SdkInternalTestAdvancedClientOption.java index 9bebbe2fd600..25661ebb0260 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/SdkInternalTestAdvancedClientOption.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/SdkInternalTestAdvancedClientOption.java @@ -20,7 +20,6 @@ import software.amazon.awssdk.annotations.SdkTestInternalApi; import software.amazon.awssdk.core.client.builder.SdkClientBuilder; import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; -import software.amazon.awssdk.core.client.config.SdkClientOption; /** * Options of {@link SdkAdvancedClientOption} that must not be used outside of tests that are stored in this project. @@ -33,7 +32,7 @@ public class SdkInternalTestAdvancedClientOption extends SdkAdvancedClientOpt * endpoints generated from a specific region. For example, endpoint discovery is not supported in some cases when endpoint * overrides are used. * - * When this option is set, the {@link SdkClientOption#ENDPOINT_OVERRIDDEN} is forced to this value. Because of the way this + * When this option is set, the "endpoint overridden" flag is forced to this value. Because of the way this * is implemented, the client configuration must be configured *after* the {@code endpointOverride} is configured. */ @SdkTestInternalApi diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/StaticClientEndpointProvider.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/StaticClientEndpointProvider.java new file mode 100644 index 000000000000..40a9cd38f2c3 --- /dev/null +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/StaticClientEndpointProvider.java @@ -0,0 +1,81 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.core.internal; + +import java.net.URI; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.ClientEndpointProvider; +import software.amazon.awssdk.utils.ToString; +import software.amazon.awssdk.utils.Validate; + +/** + * An implementation of {@link ClientEndpointProvider} that uses static values. + * + * @see ClientEndpointProvider#create(URI, boolean) + */ +@SdkInternalApi +public class StaticClientEndpointProvider implements ClientEndpointProvider { + private final URI clientEndpoint; + private final boolean isEndpointOverridden; + + public StaticClientEndpointProvider(URI clientEndpoint, boolean isEndpointOverridden) { + this.clientEndpoint = Validate.paramNotNull(clientEndpoint, "clientEndpoint"); + this.isEndpointOverridden = isEndpointOverridden; + Validate.paramNotNull(clientEndpoint.getScheme(), "The URI scheme of endpointOverride"); + } + + @Override + public URI clientEndpoint() { + return this.clientEndpoint; + } + + @Override + public boolean isEndpointOverridden() { + return this.isEndpointOverridden; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + StaticClientEndpointProvider that = (StaticClientEndpointProvider) o; + + if (isEndpointOverridden != that.isEndpointOverridden) { + return false; + } + return clientEndpoint.equals(that.clientEndpoint); + } + + @Override + public int hashCode() { + int result = clientEndpoint.hashCode(); + result = 31 * result + (isEndpointOverridden ? 1 : 0); + return result; + } + + @Override + public String toString() { + return ToString.builder("ClientEndpointProvider") + .add("clientEndpoint", clientEndpoint) + .add("isEndpointOverridden", isEndpointOverridden) + .build(); + } +} diff --git a/core/sdk-core/src/test/java/software/amazon/awssdk/core/client/builder/DefaultClientBuilderTest.java b/core/sdk-core/src/test/java/software/amazon/awssdk/core/client/builder/DefaultClientBuilderTest.java index 0a9938ea9e2e..25e83b36383c 100644 --- a/core/sdk-core/src/test/java/software/amazon/awssdk/core/client/builder/DefaultClientBuilderTest.java +++ b/core/sdk-core/src/test/java/software/amazon/awssdk/core/client/builder/DefaultClientBuilderTest.java @@ -30,7 +30,6 @@ import static software.amazon.awssdk.core.client.config.SdkClientOption.ADDITIONAL_HTTP_HEADERS; import static software.amazon.awssdk.core.client.config.SdkClientOption.API_CALL_ATTEMPT_TIMEOUT; import static software.amazon.awssdk.core.client.config.SdkClientOption.API_CALL_TIMEOUT; -import static software.amazon.awssdk.core.client.config.SdkClientOption.ENDPOINT_OVERRIDDEN; import static software.amazon.awssdk.core.client.config.SdkClientOption.EXECUTION_ATTRIBUTES; import static software.amazon.awssdk.core.client.config.SdkClientOption.EXECUTION_INTERCEPTORS; import static software.amazon.awssdk.core.client.config.SdkClientOption.METRIC_PUBLISHERS; @@ -65,6 +64,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; @@ -285,7 +285,6 @@ public void close() { assertThat(config.option(PROFILE_NAME)).isEqualTo(profileName); assertThat(config.option(METRIC_PUBLISHERS)).contains(metricPublisher); assertThat(config.option(EXECUTION_ATTRIBUTES).getAttribute(execAttribute)).isEqualTo("value"); - assertThat(config.option(ENDPOINT_OVERRIDDEN)).isEqualTo(Boolean.TRUE); // Ensure that the SDK won't close the scheduled executor service we provided. config.close(); @@ -306,7 +305,8 @@ public void buildIncludesServiceDefaults() { public void buildWithEndpointShouldHaveCorrectEndpointAndSigningRegion() { TestClient client = testClientBuilder().endpointOverride(ENDPOINT).build(); - assertThat(client.clientConfiguration.option(SdkClientOption.ENDPOINT)).isEqualTo(ENDPOINT); + assertThat(client.clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).clientEndpoint()) + .isEqualTo(ENDPOINT); } @Test @@ -482,7 +482,8 @@ protected TestClient buildClient() { @Override protected SdkClientConfiguration mergeChildDefaults(SdkClientConfiguration configuration) { - return configuration.merge(c -> c.option(SdkClientOption.ENDPOINT, DEFAULT_ENDPOINT)); + return configuration.merge(c -> c.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(DEFAULT_ENDPOINT))); } @Override @@ -513,7 +514,8 @@ protected TestAsyncClient buildClient() { @Override protected SdkClientConfiguration mergeChildDefaults(SdkClientConfiguration configuration) { - return configuration.merge(c -> c.option(SdkClientOption.ENDPOINT, DEFAULT_ENDPOINT)); + return configuration.merge(c -> c.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(DEFAULT_ENDPOINT))); } @Override diff --git a/core/sdk-core/src/test/java/utils/HttpTestUtils.java b/core/sdk-core/src/test/java/utils/HttpTestUtils.java index 6c21a54c227b..127584c67e5a 100644 --- a/core/sdk-core/src/test/java/utils/HttpTestUtils.java +++ b/core/sdk-core/src/test/java/utils/HttpTestUtils.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.concurrent.Executors; import java.util.stream.Collectors; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.SdkAdvancedAsyncClientOption; import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; @@ -70,7 +71,8 @@ public static TestAsyncClientBuilder testAsyncClientBuilder() { public static SdkClientConfiguration testClientConfiguration() { return SdkClientConfiguration.builder() .option(SdkClientOption.EXECUTION_INTERCEPTORS, new ArrayList<>()) - .option(SdkClientOption.ENDPOINT, URI.create("http://localhost:8080")) + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(URI.create("http://localhost:8080"))) .option(SdkClientOption.RETRY_STRATEGY, SdkDefaultRetryStrategy.defaultRetryStrategy()) .option(SdkClientOption.ADDITIONAL_HTTP_HEADERS, new HashMap<>()) diff --git a/services/docdb/src/main/java/software/amazon/awssdk/services/docdb/internal/RdsPresignInterceptor.java b/services/docdb/src/main/java/software/amazon/awssdk/services/docdb/internal/RdsPresignInterceptor.java index 4d48de11e262..55b0fd574e64 100644 --- a/services/docdb/src/main/java/software/amazon/awssdk/services/docdb/internal/RdsPresignInterceptor.java +++ b/services/docdb/src/main/java/software/amazon/awssdk/services/docdb/internal/RdsPresignInterceptor.java @@ -25,13 +25,13 @@ import java.util.concurrent.CompletableFuture; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.AwsExecutionAttribute; -import software.amazon.awssdk.awscore.endpoint.DefaultServiceEndpointBuilder; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.Protocol; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.SelectedAuthScheme; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; -import software.amazon.awssdk.core.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.Context; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; @@ -60,13 +60,15 @@ @SdkInternalApi public abstract class RdsPresignInterceptor implements ExecutionInterceptor { - private static final URI CUSTOM_ENDPOINT_LOCALHOST = URI.create("http://localhost"); + private static final ClientEndpointProvider CUSTOM_ENDPOINT_PROVIDER_LOCALHOST = + ClientEndpointProvider.forEndpointOverride(URI.create("http://localhost")); protected static final AwsQueryProtocolFactory PROTOCOL_FACTORY = AwsQueryProtocolFactory .builder() // Need an endpoint to marshall but this will be overwritten in modifyHttpRequest .clientConfiguration(SdkClientConfiguration.builder() - .option(SdkClientOption.ENDPOINT, CUSTOM_ENDPOINT_LOCALHOST) + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + CUSTOM_ENDPOINT_PROVIDER_LOCALHOST) .build()) .build(); @@ -217,20 +219,16 @@ private SdkHttpFullRequest toSdkHttpFullRequest(SignedRequest signedRequest) { } private URI createEndpoint(String regionName, String serviceName, ExecutionAttributes attributes) { - Region region = Region.of(regionName); - if (region == null) { - throw SdkClientException.builder() - .message("{" + serviceName + ", " + regionName + "} was not " - + "found in region metadata. Update to latest version of SDK and try again.") - .build(); - } - - return new DefaultServiceEndpointBuilder(SERVICE_NAME, Protocol.HTTPS.toString()) - .withRegion(region) - .withProfileFile(attributes.getAttribute(SdkExecutionAttribute.PROFILE_FILE_SUPPLIER)) - .withProfileName(attributes.getAttribute(SdkExecutionAttribute.PROFILE_NAME)) - .withDualstackEnabled(attributes.getAttribute(AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED)) - .withFipsEnabled(attributes.getAttribute(AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED)) - .getServiceEndpoint(); + return AwsClientEndpointProvider.builder() + .serviceEndpointPrefix(SERVICE_NAME) + .defaultProtocol(Protocol.HTTPS.toString()) + .region(Region.of(regionName)) + .profileFile(attributes.getAttribute(SdkExecutionAttribute.PROFILE_FILE_SUPPLIER)) + .profileName(attributes.getAttribute(SdkExecutionAttribute.PROFILE_NAME)) + .dualstackEnabled( + attributes.getAttribute(AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(attributes.getAttribute(AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED)) + .build() + .clientEndpoint(); } } diff --git a/services/dynamodb/src/test/java/software/amazon/awssdk/services/dynamodb/PutItemRequestMarshallerTest.java b/services/dynamodb/src/test/java/software/amazon/awssdk/services/dynamodb/PutItemRequestMarshallerTest.java index 70b65c2c9b52..788280ad457c 100644 --- a/services/dynamodb/src/test/java/software/amazon/awssdk/services/dynamodb/PutItemRequestMarshallerTest.java +++ b/services/dynamodb/src/test/java/software/amazon/awssdk/services/dynamodb/PutItemRequestMarshallerTest.java @@ -24,6 +24,7 @@ import java.nio.ByteBuffer; import org.junit.jupiter.api.Test; import software.amazon.awssdk.core.SdkBytes; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.http.SdkHttpFullRequest; @@ -42,7 +43,8 @@ public class PutItemRequestMarshallerTest { AwsJsonProtocolFactory.builder() .clientConfiguration( SdkClientConfiguration.builder() - .option(SdkClientOption.ENDPOINT, URI.create("http://localhost")) + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(URI.create("http://localhost"))) .build()) .protocolVersion("1.1") .protocol(AwsJsonProtocol.AWS_JSON) diff --git a/services/ec2/src/main/java/software/amazon/awssdk/services/ec2/transform/internal/GeneratePreSignUrlInterceptor.java b/services/ec2/src/main/java/software/amazon/awssdk/services/ec2/transform/internal/GeneratePreSignUrlInterceptor.java index baf011facda5..7e8f314d0eca 100644 --- a/services/ec2/src/main/java/software/amazon/awssdk/services/ec2/transform/internal/GeneratePreSignUrlInterceptor.java +++ b/services/ec2/src/main/java/software/amazon/awssdk/services/ec2/transform/internal/GeneratePreSignUrlInterceptor.java @@ -27,6 +27,7 @@ import software.amazon.awssdk.auth.signer.Aws4Signer; import software.amazon.awssdk.auth.signer.params.Aws4PresignerParams; import software.amazon.awssdk.awscore.util.AwsHostNameUtils; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; @@ -51,13 +52,15 @@ @SdkInternalApi public final class GeneratePreSignUrlInterceptor implements ExecutionInterceptor { - private static final URI CUSTOM_ENDPOINT_LOCALHOST = URI.create("http://localhost"); + private static final ClientEndpointProvider CUSTOM_ENDPOINT_PROVIDER_LOCALHOST = + ClientEndpointProvider.forEndpointOverride(URI.create("http://localhost")); private static final AwsEc2ProtocolFactory PROTOCOL_FACTORY = AwsEc2ProtocolFactory .builder() // Need an endpoint to marshall but this will be overwritten in modifyHttpRequest .clientConfiguration(SdkClientConfiguration.builder() - .option(SdkClientOption.ENDPOINT, CUSTOM_ENDPOINT_LOCALHOST) + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + CUSTOM_ENDPOINT_PROVIDER_LOCALHOST) .build()) .build(); diff --git a/services/neptune/src/main/java/software/amazon/awssdk/services/neptune/internal/RdsPresignInterceptor.java b/services/neptune/src/main/java/software/amazon/awssdk/services/neptune/internal/RdsPresignInterceptor.java index 07dd4567100c..34f8fe30247c 100644 --- a/services/neptune/src/main/java/software/amazon/awssdk/services/neptune/internal/RdsPresignInterceptor.java +++ b/services/neptune/src/main/java/software/amazon/awssdk/services/neptune/internal/RdsPresignInterceptor.java @@ -25,13 +25,13 @@ import java.util.concurrent.CompletableFuture; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.AwsExecutionAttribute; -import software.amazon.awssdk.awscore.endpoint.DefaultServiceEndpointBuilder; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.Protocol; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.SelectedAuthScheme; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; -import software.amazon.awssdk.core.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.Context; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; @@ -61,13 +61,15 @@ @SdkInternalApi public abstract class RdsPresignInterceptor implements ExecutionInterceptor { - private static final URI CUSTOM_ENDPOINT_LOCALHOST = URI.create("http://localhost"); + private static final ClientEndpointProvider CUSTOM_ENDPOINT_PROVIDER_LOCALHOST = + ClientEndpointProvider.forEndpointOverride(URI.create("http://localhost")); protected static final AwsQueryProtocolFactory PROTOCOL_FACTORY = AwsQueryProtocolFactory .builder() // Need an endpoint to marshall but this will be overwritten in modifyHttpRequest .clientConfiguration(SdkClientConfiguration.builder() - .option(SdkClientOption.ENDPOINT, CUSTOM_ENDPOINT_LOCALHOST) + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + CUSTOM_ENDPOINT_PROVIDER_LOCALHOST) .build()) .build(); @@ -218,20 +220,16 @@ private SdkHttpFullRequest toSdkHttpFullRequest(SignedRequest signedRequest) { } private URI createEndpoint(String regionName, String serviceName, ExecutionAttributes attributes) { - Region region = Region.of(regionName); - if (region == null) { - throw SdkClientException.builder() - .message("{" + serviceName + ", " + regionName + "} was not " - + "found in region metadata. Update to latest version of SDK and try again.") - .build(); - } - - return new DefaultServiceEndpointBuilder(SERVICE_NAME, Protocol.HTTPS.toString()) - .withRegion(region) - .withProfileFile(attributes.getAttribute(SdkExecutionAttribute.PROFILE_FILE_SUPPLIER)) - .withProfileName(attributes.getAttribute(SdkExecutionAttribute.PROFILE_NAME)) - .withDualstackEnabled(attributes.getAttribute(AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED)) - .withFipsEnabled(attributes.getAttribute(AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED)) - .getServiceEndpoint(); + return AwsClientEndpointProvider.builder() + .serviceEndpointPrefix(SERVICE_NAME) + .defaultProtocol(Protocol.HTTPS.toString()) + .region(Region.of(regionName)) + .profileFile(attributes.getAttribute(SdkExecutionAttribute.PROFILE_FILE_SUPPLIER)) + .profileName(attributes.getAttribute(SdkExecutionAttribute.PROFILE_NAME)) + .dualstackEnabled( + attributes.getAttribute(AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(attributes.getAttribute(AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED)) + .build() + .clientEndpoint(); } } diff --git a/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java b/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java index 3e5438c5ded5..0ed43bf8df63 100644 --- a/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java +++ b/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java @@ -38,7 +38,7 @@ import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute; import software.amazon.awssdk.awscore.AwsExecutionAttribute; import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration; -import software.amazon.awssdk.awscore.endpoint.DefaultServiceEndpointBuilder; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.endpoint.DualstackEnabledProvider; import software.amazon.awssdk.awscore.endpoint.FipsEnabledProvider; import software.amazon.awssdk.awscore.presigner.PresignRequest; @@ -341,17 +341,20 @@ private void applyEndpoint(SdkHttpFullRequest.Builder httpRequestBuilder) { } private URI resolveEndpoint() { - if (endpointOverride != null) { - return endpointOverride; - } - - return new DefaultServiceEndpointBuilder(SERVICE_NAME, "https") - .withRegion(region) - .withProfileFile(profileFile) - .withProfileName(profileName) - .withDualstackEnabled(dualstackEnabled) - .withFipsEnabled(fipsEnabled) - .getServiceEndpoint(); + return AwsClientEndpointProvider.builder() + .clientEndpointOverride(endpointOverride) + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_POLLY") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlPolly") + .serviceProfileProperty("polly") + .serviceEndpointPrefix(SERVICE_NAME) + .defaultProtocol("https") + .region(region) + .profileFile(profileFile) + .profileName(profileName) + .dualstackEnabled(dualstackEnabled) + .fipsEnabled(fipsEnabled) + .build() + .clientEndpoint(); } public static class BuilderImpl implements PollyPresigner.Builder { diff --git a/services/rds/src/main/java/software/amazon/awssdk/services/rds/internal/RdsPresignInterceptor.java b/services/rds/src/main/java/software/amazon/awssdk/services/rds/internal/RdsPresignInterceptor.java index eae144050d6d..3e55f5ae9f24 100644 --- a/services/rds/src/main/java/software/amazon/awssdk/services/rds/internal/RdsPresignInterceptor.java +++ b/services/rds/src/main/java/software/amazon/awssdk/services/rds/internal/RdsPresignInterceptor.java @@ -25,13 +25,13 @@ import java.util.concurrent.CompletableFuture; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.AwsExecutionAttribute; -import software.amazon.awssdk.awscore.endpoint.DefaultServiceEndpointBuilder; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.Protocol; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.SelectedAuthScheme; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; -import software.amazon.awssdk.core.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.Context; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; @@ -60,13 +60,15 @@ @SdkInternalApi public abstract class RdsPresignInterceptor implements ExecutionInterceptor { - private static final URI CUSTOM_ENDPOINT_LOCALHOST = URI.create("http://localhost"); + private static final ClientEndpointProvider CUSTOM_ENDPOINT_PROVIDER_LOCALHOST = + ClientEndpointProvider.forEndpointOverride(URI.create("http://localhost")); protected static final AwsQueryProtocolFactory PROTOCOL_FACTORY = AwsQueryProtocolFactory .builder() // Need an endpoint to marshall but this will be overwritten in modifyHttpRequest .clientConfiguration(SdkClientConfiguration.builder() - .option(SdkClientOption.ENDPOINT, CUSTOM_ENDPOINT_LOCALHOST) + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + CUSTOM_ENDPOINT_PROVIDER_LOCALHOST) .build()) .build(); @@ -216,20 +218,16 @@ private SdkHttpFullRequest toSdkHttpFullRequest(SignedRequest signedRequest) { } private URI createEndpoint(String regionName, String serviceName, ExecutionAttributes attributes) { - Region region = Region.of(regionName); - if (region == null) { - throw SdkClientException.builder() - .message("{" + serviceName + ", " + regionName + "} was not " - + "found in region metadata. Update to latest version of SDK and try again.") - .build(); - } - - return new DefaultServiceEndpointBuilder(SERVICE_NAME, Protocol.HTTPS.toString()) - .withRegion(region) - .withProfileFile(attributes.getAttribute(SdkExecutionAttribute.PROFILE_FILE_SUPPLIER)) - .withProfileName(attributes.getAttribute(SdkExecutionAttribute.PROFILE_NAME)) - .withDualstackEnabled(attributes.getAttribute(AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED)) - .withFipsEnabled(attributes.getAttribute(AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED)) - .getServiceEndpoint(); + return AwsClientEndpointProvider.builder() + .serviceEndpointPrefix(SERVICE_NAME) + .defaultProtocol(Protocol.HTTPS.toString()) + .region(Region.of(regionName)) + .profileFile(attributes.getAttribute(SdkExecutionAttribute.PROFILE_FILE_SUPPLIER)) + .profileName(attributes.getAttribute(SdkExecutionAttribute.PROFILE_NAME)) + .dualstackEnabled( + attributes.getAttribute(AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(attributes.getAttribute(AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED)) + .build() + .clientEndpoint(); } } diff --git a/services/route53/src/test/java/software/amazon/awssdk/services/route53/QueryParamBindingTest.java b/services/route53/src/test/java/software/amazon/awssdk/services/route53/QueryParamBindingTest.java index 8c1cdda76b46..78a21d9e145e 100644 --- a/services/route53/src/test/java/software/amazon/awssdk/services/route53/QueryParamBindingTest.java +++ b/services/route53/src/test/java/software/amazon/awssdk/services/route53/QueryParamBindingTest.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.http.SdkHttpFullRequest; @@ -35,7 +36,8 @@ public class QueryParamBindingTest { protected static final AwsXmlProtocolFactory PROTOCOL_FACTORY = AwsXmlProtocolFactory .builder() .clientConfiguration(SdkClientConfiguration.builder() - .option(SdkClientOption.ENDPOINT, URI.create("http://localhost")) + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(URI.create("http://localhost"))) .build()) .build(); diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3Utilities.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3Utilities.java index 6175e2004247..26ed7e82e8c6 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3Utilities.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3Utilities.java @@ -35,10 +35,11 @@ import software.amazon.awssdk.awscore.AwsExecutionAttribute; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.defaultsmode.DefaultsMode; -import software.amazon.awssdk.awscore.endpoint.DefaultServiceEndpointBuilder; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.endpoint.DualstackEnabledProvider; import software.amazon.awssdk.awscore.endpoint.FipsEnabledProvider; import software.amazon.awssdk.awscore.internal.defaultsmode.DefaultsModeConfiguration; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.ClientType; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; @@ -182,8 +183,9 @@ static S3Utilities create(SdkClientConfiguration clientConfiguration) { .profileFile(clientConfiguration.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) .profileName(clientConfiguration.option(SdkClientOption.PROFILE_NAME)); - if (Boolean.TRUE.equals(clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN))) { - builder.endpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)); + ClientEndpointProvider clientEndpoint = clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER); + if (clientEndpoint.isEndpointOverridden()) { + builder.endpoint(clientEndpoint.clientEndpoint()); } return builder.build(); @@ -231,9 +233,9 @@ public URL getUrl(Consumer getUrlRequest) { public URL getUrl(GetUrlRequest getUrlRequest) { Region resolvedRegion = resolveRegionForGetUrl(getUrlRequest); URI endpointOverride = getEndpointOverride(getUrlRequest); - URI resolvedEndpoint = resolveEndpoint(endpointOverride, resolvedRegion); + ClientEndpointProvider clientEndpoint = clientEndpointProvider(endpointOverride, resolvedRegion); - SdkHttpFullRequest marshalledRequest = createMarshalledRequest(getUrlRequest, resolvedEndpoint); + SdkHttpFullRequest marshalledRequest = createMarshalledRequest(getUrlRequest, clientEndpoint); GetObjectRequest getObjectRequest = GetObjectRequest.builder() .bucket(getUrlRequest.bucket()) @@ -246,9 +248,7 @@ public URL getUrl(GetUrlRequest getUrlRequest) { .request(getObjectRequest) .build(); - ExecutionAttributes executionAttributes = createExecutionAttributes(resolvedEndpoint, - resolvedRegion, - endpointOverride != null); + ExecutionAttributes executionAttributes = createExecutionAttributes(clientEndpoint, resolvedRegion); SdkHttpRequest modifiedRequest = runInterceptors(interceptorContext, executionAttributes).httpRequest(); try { @@ -426,15 +426,20 @@ private Region resolveRegionForGetUrl(GetUrlRequest getUrlRequest) { /** * If endpoint is not present, construct a default endpoint using the region information. */ - private URI resolveEndpoint(URI overrideEndpoint, Region region) { - return overrideEndpoint != null - ? overrideEndpoint - : new DefaultServiceEndpointBuilder("s3", "https").withRegion(region) - .withProfileFile(profileFile) - .withProfileName(profileName) - .withDualstackEnabled(s3Configuration.dualstackEnabled()) - .withFipsEnabled(fipsEnabled) - .getServiceEndpoint(); + private ClientEndpointProvider clientEndpointProvider(URI overrideEndpoint, Region region) { + return AwsClientEndpointProvider.builder() + .clientEndpointOverride(overrideEndpoint) + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_S3") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlS3") + .serviceProfileProperty("s3") + .serviceEndpointPrefix(SERVICE_NAME) + .defaultProtocol("https") + .region(region) + .profileFile(profileFile) + .profileName(profileName) + .dualstackEnabled(s3Configuration.dualstackEnabled()) + .fipsEnabled(fipsEnabled) + .build(); } private URI getEndpointOverride(GetUrlRequest request) { @@ -445,13 +450,15 @@ private URI getEndpointOverride(GetUrlRequest request) { /** * Create a {@link SdkHttpFullRequest} object with the bucket and key values marshalled into the path params. */ - private SdkHttpFullRequest createMarshalledRequest(GetUrlRequest getUrlRequest, URI endpoint) { + private SdkHttpFullRequest createMarshalledRequest(GetUrlRequest getUrlRequest, + ClientEndpointProvider clientEndpoint) { OperationInfo operationInfo = OperationInfo.builder() .requestUri("/{Key+}") .httpMethod(SdkHttpMethod.HEAD) .build(); - SdkHttpFullRequest.Builder builder = ProtocolUtils.createSdkHttpRequest(operationInfo, endpoint); + SdkHttpFullRequest.Builder builder = ProtocolUtils.createSdkHttpRequest(operationInfo, + clientEndpoint.clientEndpoint()); // encode bucket builder.encodedPath(PathMarshaller.NON_GREEDY.marshall(builder.encodedPath(), @@ -472,8 +479,8 @@ private SdkHttpFullRequest createMarshalledRequest(GetUrlRequest getUrlRequest, * Create the execution attributes to provide to the endpoint interceptors. * @return */ - private ExecutionAttributes createExecutionAttributes(URI clientEndpoint, Region region, boolean isEndpointOverridden) { - ExecutionAttributes executionAttributes = new ExecutionAttributes() + private ExecutionAttributes createExecutionAttributes(ClientEndpointProvider clientEndpointProvider, Region region) { + return new ExecutionAttributes() .putAttribute(AwsExecutionAttribute.AWS_REGION, region) .putAttribute(SdkExecutionAttribute.CLIENT_TYPE, ClientType.SYNC) .putAttribute(SdkExecutionAttribute.SERVICE_NAME, SERVICE_NAME) @@ -483,14 +490,8 @@ private ExecutionAttributes createExecutionAttributes(URI clientEndpoint, Region .putAttribute(AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED, s3Configuration.dualstackEnabled()) .putAttribute(SdkInternalExecutionAttribute.ENDPOINT_PROVIDER, S3EndpointProvider.defaultProvider()) .putAttribute(SdkInternalExecutionAttribute.CLIENT_CONTEXT_PARAMS, createClientContextParams()) - .putAttribute(SdkExecutionAttribute.CLIENT_ENDPOINT, clientEndpoint) + .putAttribute(SdkInternalExecutionAttribute.CLIENT_ENDPOINT_PROVIDER, clientEndpointProvider) .putAttribute(AwsExecutionAttribute.USE_GLOBAL_ENDPOINT, useGlobalEndpointResolver.resolve(region)); - - if (isEndpointOverridden) { - executionAttributes.putAttribute(SdkExecutionAttribute.ENDPOINT_OVERRIDDEN, true); - } - - return executionAttributes; } private AttributeMap createClientContextParams() { diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultS3Presigner.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultS3Presigner.java index cef44ed8abf1..1bbb2e3917cf 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultS3Presigner.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultS3Presigner.java @@ -21,7 +21,6 @@ import static software.amazon.awssdk.utils.CollectionUtils.mergeLists; import static software.amazon.awssdk.utils.FunctionalUtils.invokeSafely; -import java.net.URI; import java.time.Clock; import java.time.Duration; import java.time.Instant; @@ -41,7 +40,7 @@ import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.defaultsmode.DefaultsMode; -import software.amazon.awssdk.awscore.endpoint.DefaultServiceEndpointBuilder; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.internal.AwsExecutionContextBuilder; import software.amazon.awssdk.awscore.internal.defaultsmode.DefaultsModeConfiguration; import software.amazon.awssdk.awscore.presigner.PresignRequest; @@ -238,23 +237,29 @@ private List initializeInterceptors() { * Copied from {@link AwsDefaultClientBuilder}. */ private SdkClientConfiguration createClientConfiguration() { - if (endpointOverride() != null) { - return SdkClientConfiguration.builder() - .option(SdkClientOption.ENDPOINT, endpointOverride()) - .option(SdkClientOption.ENDPOINT_OVERRIDDEN, true) - .build(); - } else { - URI defaultEndpoint = new DefaultServiceEndpointBuilder(SERVICE_NAME, "https") - .withRegion(region()) - .withProfileFile(profileFileSupplier()) - .withProfileName(profileName()) - .withDualstackEnabled(serviceConfiguration.dualstackEnabled()) - .withFipsEnabled(fipsEnabled()) - .getServiceEndpoint(); - return SdkClientConfiguration.builder() - .option(SdkClientOption.ENDPOINT, defaultEndpoint) - .build(); - } + AwsClientEndpointProvider endpointProvider = + AwsClientEndpointProvider.builder() + .clientEndpointOverride(endpointOverride()) + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_S3") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlS3") + .serviceProfileProperty("s3") + .serviceEndpointPrefix(SERVICE_NAME) + .defaultProtocol("https") + .region(region()) + .profileFile(profileFileSupplier()) + .profileName(profileName()) + .dualstackEnabled(serviceConfiguration.dualstackEnabled()) + .fipsEnabled(fipsEnabled()) + .build(); + + // Make sure the endpoint resolver can actually resolve an endpoint, so that we fail now instead of + // when a request is made. + endpointProvider.clientEndpoint(); + + return SdkClientConfiguration.builder() + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + endpointProvider) + .build(); } @Override @@ -394,9 +399,8 @@ private ExecutionContext invokeInterceptorsAndCreateExecutionContext(SdkRequest .putAttribute(SdkExecutionAttribute.SERVICE_CONFIG, serviceConfiguration()) .putAttribute(PRESIGNER_EXPIRATION, expiration) .putAttribute(AwsSignerExecutionAttribute.SIGNING_CLOCK, signingClock) - .putAttribute(SdkExecutionAttribute.CLIENT_ENDPOINT, clientConfiguration.option(SdkClientOption.ENDPOINT)) - .putAttribute(SdkExecutionAttribute.ENDPOINT_OVERRIDDEN, - clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN)) + .putAttribute(SdkInternalExecutionAttribute.CLIENT_ENDPOINT_PROVIDER, + clientConfiguration.option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER)) .putAttribute(AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED, fipsEnabled()) .putAttribute(AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED, serviceConfiguration.dualstackEnabled()) .putAttribute(SdkInternalExecutionAttribute.ENDPOINT_PROVIDER, S3EndpointProvider.defaultProvider()) diff --git a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/s3express/S3ExpressAuthSchemeProviderTest.java b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/s3express/S3ExpressAuthSchemeProviderTest.java index 3c0ea297b530..13c7b37ab958 100644 --- a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/s3express/S3ExpressAuthSchemeProviderTest.java +++ b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/s3express/S3ExpressAuthSchemeProviderTest.java @@ -17,12 +17,14 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import java.net.URI; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; import org.junit.jupiter.api.Test; import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; import software.amazon.awssdk.awscore.AwsExecutionAttribute; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SelectedAuthScheme; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute; @@ -72,6 +74,8 @@ private ExecutionAttributes requiredExecutionAttributes(AttributeMap clientConte DefaultIdentityProviders.builder() .putIdentityProvider(DefaultCredentialsProvider.create()) .build()); + executionAttributes.putAttribute(SdkInternalExecutionAttribute.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(URI.create("https://localhost"))); executionAttributes.putAttribute(SdkInternalExecutionAttribute.ENDPOINT_PROVIDER, S3EndpointProvider.defaultProvider()); return executionAttributes; diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/CodegenServiceClientConfigurationTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/CodegenServiceClientConfigurationTest.java index 6f7e1ce4208b..201141550d87 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/CodegenServiceClientConfigurationTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/CodegenServiceClientConfigurationTest.java @@ -28,6 +28,7 @@ import org.junit.jupiter.params.provider.MethodSource; import software.amazon.awssdk.awscore.AwsServiceClientConfiguration; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.ClientOption; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; @@ -101,6 +102,13 @@ public static List> testCases() throws Exception { .getter(ProtocolRestJsonServiceClientConfiguration.Builder::endpointOverride) .dataGetter(x -> x.endpointOverride().orElse(null)) .build(), + TestCase.builder() + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER) + .value(ClientEndpointProvider.forEndpointOverride(new URI("http://localhost:8080"))) + .setter((b, p) -> b.endpointOverride(p.clientEndpoint())) + .getter(b -> b.endpointOverride() == null ? null : ClientEndpointProvider.forEndpointOverride(b.endpointOverride())) + .dataGetter(x -> x.endpointOverride().map(ClientEndpointProvider::forEndpointOverride).orElse(null)) + .build(), TestCase.builder() .option(SdkClientOption.ENDPOINT_PROVIDER) .value(MOCK_ENDPOINT_PROVIDER) diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/EndpointSharedConfigTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/EndpointSharedConfigTest.java new file mode 100644 index 000000000000..546810cf1c50 --- /dev/null +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/EndpointSharedConfigTest.java @@ -0,0 +1,267 @@ +package software.amazon.awssdk.services; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; +import software.amazon.awssdk.profiles.ProfileFile; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonClient; +import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonClientBuilder; +import software.amazon.awssdk.testutils.EnvironmentVariableHelper; + +/** + * Tests that endpoint resolution using service-specific endpoint overrides in environment variables, system properties, + * and profile configuration functions correctly. + */ +@RunWith(Parameterized.class) +public class EndpointSharedConfigTest { + private static final String GLOBAL_ENV_VAR = "AWS_ENDPOINT_URL"; + private static final String GLOBAL_SYS_PROP = "aws.endpointUrl"; + private static final String SERVICE_ENV_VAR = "AWS_ENDPOINT_URL_AMAZONPROTOCOLRESTJSON"; + private static final String SERVICE_SYS_PROP = "aws.endpointUrlProtocolRestJson"; + + @Parameterized.Parameter + public TestCase testCase; + + @Test + public void resolvesCorrectEndpoint() { + Map systemPropertiesBeforeTest = new HashMap<>(); + systemPropertiesBeforeTest.put(GLOBAL_SYS_PROP, System.getProperty(GLOBAL_SYS_PROP)); + systemPropertiesBeforeTest.put(SERVICE_SYS_PROP, System.getProperty(SERVICE_SYS_PROP)); + + EnvironmentVariableHelper helper = new EnvironmentVariableHelper(); + + try { + ProtocolRestJsonClientBuilder builder = + ProtocolRestJsonClient.builder() + .region(Region.US_WEST_2) + .credentialsProvider(AnonymousCredentialsProvider.create()); + + if (testCase.clientSetting != null) { + builder.endpointOverride(URI.create(testCase.clientSetting)); + } + + if (testCase.globalEnvVarSetting != null) { + helper.set(GLOBAL_ENV_VAR, testCase.globalEnvVarSetting); + } + + if (testCase.serviceEnvVarSetting != null) { + helper.set(SERVICE_ENV_VAR, testCase.serviceEnvVarSetting); + } + + if (testCase.globalSystemPropSetting != null) { + System.setProperty(GLOBAL_SYS_PROP, testCase.globalSystemPropSetting); + } + + if (testCase.serviceSystemPropSetting != null) { + System.setProperty(SERVICE_SYS_PROP, testCase.serviceSystemPropSetting); + } + + StringBuilder profileFileContent = new StringBuilder(); + profileFileContent.append("[default]\n"); + if (testCase.globalProfileSetting != null) { + profileFileContent.append("endpoint_url = ").append(testCase.globalProfileSetting).append("\n"); + } + if (testCase.serviceProfileSetting != null) { + profileFileContent.append("amazonprotocolrestjson =\n") + .append(" endpoint_url = ").append(testCase.serviceProfileSetting).append("\n"); + } + + ProfileFile profileFile = + ProfileFile.builder() + .type(ProfileFile.Type.CONFIGURATION) + .content(profileFileContent.toString()) + .build(); + + EndpointCapturingInterceptor interceptor = new EndpointCapturingInterceptor(); + + builder.overrideConfiguration(c -> c.defaultProfileFile(profileFile) + .defaultProfileName("default") + .addExecutionInterceptor(interceptor)); + + ProtocolRestJsonClient client = builder.build(); + + try { + client.allTypes(); + } catch (EndpointCapturingInterceptor.CaptureCompletedException e) { + // Expected + } + + assertThat(interceptor.endpoints()) + .singleElement() + .isEqualTo(testCase.expectedEndpoint + "/2016-03-11/allTypes"); + } finally { + systemPropertiesBeforeTest.forEach((k, v) -> { + if (v != null) { + System.setProperty(k, v); + } else { + System.clearProperty(k); + } + }); + helper.reset(); + } + } + + @Parameterized.Parameters(name = "{0}") + public static Iterable testCases() { + List settingNames = + Arrays.asList("Client", + "Service system property", + "Global system property", + "Service environment variable", + "Global environment variable", + "Service profile file", + "Global profile file"); + + boolean[][] settingCombinations = getSettingCombinations(settingNames.size()); + + List testCases = new ArrayList<>(); + for (int i = 0; i < settingCombinations.length; i++) { + boolean[] settings = settingCombinations[i]; + testCases.add(createCase(settingNames, settings, i)); + } + + return testCases; + } + + private static TestCase createCase(List settingNames, + boolean[] settings, + int caseIndex) { + List falseSettings = new ArrayList<>(); + String firstTrueSetting = null; + List lowerPrioritySettings = new ArrayList<>(); + Integer expectedEndpointIndex = null; + + for (int j = 0; j < settings.length; j++) { + String settingName = settingNames.get(j); + if (settings[j] && firstTrueSetting == null) { + firstTrueSetting = settingName; + expectedEndpointIndex = j; + } else if (firstTrueSetting == null) { + falseSettings.add(settingName); + } else { + lowerPrioritySettings.add(settingName); + } + } + + // Create case name + String caseName; + if (firstTrueSetting == null) { + caseName = "(" + caseIndex + ") Defaults are used."; + } else { + caseName = "(" + caseIndex + ") " + firstTrueSetting + " setting should be used"; + if (!falseSettings.isEmpty()) { + caseName += ", because " + falseSettings + " setting(s) were not set"; + } + if (!lowerPrioritySettings.isEmpty()) { + caseName += ". " + lowerPrioritySettings + " setting(s) should be ignored"; + } + caseName += "."; + } + + return new TestCase(settings, expectedEndpointIndex, caseName); + } + + public static void printArrayOfArrays(boolean[][] arrays) { + for (boolean[] array : arrays) { + System.out.println(arrayToString(array)); + } + } + + private static String arrayToString(boolean[] array) { + StringBuilder sb = new StringBuilder("["); + for (int i = 0; i < array.length; i++) { + sb.append(array[i]); + if (i < array.length - 1) { + sb.append(", "); + } + } + sb.append("]"); + return sb.toString(); + } + + private static boolean[][] getSettingCombinations(int numSettings) { + int numCombinations = 1 << numSettings; + boolean[][] settingCombinations = new boolean[numCombinations][numSettings]; + for (int combination = 0; combination < numCombinations; combination++) { + for (int settingIndex = 0; settingIndex < numSettings; settingIndex++) { + int settingBit = 1 << settingIndex; + settingCombinations[combination][settingIndex] = (combination & settingBit) > 0; + } + } + return settingCombinations; + } + + public static class TestCase { + private static final String DEFAULT_ENDPOINT = "https://customresponsemetadata.us-west-2.amazonaws.com"; + private static final List SETTING_ENDPOINTS = + Arrays.asList("https://client-endpoint.com", + "https://service-system-property-endpoint.com", + "https://global-system-property-endpoint.com", + "https://service-env-var-endpoint.com", + "https://global-env-var-endpoint.com", + "https://service-profile-endpoint.com", + "https://global-profile-endpoint.com"); + + private final String clientSetting; + private final String serviceSystemPropSetting; + private final String globalSystemPropSetting; + private final String serviceEnvVarSetting; + private final String globalEnvVarSetting; + private final String serviceProfileSetting; + private final String globalProfileSetting; + private final String caseName; + private final String expectedEndpoint; + + public TestCase(boolean[] settings, Integer expectedEndpointIndex, String caseName) { + this(endpoint(settings, 0), endpoint(settings, 1), endpoint(settings, 2), endpoint(settings, 3), + endpoint(settings, 4), endpoint(settings, 5), endpoint(settings, 6), + endpointForIndex(expectedEndpointIndex), caseName); + } + + private static String endpoint(boolean[] settings, int i) { + if (settings[i]) { + return SETTING_ENDPOINTS.get(i); + } + return null; + } + + private static String endpointForIndex(Integer expectedEndpointIndex) { + return expectedEndpointIndex == null ? DEFAULT_ENDPOINT : SETTING_ENDPOINTS.get(expectedEndpointIndex); + } + + private TestCase(String clientSetting, + String serviceSystemPropSetting, + String globalSystemPropSetting, + String serviceEnvVarSetting, + String globalEnvVarSetting, + String serviceProfileSetting, + String globalProfileSetting, + String expectedEndpoint, + String caseName) { + this.clientSetting = clientSetting; + this.serviceSystemPropSetting = serviceSystemPropSetting; + this.globalSystemPropSetting = globalSystemPropSetting; + this.serviceEnvVarSetting = serviceEnvVarSetting; + this.globalEnvVarSetting = globalEnvVarSetting; + this.serviceProfileSetting = serviceProfileSetting; + this.globalProfileSetting = globalProfileSetting; + this.expectedEndpoint = expectedEndpoint; + this.caseName = caseName; + } + + @Override + public String toString() { + return caseName; + } + } +} diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/endpointproviders/AwsEndpointProviderUtilsTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/endpointproviders/AwsEndpointProviderUtilsTest.java index b48e27c99e5f..ff6cc0595753 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/endpointproviders/AwsEndpointProviderUtilsTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/endpointproviders/AwsEndpointProviderUtilsTest.java @@ -19,47 +19,29 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.net.URI; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; import org.junit.Test; import software.amazon.awssdk.awscore.AwsExecutionAttribute; -import software.amazon.awssdk.awscore.endpoints.AwsEndpointAttribute; -import software.amazon.awssdk.awscore.endpoints.authscheme.EndpointAuthScheme; -import software.amazon.awssdk.awscore.endpoints.authscheme.SigV4AuthScheme; -import software.amazon.awssdk.awscore.endpoints.authscheme.SigV4aAuthScheme; -import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; -import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute; import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute; import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.SdkHttpMethod; import software.amazon.awssdk.http.SdkHttpRequest; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.restjsonendpointproviders.endpoints.internal.AwsEndpointProviderUtils; -import software.amazon.awssdk.services.restjsonendpointproviders.endpoints.internal.Identifier; -import software.amazon.awssdk.services.restjsonendpointproviders.endpoints.internal.Value; -import software.amazon.awssdk.utils.MapUtils; public class AwsEndpointProviderUtilsTest { @Test public void endpointOverridden_attrIsFalse_returnsFalse() { ExecutionAttributes attrs = new ExecutionAttributes(); - attrs.putAttribute(SdkExecutionAttribute.ENDPOINT_OVERRIDDEN, false); - assertThat(AwsEndpointProviderUtils.endpointIsOverridden(attrs)).isFalse(); - } - - @Test - public void endpointOverridden_attrIsAbsent_returnsFalse() { - ExecutionAttributes attrs = new ExecutionAttributes(); + attrs.putAttribute(SdkInternalExecutionAttribute.CLIENT_ENDPOINT_PROVIDER, endpointProvider(false)); assertThat(AwsEndpointProviderUtils.endpointIsOverridden(attrs)).isFalse(); } @Test public void endpointOverridden_attrIsTrue_returnsTrue() { ExecutionAttributes attrs = new ExecutionAttributes(); - attrs.putAttribute(SdkExecutionAttribute.ENDPOINT_OVERRIDDEN, true); + attrs.putAttribute(SdkInternalExecutionAttribute.CLIENT_ENDPOINT_PROVIDER, endpointProvider(true)); assertThat(AwsEndpointProviderUtils.endpointIsOverridden(attrs)).isTrue(); } @@ -128,8 +110,8 @@ public void fipsEnabledBuiltIn_returnsAttrValue() { public void endpointBuiltIn_doesNotIncludeQueryParams() { URI endpoint = URI.create("https://example.com/path?foo=bar"); ExecutionAttributes attrs = new ExecutionAttributes(); - attrs.putAttribute(SdkExecutionAttribute.ENDPOINT_OVERRIDDEN, true); - attrs.putAttribute(SdkExecutionAttribute.CLIENT_ENDPOINT, endpoint); + attrs.putAttribute(SdkInternalExecutionAttribute.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(endpoint)); assertThat(AwsEndpointProviderUtils.endpointBuiltIn(attrs).toString()).isEqualTo("https://example.com/path"); } @@ -231,4 +213,8 @@ public void addHostPrefix_prefixInvalid_throws() { .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("component must match the pattern"); } + + private static ClientEndpointProvider endpointProvider(boolean isEndpointOverridden) { + return ClientEndpointProvider.create(URI.create("https://foo.aws"), isEndpointOverridden); + } } diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/protocolrestjson/ServiceRequestRequiredValidationMarshallingTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/protocolrestjson/ServiceRequestRequiredValidationMarshallingTest.java index c6f94334d19a..1e8cc9952935 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/protocolrestjson/ServiceRequestRequiredValidationMarshallingTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/protocolrestjson/ServiceRequestRequiredValidationMarshallingTest.java @@ -26,6 +26,7 @@ import java.util.stream.Stream; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.core.exception.SdkClientException; @@ -45,7 +46,8 @@ static void setup() { .builder() .clientConfiguration(SdkClientConfiguration .builder() - .option(SdkClientOption.ENDPOINT, URI.create("http://localhost")) + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(URI.create("http://localhost"))) .build()) .build(); marshaller = new QueryParameterOperationRequestMarshaller(awsJsonProtocolFactory); diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/protocolrestxml/ServiceRequestRequiredValidationMarshallingTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/protocolrestxml/ServiceRequestRequiredValidationMarshallingTest.java index 523116357ed5..df8d076d2cd9 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/protocolrestxml/ServiceRequestRequiredValidationMarshallingTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/protocolrestxml/ServiceRequestRequiredValidationMarshallingTest.java @@ -26,6 +26,7 @@ import java.util.stream.Stream; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.core.exception.SdkClientException; @@ -45,7 +46,8 @@ static void setup() { .builder() .clientConfiguration(SdkClientConfiguration .builder() - .option(SdkClientOption.ENDPOINT, URI.create("http://localhost")) + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(URI.create("http://localhost"))) .build()) .build(); marshaller = new QueryParameterOperationRequestMarshaller(awsXmlProtocolFactory); diff --git a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/EventTransformTest.java b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/EventTransformTest.java index 93b89c178064..ee15db527df2 100644 --- a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/EventTransformTest.java +++ b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/EventTransformTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import software.amazon.awssdk.core.SdkBytes; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPojo; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; @@ -53,7 +54,8 @@ public static void setup() { protocolFactory = AwsJsonProtocolFactory.builder() .clientConfiguration( SdkClientConfiguration.builder() - .option(SdkClientOption.ENDPOINT, URI.create("http://foo.amazonaws.com")) + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(URI.create("http://foo.amazonaws.com"))) .build()) .protocol(AwsJsonProtocol.AWS_JSON) .build(); diff --git a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/RestJsonEventStreamProtocolTest.java b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/RestJsonEventStreamProtocolTest.java index 0b2ddebb80e8..d03b14066d52 100644 --- a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/RestJsonEventStreamProtocolTest.java +++ b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/RestJsonEventStreamProtocolTest.java @@ -23,7 +23,6 @@ import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static com.github.tomakehurst.wiremock.client.WireMock.verify; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.in; import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; import com.github.tomakehurst.wiremock.junit5.WireMockTest; @@ -33,6 +32,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import software.amazon.awssdk.core.SdkBytes; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.http.ContentStreamProvider; @@ -162,8 +162,8 @@ private static AwsJsonProtocolFactory protocolFactory() { return AwsJsonProtocolFactory.builder() .clientConfiguration( SdkClientConfiguration.builder() - .option(SdkClientOption.ENDPOINT, - URI.create("https://test.aws.com")) + .option(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(URI.create("http://test.aws.com"))) .build()) .defaultServiceExceptionSupplier(ProtocolRestJsonContentTypeException::builder) .protocol(AwsJsonProtocol.REST_JSON) diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/enhanced/dynamodb/EnhancedClientGetOverheadBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/enhanced/dynamodb/EnhancedClientGetOverheadBenchmark.java index ce2fdf38786a..e1baf688de19 100644 --- a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/enhanced/dynamodb/EnhancedClientGetOverheadBenchmark.java +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/enhanced/dynamodb/EnhancedClientGetOverheadBenchmark.java @@ -15,7 +15,7 @@ package software.amazon.awssdk.benchmark.enhanced.dynamodb; -import static software.amazon.awssdk.core.client.config.SdkClientOption.ENDPOINT; +import static software.amazon.awssdk.core.client.config.SdkClientOption.CLIENT_ENDPOINT_PROVIDER; import java.io.IOException; import java.io.UncheckedIOException; @@ -35,6 +35,7 @@ import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.benchmark.utils.MockHttpClient; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.interceptor.Context; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; @@ -62,7 +63,8 @@ public class EnhancedClientGetOverheadBenchmark { private static final AwsJsonProtocolFactory JSON_PROTOCOL_FACTORY = AwsJsonProtocolFactory .builder() .clientConfiguration(SdkClientConfiguration.builder() - .option(ENDPOINT, URI.create("https://dynamodb.amazonaws.com")) + .option(CLIENT_ENDPOINT_PROVIDER, + ClientEndpointProvider.forEndpointOverride(URI.create("https://dynamodb.amazonaws.com"))) .build()) .defaultServiceExceptionSupplier(DynamoDbException::builder) .protocol(AwsJsonProtocol.AWS_JSON)