diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java index e676ad9eb51..596d44bcf14 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java @@ -19,7 +19,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import software.amazon.awssdk.awscore.internal.client.ClientComposer; +import software.amazon.awssdk.codegen.model.service.ClientContextParam; import software.amazon.awssdk.core.retry.RetryMode; import software.amazon.awssdk.core.traits.PayloadTrait; import software.amazon.awssdk.utils.AttributeMap; @@ -216,16 +216,16 @@ public class CustomizationConfig { /** * Fully qualified name of a class that given the default sync client instance can return the final client instance, * for instance by decorating the client with specific-purpose implementations of the client interface. - * The class should implement the {@link ClientComposer} interface. See S3 customization.config for an example. + * See S3 customization.config for an example. */ - private String syncClientComposer; + private String syncClientDecorator; /** * Fully qualified name of a class that given the default async client instance can return the final client instance, * for instance by decorating the client with specific-purpose implementations of the client interface. - * The class should implement the {@link ClientComposer} interface. See S3 customization.config for an example. + * See S3 customization.config for an example. */ - private String asyncClientComposer; + private String asyncClientDecorator; /** * Whether to skip generating endpoint tests from endpoint-tests.json @@ -251,6 +251,11 @@ public class CustomizationConfig { */ private boolean requiredTraitValidationEnabled = false; + /** + * Customization to attach map of Custom client param configs that can be set on a client builder. + */ + private Map customClientContextParams; + private CustomizationConfig() { } @@ -581,20 +586,20 @@ public void setDelegateAsyncClientClass(boolean delegateAsyncClientClass) { this.delegateAsyncClientClass = delegateAsyncClientClass; } - public String getSyncClientComposer() { - return syncClientComposer; + public String getSyncClientDecorator() { + return syncClientDecorator; } - public void setSyncClientComposer(String syncClientComposer) { - this.syncClientComposer = syncClientComposer; + public void setSyncClientDecorator(String syncClientDecorator) { + this.syncClientDecorator = syncClientDecorator; } - public String getAsyncClientComposer() { - return asyncClientComposer; + public String getAsyncClientDecorator() { + return asyncClientDecorator; } - public void setAsyncClientComposer(String asyncClientComposer) { - this.asyncClientComposer = asyncClientComposer; + public void setAsyncClientDecorator(String asyncClientDecorator) { + this.asyncClientDecorator = asyncClientDecorator; } public boolean isDelegateSyncClientClass() { @@ -652,4 +657,12 @@ public boolean isRequiredTraitValidationEnabled() { public void setRequiredTraitValidationEnabled(boolean requiredTraitValidationEnabled) { this.requiredTraitValidationEnabled = requiredTraitValidationEnabled; } + + public Map getCustomClientContextParams() { + return customClientContextParams; + } + + public void setCustomClientContextParams(Map customClientContextParams) { + this.customClientContextParams = customClientContextParams; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/IntermediateModel.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/IntermediateModel.java index 087b8ded763..28113a0d8b3 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/IntermediateModel.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/IntermediateModel.java @@ -235,17 +235,17 @@ public String getSdkResponseBaseClassName() { } } - public Optional syncClientComposerClassName() { - if (customizationConfig.getSyncClientComposer() != null) { - return Optional.of(customizationConfig.getSyncClientComposer()); + public Optional syncClientDecoratorClassName() { + if (customizationConfig.getSyncClientDecorator() != null) { + return Optional.of(customizationConfig.getSyncClientDecorator()); } return Optional.empty(); } - public Optional asyncClientComposerClassName() { - String asyncClientComposer = customizationConfig.getAsyncClientComposer(); - if (customizationConfig.getAsyncClientComposer() != null) { - return Optional.of(asyncClientComposer); + public Optional asyncClientDecoratorClassName() { + String asyncClientDecorator = customizationConfig.getAsyncClientDecorator(); + if (customizationConfig.getAsyncClientDecorator() != null) { + return Optional.of(asyncClientDecorator); } return Optional.empty(); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/AsyncClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/AsyncClientBuilderClass.java index 8001f5601c0..22df0e8502c 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/AsyncClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/AsyncClientBuilderClass.java @@ -28,7 +28,6 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.token.credentials.SdkTokenProvider; import software.amazon.awssdk.awscore.client.config.AwsClientOption; -import software.amazon.awssdk.awscore.internal.client.ClientComposer; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.poet.ClassSpec; import software.amazon.awssdk.codegen.poet.PoetExtension; @@ -148,11 +147,9 @@ private MethodSpec buildClientMethod() { builder.addStatement("$1T client = new $2T(serviceClientConfiguration, clientConfiguration)", clientInterfaceName, clientClassName); - if (model.asyncClientComposerClassName().isPresent()) { - builder.addStatement("$1T composer = new $2T()", - ClientComposer.class, - PoetUtils.classNameFromFqcn(model.asyncClientComposerClassName().get())); - builder.addStatement("return ($T) composer.compose(client, clientConfiguration)", clientInterfaceName); + if (model.asyncClientDecoratorClassName().isPresent()) { + builder.addStatement("return new $T().decorate(client, clientConfiguration, clientContextParams.copy().build())", + PoetUtils.classNameFromFqcn(model.asyncClientDecoratorClassName().get())); } else { builder.addStatement("return client"); } 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 72d534d5ab9..9a2b541220a 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 @@ -117,6 +117,12 @@ public TypeSpec poetSpec() { }); } + if (hasSdkClientContextParams()) { + model.getCustomizationConfig().getCustomClientContextParams().forEach((n, m) -> { + builder.addMethod(clientContextParamSetter(n, m)); + }); + } + if (model.getCustomizationConfig().getServiceConfig().getClassName() != null) { builder.addMethod(setServiceConfigurationMethod()) .addMethod(beanStyleSetServiceConfigurationMethod()); @@ -609,6 +615,12 @@ private boolean hasClientContextParams() { return clientContextParams != null && !clientContextParams.isEmpty(); } + private boolean hasSdkClientContextParams() { + return model.getCustomizationConfig() != null + && model.getCustomizationConfig().getCustomClientContextParams() != null + && !model.getCustomizationConfig().getCustomClientContextParams().isEmpty(); + } + private MethodSpec validateClientOptionsMethod() { MethodSpec.Builder builder = MethodSpec.methodBuilder("validateClientOptions") .addModifiers(PROTECTED, Modifier.STATIC) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderInterface.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderInterface.java index a65d8ae6398..0aac740152b 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderInterface.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderInterface.java @@ -80,6 +80,12 @@ public TypeSpec poetSpec() { }); } + if (hasSdkClientContextParams()) { + model.getCustomizationConfig().getCustomClientContextParams().forEach((n, m) -> { + builder.addMethod(clientContextParamSetter(n, m)); + }); + } + if (generateTokenProviderMethod()) { builder.addMethod(tokenProviderMethod()); } @@ -193,4 +199,10 @@ public ClassName className() { private boolean hasClientContextParams() { return model.getClientContextParams() != null && !model.getClientContextParams().isEmpty(); } + + private boolean hasSdkClientContextParams() { + return model.getCustomizationConfig() != null + && model.getCustomizationConfig().getCustomClientContextParams() != null + && !model.getCustomizationConfig().getCustomClientContextParams().isEmpty(); + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/SyncClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/SyncClientBuilderClass.java index bbed1b8f5a6..869d1e575b1 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/SyncClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/SyncClientBuilderClass.java @@ -28,7 +28,6 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.token.credentials.SdkTokenProvider; import software.amazon.awssdk.awscore.client.config.AwsClientOption; -import software.amazon.awssdk.awscore.internal.client.ClientComposer; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.poet.ClassSpec; import software.amazon.awssdk.codegen.poet.PoetExtension; @@ -141,16 +140,13 @@ private MethodSpec buildClientMethod() { .addStatement("$T serviceClientConfiguration = initializeServiceClientConfig" + "(clientConfiguration)", serviceConfigClassName); - addQueryProtocolInterceptors(builder); builder.addStatement("$1T client = new $2T(serviceClientConfiguration, clientConfiguration)", clientInterfaceName, clientClassName); - if (model.syncClientComposerClassName().isPresent()) { - builder.addStatement("$1T composer = new $2T()", - ClientComposer.class, - PoetUtils.classNameFromFqcn(model.syncClientComposerClassName().get())); - builder.addStatement("return ($T) composer.compose(client, clientConfiguration)", clientInterfaceName); + if (model.syncClientDecoratorClassName().isPresent()) { + builder.addStatement("return new $T().decorate(client, clientConfiguration, clientContextParams.copy().build())", + PoetUtils.classNameFromFqcn(model.syncClientDecoratorClassName().get())); } else { builder.addStatement("return client"); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules/ClientContextParamsClassSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules/ClientContextParamsClassSpec.java index 46bad58f254..f4923eb6b87 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules/ClientContextParamsClassSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules/ClientContextParamsClassSpec.java @@ -54,6 +54,12 @@ public TypeSpec poetSpec() { b.addField(paramDeclaration(n, m)); }); + if (model.getCustomizationConfig() != null && model.getCustomizationConfig().getCustomClientContextParams() != null) { + model.getCustomizationConfig().getCustomClientContextParams().forEach((n, m) -> { + b.addField(paramDeclaration(n, m)); + }); + } + return b.build(); } diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/builder/BuilderClassTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/builder/BuilderClassTest.java index 453b4ffbc24..6eca13643d0 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/builder/BuilderClassTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/builder/BuilderClassTest.java @@ -83,6 +83,17 @@ public void syncComposedClientBuilderClass() throws Exception { validateComposedClientGeneration(SyncClientBuilderClass::new, "test-composed-sync-client-builder-class.java"); } + @Test + public void syncComposedDefaultClientBuilderClass() throws Exception { + validateComposedClientGeneration(BaseClientBuilderClass::new, "test-composed-sync-default-client-builder.java"); + } + + @Test + public void syncHasCrossRegionAccessEnabledPropertyBuilderClass() throws Exception { + validateComposedClientGeneration(BaseClientBuilderInterface::new, "test-customcontextparams-sync-client-builder-class.java"); + } + + @Test public void asyncClientBuilderInterface() throws Exception { validateGeneration(AsyncClientBuilderInterface::new, "test-async-client-builder-interface.java"); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-async-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-async-client-builder-class.java index 44de013f10e..a95cb03bd17 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-async-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-async-client-builder-class.java @@ -5,11 +5,10 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.token.credentials.SdkTokenProvider; import software.amazon.awssdk.awscore.client.config.AwsClientOption; -import software.amazon.awssdk.awscore.internal.client.ClientComposer; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.endpoints.EndpointProvider; -import software.amazon.awssdk.services.builder.AsyncClientComposer; +import software.amazon.awssdk.services.builder.AsyncClientDecorator; import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; /** @@ -37,8 +36,7 @@ protected final JsonAsyncClient buildClient() { this.validateClientOptions(clientConfiguration); JsonServiceClientConfiguration serviceClientConfiguration = initializeServiceClientConfig(clientConfiguration); JsonAsyncClient client = new DefaultJsonAsyncClient(serviceClientConfiguration, clientConfiguration); - ClientComposer composer = new AsyncClientComposer(); - return (JsonAsyncClient) composer.compose(client, clientConfiguration); + return new AsyncClientDecorator().decorate(client, clientConfiguration, clientContextParams.copy().build()); } private JsonServiceClientConfiguration initializeServiceClientConfig(SdkClientConfiguration clientConfig) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-client-builder-class.java index 0f6a077fc47..47887e3135c 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-client-builder-class.java @@ -5,11 +5,10 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.token.credentials.SdkTokenProvider; import software.amazon.awssdk.awscore.client.config.AwsClientOption; -import software.amazon.awssdk.awscore.internal.client.ClientComposer; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.endpoints.EndpointProvider; -import software.amazon.awssdk.services.builder.SyncClientComposer; +import software.amazon.awssdk.services.builder.SyncClientDecorator; import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; /** @@ -37,8 +36,7 @@ protected final JsonClient buildClient() { this.validateClientOptions(clientConfiguration); JsonServiceClientConfiguration serviceClientConfiguration = initializeServiceClientConfig(clientConfiguration); JsonClient client = new DefaultJsonClient(serviceClientConfiguration, clientConfiguration); - ClientComposer composer = new SyncClientComposer(); - return (JsonClient) composer.compose(client, clientConfiguration); + return new SyncClientDecorator().decorate(client, clientConfiguration, clientContextParams.copy().build()); } private JsonServiceClientConfiguration initializeServiceClientConfig(SdkClientConfiguration clientConfig) { 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 new file mode 100644 index 00000000000..b352d7b685d --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java @@ -0,0 +1,120 @@ +package software.amazon.awssdk.services.json; + +import java.util.ArrayList; +import java.util.List; +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.auth.signer.Aws4Signer; +import software.amazon.awssdk.auth.token.credentials.SdkTokenProvider; +import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; +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.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.ClasspathInterceptorChainFactory; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.awssdk.core.signer.Signer; +import software.amazon.awssdk.services.json.endpoints.JsonClientContextParams; +import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; +import software.amazon.awssdk.services.json.endpoints.internal.JsonEndpointAuthSchemeInterceptor; +import software.amazon.awssdk.services.json.endpoints.internal.JsonRequestSetEndpointInterceptor; +import software.amazon.awssdk.services.json.endpoints.internal.JsonResolveEndpointInterceptor; +import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.Validate; + +/** + * Internal base class for {@link DefaultJsonClientBuilder} and {@link DefaultJsonAsyncClientBuilder}. + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +abstract class DefaultJsonBaseClientBuilder, C> extends AwsDefaultClientBuilder { + @Override + protected final String serviceEndpointPrefix() { + return "json-service-endpoint"; + } + + @Override + protected final String serviceName() { + return "Json"; + } + + @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()) + .option(AwsClientOption.TOKEN_PROVIDER, defaultTokenProvider()) + .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); + } + + @Override + protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientConfiguration config) { + List endpointInterceptors = new ArrayList<>(); + endpointInterceptors.add(new JsonResolveEndpointInterceptor()); + endpointInterceptors.add(new JsonEndpointAuthSchemeInterceptor()); + endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); + ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); + List interceptors = interceptorFactory + .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(); + serviceConfigBuilder.profileFile(serviceConfigBuilder.profileFileSupplier() != null ? serviceConfigBuilder + .profileFileSupplier() : config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)); + serviceConfigBuilder.profileName(serviceConfigBuilder.profileName() != null ? serviceConfigBuilder.profileName() : config + .option(SdkClientOption.PROFILE_NAME)); + ServiceConfiguration finalServiceConfig = serviceConfigBuilder.build(); + return config.toBuilder().option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors) + .option(SdkClientOption.SERVICE_CONFIGURATION, finalServiceConfig).build(); + } + + private Signer defaultSigner() { + return Aws4Signer.create(); + } + + @Override + protected final String signingName() { + return "json-service"; + } + + private JsonEndpointProvider defaultEndpointProvider() { + return JsonEndpointProvider.defaultProvider(); + } + + public B customParameter(Boolean customParameter) { + clientContextParams.put(JsonClientContextParams.CUSTOM_PARAMETER, customParameter); + return thisBuilder(); + } + + public B serviceConfiguration(ServiceConfiguration serviceConfiguration) { + clientConfiguration.option(SdkClientOption.SERVICE_CONFIGURATION, serviceConfiguration); + return thisBuilder(); + } + + public void setServiceConfiguration(ServiceConfiguration serviceConfiguration) { + serviceConfiguration(serviceConfiguration); + } + + private SdkTokenProvider defaultTokenProvider() { + return DefaultAwsTokenProvider.create(); + } + + private Signer defaultTokenSigner() { + return BearerTokenSigner.create(); + } + + protected static void validateClientOptions(SdkClientConfiguration c) { + Validate.notNull(c.option(SdkAdvancedClientOption.SIGNER), + "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."); + Validate.notNull(c.option(AwsClientOption.TOKEN_PROVIDER), + "The 'overrideConfiguration.advancedOption[TOKEN_PROVIDER]' must be configured in the client builder."); + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-customcontextparams-sync-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-customcontextparams-sync-client-builder-class.java new file mode 100644 index 00000000000..3c39bb9fc9c --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-customcontextparams-sync-client-builder-class.java @@ -0,0 +1,46 @@ +package software.amazon.awssdk.services.json; + +import java.util.function.Consumer; +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.auth.token.credentials.SdkTokenProvider; +import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder; +import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; + +/** + * This includes configuration specific to Json Service that is supported by both {@link JsonClientBuilder} and + * {@link JsonAsyncClientBuilder}. + */ +@Generated("software.amazon.awssdk:codegen") +public interface JsonBaseClientBuilder, C> extends AwsClientBuilder { + B serviceConfiguration(ServiceConfiguration serviceConfiguration); + + default B serviceConfiguration(Consumer serviceConfiguration) { + return serviceConfiguration(ServiceConfiguration.builder().applyMutation(serviceConfiguration).build()); + } + + /** + * Set the {@link JsonEndpointProvider} implementation that will be used by the client to determine the endpoint for + * each request. This is optional; if none is provided a default implementation will be used the SDK. + */ + default B endpointProvider(JsonEndpointProvider endpointProvider) { + throw new UnsupportedOperationException(); + } + + /** + * Enables this client to use Custom Parameter + */ + B customParameter(Boolean customParameter); + + /** + * Set the token provider to use for bearer token authorization. This is optional, if none is provided, the SDK will + * use {@link software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider}. + *

+ * If the service, or any of its operations require Bearer Token Authorization, then the SDK will default to this + * token provider to retrieve the token to use for authorization. + *

+ * This provider works in conjunction with the + * {@code software.amazon.awssdk.core.client.config.SdkAdvancedClientOption.TOKEN_SIGNER} set on the client. By + * default it is {@link software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner}. + */ + B tokenProvider(SdkTokenProvider tokenProvider); +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/composedclient/customization.config b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/composedclient/customization.config index 37769f4786a..5f33dce1133 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/composedclient/customization.config +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/composedclient/customization.config @@ -1,19 +1,20 @@ { "serviceConfig": { "className": "ServiceConfiguration", - "hasDualstackProperty": true, - "hasFipsProperty": true, - "hasUseArnRegionProperty": true, - "hasMultiRegionEnabledProperty": true, - "hasPathStyleAccessEnabledProperty":true, - "hasAccelerateModeEnabledProperty":true + "hasCrossRegionAccessEnabledProperty": true }, "utilitiesMethod": { "returnType": "software.amazon.awssdk.services.json.JsonUtilities", "createMethodParams": ["param1", "param2", "param3"] }, - "syncClientComposer": "software.amazon.awssdk.services.builder.SyncClientComposer", - "asyncClientComposer": "software.amazon.awssdk.services.builder.AsyncClientComposer", + "syncClientDecorator": "software.amazon.awssdk.services.builder.SyncClientDecorator", + "asyncClientDecorator": "software.amazon.awssdk.services.builder.AsyncClientDecorator", "asyncClientDecoratorClass": true, - "syncClientDecoratorClass": true + "syncClientDecoratorClass": true, + "customClientContextParams":{ + "CustomParameter":{ + "documentation":"Enables this client to use Custom Parameter", + "type":"boolean" + } + } } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/client/ClientComposer.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/client/ClientComposer.java deleted file mode 100644 index 2407e20f062..00000000000 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/client/ClientComposer.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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.internal.client; - -import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.awscore.AwsClient; -import software.amazon.awssdk.core.client.config.SdkClientConfiguration; - -@SdkInternalApi -public interface ClientComposer { - T compose(T base, SdkClientConfiguration clientConfiguration); -} diff --git a/services/s3/src/it/java/software/amazon/awssdk/services/s3/crossregion/S3CrossRegionAsyncIntegrationTest.java b/services/s3/src/it/java/software/amazon/awssdk/services/s3/crossregion/S3CrossRegionAsyncIntegrationTest.java index d986ee1e3e2..6fd43016dc0 100644 --- a/services/s3/src/it/java/software/amazon/awssdk/services/s3/crossregion/S3CrossRegionAsyncIntegrationTest.java +++ b/services/s3/src/it/java/software/amazon/awssdk/services/s3/crossregion/S3CrossRegionAsyncIntegrationTest.java @@ -40,7 +40,7 @@ static void clearClass() { public void initialize() { crossRegionS3Client = S3AsyncClient.builder() .region(CROSS_REGION) - .serviceConfiguration(s -> s.crossRegionAccessEnabled(true)) + .crossRegionAccessEnabled(true) .build(); } diff --git a/services/s3/src/it/java/software/amazon/awssdk/services/s3/crossregion/S3CrossRegionSyncIntegrationTest.java b/services/s3/src/it/java/software/amazon/awssdk/services/s3/crossregion/S3CrossRegionSyncIntegrationTest.java index 53813954c95..e7e68b6dac6 100644 --- a/services/s3/src/it/java/software/amazon/awssdk/services/s3/crossregion/S3CrossRegionSyncIntegrationTest.java +++ b/services/s3/src/it/java/software/amazon/awssdk/services/s3/crossregion/S3CrossRegionSyncIntegrationTest.java @@ -60,7 +60,7 @@ static void clearClass() { public void initialize() { crossRegionS3Client = S3Client.builder() .region(CROSS_REGION) - .serviceConfiguration(s -> s.crossRegionAccessEnabled(true)) + .crossRegionAccessEnabled(true) .build(); } diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3Configuration.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3Configuration.java index fe95e13c2ea..5dec8e93602 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3Configuration.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3Configuration.java @@ -64,16 +64,11 @@ public final class S3Configuration implements ServiceConfiguration, ToCopyableBu */ private static final boolean DEFAULT_CHUNKED_ENCODING_ENABLED = true; - private static final boolean DEFAULT_CROSS_REGION_ACCESS_ENABLED = false; - - private final FieldWithDefault pathStyleAccessEnabled; private final FieldWithDefault accelerateModeEnabled; private final FieldWithDefault dualstackEnabled; private final FieldWithDefault checksumValidationEnabled; private final FieldWithDefault chunkedEncodingEnabled; - private final FieldWithDefault crossRegionAccessEnabled; - private final Boolean useArnRegionEnabled; private final Boolean multiRegionEnabled; private final FieldWithDefault> profileFile; @@ -95,9 +90,6 @@ private S3Configuration(DefaultS3ServiceConfigurationBuilder builder) { if (accelerateModeEnabled() && pathStyleAccessEnabled()) { throw new IllegalArgumentException("Accelerate mode cannot be used with path style addressing"); } - this.crossRegionAccessEnabled = FieldWithDefault.create(builder.crossRegionAccessEnabled, - DEFAULT_CROSS_REGION_ACCESS_ENABLED); - } private boolean resolveUseArnRegionEnabled() { @@ -214,18 +206,6 @@ public boolean multiRegionEnabled() { .orElseGet(this::resolveMultiRegionEnabled); } - - - /** - * Returns whether the client is allowed to make cross-region calls based on bucket names. - *

- * @return True if cross Region Bucket Access Enabled - */ - public boolean crossRegionAccessEnabled() { - return crossRegionAccessEnabled.value(); - } - - @Override public Builder toBuilder() { return builder() @@ -237,8 +217,7 @@ public Builder toBuilder() { .chunkedEncodingEnabled(chunkedEncodingEnabled.valueOrNullIfDefault()) .useArnRegionEnabled(useArnRegionEnabled) .profileFile(profileFile.valueOrNullIfDefault()) - .profileName(profileName.valueOrNullIfDefault()) - .crossRegionAccessEnabled(crossRegionAccessEnabled.valueOrNullIfDefault()); + .profileName(profileName.valueOrNullIfDefault()); } @NotThreadSafe @@ -376,33 +355,6 @@ public interface Builder extends CopyableBuilder { *

*/ Builder profileName(String profileName); - - /** - *

Configures whether cross-region bucket access is enabled for clients using the configuration. - *

The following behavior is used when this mode is enabled: - *

    - *
  1. This method allows enabling or disabling cross-region bucket access for clients. When cross-region bucket - * access is enabled, requests that do not act on an existing bucket (e.g., createBucket API) will be routed to the - * region configured on the client
  2. - *
  3. The first time a request is made that references an existing bucket (e.g., putObject API), a request will be - * made to the client-configured region. If the bucket does not exist in this region, the service will include the - * actual region in the error responses. Subsequently, the API will be called using the correct region obtained - * from the error response.
  4. - *
  5. This location may be cached in the client for subsequent requests to the same bucket.
  6. - *
- *

Enabling this mode has several drawbacks, as it can increase latency if the bucket's location is physically far - * from the location of the request.Therefore, it is strongly advised, whenever possible, to know the location of your - * buckets and create a region-specific client to access them - * - * @param crossRegionAccessEnabled Whether cross region bucket access should be enabled. - * @return The builder object for method chaining. - */ - Builder crossRegionAccessEnabled(Boolean crossRegionAccessEnabled); - - /** - * Returns value of crossRegionAccessEnabled value set using {@link Builder#crossRegionAccessEnabled(Boolean)} - */ - Boolean crossRegionAccessEnabled(); } static final class DefaultS3ServiceConfigurationBuilder implements Builder { @@ -416,8 +368,6 @@ static final class DefaultS3ServiceConfigurationBuilder implements Builder { private Supplier profileFile; private String profileName; - private Boolean crossRegionAccessEnabled; - @Override public Boolean dualstackEnabled() { return dualstackEnabled; @@ -555,26 +505,6 @@ public void setUseArnRegionEnabled(Boolean useArnRegionEnabled) { useArnRegionEnabled(useArnRegionEnabled); } - - @Override - public Boolean crossRegionAccessEnabled() { - return crossRegionAccessEnabled; - } - - @Override - public Builder crossRegionAccessEnabled(Boolean crossRegionAccessEnabled) { - this.crossRegionAccessEnabled = crossRegionAccessEnabled; - return this; - } - - /** - * refer {@link Builder#crossRegionAccessEnabled(Boolean)} - * @param crossRegionAccessEnabled - */ - public void setCrossRegionAccessEnabled(Boolean crossRegionAccessEnabled) { - crossRegionAccessEnabled(crossRegionAccessEnabled); - } - @Override public S3Configuration build() { return new S3Configuration(this); 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 3e9c32b0ff4..6fcc596ced2 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 @@ -499,7 +499,6 @@ private AttributeMap createClientContextParams() { !s3Configuration.multiRegionEnabled()); params.put(S3ClientContextParams.FORCE_PATH_STYLE, s3Configuration.pathStyleAccessEnabled()); params.put(S3ClientContextParams.ACCELERATE, s3Configuration.accelerateModeEnabled()); - return params.build(); } diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3AsyncClientComposer.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3AsyncClientDecorator.java similarity index 65% rename from services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3AsyncClientComposer.java rename to services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3AsyncClientDecorator.java index fa9fddae4ff..2dbb61091da 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3AsyncClientComposer.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3AsyncClientDecorator.java @@ -19,31 +19,31 @@ import java.util.List; import java.util.function.Predicate; import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.awscore.internal.client.ClientComposer; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; -import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.services.s3.S3AsyncClient; -import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.endpoints.S3ClientContextParams; import software.amazon.awssdk.services.s3.internal.crossregion.S3CrossRegionAsyncClient; +import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.ConditionalDecorator; @SdkInternalApi -public class S3AsyncClientComposer implements ClientComposer { +public class S3AsyncClientDecorator { - public S3AsyncClientComposer() { + public S3AsyncClientDecorator() { } - @Override - public S3AsyncClient compose(S3AsyncClient base, SdkClientConfiguration clientConfiguration) { + public S3AsyncClient decorate(S3AsyncClient base, + SdkClientConfiguration clientConfiguration, + AttributeMap clientContextParams) { List> decorators = new ArrayList<>(); - decorators.add(ConditionalDecorator.create(isCrossRegionEnabledAsync(clientConfiguration), + decorators.add(ConditionalDecorator.create(isCrossRegionEnabledAsync(clientContextParams), S3CrossRegionAsyncClient::new)); return ConditionalDecorator.decorate(base, decorators); } - private Predicate isCrossRegionEnabledAsync(SdkClientConfiguration clientConfiguration) { - return client -> ((S3Configuration) clientConfiguration.option(SdkClientOption.SERVICE_CONFIGURATION)) - .crossRegionAccessEnabled(); + private Predicate isCrossRegionEnabledAsync(AttributeMap clientContextParams) { + Boolean crossRegionEnabled = clientContextParams.get(S3ClientContextParams.CROSS_REGION_ACCESS_ENABLED); + return client -> crossRegionEnabled != null && crossRegionEnabled.booleanValue(); } } diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3SyncClientComposer.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3SyncClientDecorator.java similarity index 65% rename from services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3SyncClientComposer.java rename to services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3SyncClientDecorator.java index 47f98e5df84..0aa80cd5e25 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3SyncClientComposer.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3SyncClientDecorator.java @@ -19,30 +19,31 @@ import java.util.List; import java.util.function.Predicate; import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.awscore.internal.client.ClientComposer; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; -import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.endpoints.S3ClientContextParams; import software.amazon.awssdk.services.s3.internal.crossregion.S3CrossRegionSyncClient; +import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.ConditionalDecorator; @SdkInternalApi -public class S3SyncClientComposer implements ClientComposer { +public class S3SyncClientDecorator { - public S3SyncClientComposer() { + public S3SyncClientDecorator() { } - @Override - public S3Client compose(S3Client base, SdkClientConfiguration clientConfiguration) { + public S3Client decorate(S3Client base, + SdkClientConfiguration clientConfiguration, + AttributeMap clientContextParams) { List> decorators = new ArrayList<>(); - decorators.add(ConditionalDecorator.create(isCrossRegionEnabledSync(clientConfiguration), + decorators.add(ConditionalDecorator.create(isCrossRegionEnabledSync(clientContextParams), S3CrossRegionSyncClient::new)); + return ConditionalDecorator.decorate(base, decorators); } - private Predicate isCrossRegionEnabledSync(SdkClientConfiguration clientConfiguration) { - return client -> ((S3Configuration) clientConfiguration.option(SdkClientOption.SERVICE_CONFIGURATION)) - .crossRegionAccessEnabled(); + private Predicate isCrossRegionEnabledSync(AttributeMap clientContextParams) { + Boolean crossRegionEnabled = clientContextParams.get(S3ClientContextParams.CROSS_REGION_ACCESS_ENABLED); + return client -> crossRegionEnabled != null && crossRegionEnabled.booleanValue(); } } diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionAsyncClient.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionAsyncClient.java index 42b12954d57..af73bb804e1 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionAsyncClient.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionAsyncClient.java @@ -103,7 +103,7 @@ private void requestWithCrossRegion(T request, Optional bucketRegionFromException = getBucketRegionFromException((S3Exception) throwable.getCause()); if (bucketRegionFromException.isPresent()) { - sendRequestWithRightRegion(request, operation, bucketName, returnFuture, bucketRegionFromException); + sendRequestWithRightRegion(request, operation, bucketName, returnFuture, bucketRegionFromException.get()); } else { fetchRegionAndSendRequest(request, operation, bucketName, returnFuture); } @@ -121,7 +121,7 @@ private void fetchRegionAndSendRequest(T request, bucketToRegionCache.remove(bucketName); Optional bucketRegion = getBucketRegionFromException((S3Exception) throwable.getCause()); if (bucketRegion.isPresent()) { - sendRequestWithRightRegion(request, operation, bucketName, returnFuture, bucketRegion); + sendRequestWithRightRegion(request, operation, bucketName, returnFuture, bucketRegion.get()); } else { returnFuture.completeExceptionally(throwable); } @@ -136,8 +136,7 @@ private void sendRequestWithRightRegion(T request Function> operation, String bucketName, CompletableFuture returnFuture, - Optional bucketRegionFromException) { - String region = bucketRegionFromException.get(); + String region) { bucketToRegionCache.put(bucketName, Region.of(region)); CompletableFuture newFuture = operation.apply( requestWithDecoratedEndpointProvider(request, diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java index 5a5c0d9a314..936ab7b94fa 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java @@ -96,7 +96,6 @@ private static S3AsyncClient initializeS3AsyncClient(DefaultS3CrtClientBuilder b // Disable checksum, it is handled in CRT .serviceConfiguration(S3Configuration.builder() .checksumValidationEnabled(false) - .crossRegionAccessEnabled(builder.crossRegionAccessEnabled) .build()) .region(builder.region) .endpointOverride(builder.endpointOverride) @@ -104,6 +103,7 @@ private static S3AsyncClient initializeS3AsyncClient(DefaultS3CrtClientBuilder b .overrideConfiguration(overrideConfigurationBuilder.build()) .accelerate(builder.accelerate) .forcePathStyle(builder.forcePathStyle) + .crossRegionAccessEnabled(builder.crossRegionAccessEnabled) .httpClientBuilder(initializeS3CrtAsyncHttpClient(builder)) .build(); } diff --git a/services/s3/src/main/resources/codegen-resources/customization.config b/services/s3/src/main/resources/codegen-resources/customization.config index a4dc5824182..1a1efb76c5f 100644 --- a/services/s3/src/main/resources/codegen-resources/customization.config +++ b/services/s3/src/main/resources/codegen-resources/customization.config @@ -152,7 +152,8 @@ "hasUseArnRegionProperty": true, "hasMultiRegionEnabledProperty": true, "hasPathStyleAccessEnabledProperty":true, - "hasAccelerateModeEnabledProperty":true + "hasAccelerateModeEnabledProperty":true, + "hasCrossRegionAccessEnabledProperty":true }, "skipEndpointTests": { "Invalid access point ARN: Not S3": "Test assumes UseArnRegion is true but SDK defaults to false", @@ -232,8 +233,8 @@ ], "delegateAsyncClientClass": true, "delegateSyncClientClass": true, - "syncClientComposer": "software.amazon.awssdk.services.s3.internal.client.S3SyncClientComposer", - "asyncClientComposer": "software.amazon.awssdk.services.s3.internal.client.S3AsyncClientComposer", + "syncClientDecorator": "software.amazon.awssdk.services.s3.internal.client.S3SyncClientDecorator", + "asyncClientDecorator": "software.amazon.awssdk.services.s3.internal.client.S3AsyncClientDecorator", "useGlobalEndpoint": true, "interceptors": [ "software.amazon.awssdk.services.s3.internal.handlers.PutObjectInterceptor", @@ -250,5 +251,11 @@ "software.amazon.awssdk.services.s3.internal.handlers.GetObjectInterceptor", "software.amazon.awssdk.services.s3.internal.handlers.CopySourceInterceptor" ], - "requiredTraitValidationEnabled": true + "requiredTraitValidationEnabled": true, + "customClientContextParams":{ + "CrossRegionAccessEnabled":{ + "documentation":"Enables cross-region bucket access for this client", + "type":"boolean" + } + } } diff --git a/services/s3/src/test/java/software/amazon/awssdk/services/s3/S3ConfigurationTest.java b/services/s3/src/test/java/software/amazon/awssdk/services/s3/S3ConfigurationTest.java index b7dd63e0abc..c2ecc2d0107 100644 --- a/services/s3/src/test/java/software/amazon/awssdk/services/s3/S3ConfigurationTest.java +++ b/services/s3/src/test/java/software/amazon/awssdk/services/s3/S3ConfigurationTest.java @@ -46,7 +46,6 @@ public void createConfiguration_minimal() { assertThat(config.multiRegionEnabled()).isEqualTo(true); assertThat(config.pathStyleAccessEnabled()).isEqualTo(false); assertThat(config.useArnRegionEnabled()).isEqualTo(false); - assertThat(config.crossRegionAccessEnabled()).isEqualTo(false); } @Test @@ -116,13 +115,5 @@ public void useArnRegionEnabled_enabledInCProfile_shouldResolveToConfigCorrectly assertThat(config.useArnRegionEnabled()).isEqualTo(false); } - @Test - public void crossRegionEnabled__enabledInConfigOnly_shouldResolveCorrectly() { - S3Configuration config = S3Configuration.builder().crossRegionAccessEnabled(true).build(); - assertThat(config.crossRegionAccessEnabled()).isEqualTo(true); - - S3Configuration configDisabled = S3Configuration.builder().crossRegionAccessEnabled(false).build(); - assertThat(configDisabled.crossRegionAccessEnabled()).isEqualTo(false); - } } diff --git a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/ClientCompositionFactoryTest.java b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/ClientCompositionFactoryTest.java deleted file mode 100644 index 66c803421a4..00000000000 --- a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/ClientCompositionFactoryTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.services.s3.internal; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.function.Consumer; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import software.amazon.awssdk.core.client.config.SdkClientConfiguration; -import software.amazon.awssdk.core.client.config.SdkClientOption; -import software.amazon.awssdk.services.s3.S3AsyncClient; -import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.awssdk.services.s3.S3Configuration; -import software.amazon.awssdk.services.s3.internal.client.S3AsyncClientComposer; -import software.amazon.awssdk.services.s3.internal.client.S3SyncClientComposer; -import software.amazon.awssdk.services.s3.internal.crossregion.S3CrossRegionAsyncClient; -import software.amazon.awssdk.services.s3.internal.crossregion.S3CrossRegionSyncClient; - -public class ClientCompositionFactoryTest { - - @ParameterizedTest - @MethodSource("syncTestCases") - void syncClientTest(Consumer s3ConfigSettings, Class clazz, boolean isClass) { - S3SyncClientComposer composer = new S3SyncClientComposer(); - S3Client composedClient = composer.compose(S3Client.create(), - clientConfigWithServiceConfig(s3ConfigSettings)); - if (isClass) { - assertThat(composedClient).isInstanceOf(clazz); - } else { - assertThat(composedClient).isNotInstanceOf(clazz); - } - } - - @ParameterizedTest - @MethodSource("asyncTestCases") - void asyncClientTest(Consumer s3ConfigSettings, Class clazz, boolean isClass) { - S3AsyncClientComposer composer = new S3AsyncClientComposer(); - S3AsyncClient composedClient = composer.compose(S3AsyncClient.create(), - clientConfigWithServiceConfig(s3ConfigSettings)); - if (isClass) { - assertThat(composedClient).isInstanceOf(clazz); - } else { - assertThat(composedClient).isNotInstanceOf(clazz); - } - } - - private SdkClientConfiguration clientConfigWithServiceConfig(Consumer s3ConfigSettings) { - S3Configuration s3Configuration = S3Configuration.builder().applyMutation(s3ConfigSettings).build(); - return SdkClientConfiguration.builder().option(SdkClientOption.SERVICE_CONFIGURATION, s3Configuration).build(); - } - - private static Stream syncTestCases() { - return Stream.of( - Arguments.of((Consumer) c -> {}, S3CrossRegionSyncClient.class, false), - Arguments.of((Consumer) c -> c.crossRegionAccessEnabled(false), S3CrossRegionSyncClient.class, false), - Arguments.of((Consumer) c -> c.crossRegionAccessEnabled(true), S3CrossRegionSyncClient.class, true) - ); - } - - private static Stream asyncTestCases() { - return Stream.of( - Arguments.of((Consumer) c -> {}, S3CrossRegionAsyncClient.class, false), - Arguments.of((Consumer) c -> c.crossRegionAccessEnabled(false), S3CrossRegionAsyncClient.class, false), - Arguments.of((Consumer) c -> c.crossRegionAccessEnabled(true), S3CrossRegionAsyncClient.class, true) - ); - } -} diff --git a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/ClientDecorationFactoryTest.java b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/ClientDecorationFactoryTest.java new file mode 100644 index 00000000000..2fcc65e29cf --- /dev/null +++ b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/ClientDecorationFactoryTest.java @@ -0,0 +1,91 @@ +/* + * 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.services.s3.internal; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.function.Consumer; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.awssdk.core.client.config.SdkClientConfiguration; +import software.amazon.awssdk.core.client.config.SdkClientOption; +import software.amazon.awssdk.services.s3.S3AsyncClient; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.endpoints.S3ClientContextParams; +import software.amazon.awssdk.services.s3.internal.client.S3AsyncClientDecorator; +import software.amazon.awssdk.services.s3.internal.client.S3SyncClientDecorator; +import software.amazon.awssdk.services.s3.internal.crossregion.S3CrossRegionAsyncClient; +import software.amazon.awssdk.services.s3.internal.crossregion.S3CrossRegionSyncClient; +import software.amazon.awssdk.utils.AttributeMap; + +public class ClientDecorationFactoryTest { + + AttributeMap.Builder clientContextParams = AttributeMap.builder(); + + @ParameterizedTest + @MethodSource("syncTestCases") + + void syncClientTest(AttributeMap clientContextParams, Class clazz, boolean isClass) { + S3SyncClientDecorator decorator = new S3SyncClientDecorator(); + S3Client decorateClient = decorator.decorate(S3Client.create(), null, clientContextParams); + if (isClass) { + assertThat(decorateClient).isInstanceOf(clazz); + } else { + assertThat(decorateClient).isNotInstanceOf(clazz); + } + } + + @ParameterizedTest + @MethodSource("asyncTestCases") + void asyncClientTest(AttributeMap clientContextParams, Class clazz, boolean isClass) { + S3AsyncClientDecorator decorator = new S3AsyncClientDecorator(); + S3AsyncClient decoratedClient = decorator.decorate(S3AsyncClient.create(), + null ,clientContextParams); + if (isClass) { + assertThat(decoratedClient).isInstanceOf(clazz); + } else { + assertThat(decoratedClient).isNotInstanceOf(clazz); + } + } + + + private static Stream syncTestCases() { + return Stream.of( + Arguments.of(AttributeMap.builder().build(), S3CrossRegionSyncClient.class, false), + Arguments.of(AttributeMap.builder().put(S3ClientContextParams.CROSS_REGION_ACCESS_ENABLED, false).build(), + S3CrossRegionSyncClient.class, false), + Arguments.of(AttributeMap.builder().put(S3ClientContextParams.CROSS_REGION_ACCESS_ENABLED, true).build(), + S3CrossRegionSyncClient.class, true) + ); + } + + private static Stream asyncTestCases() { + return Stream.of( + Arguments.of(AttributeMap.builder().build(), + S3CrossRegionAsyncClient.class, + false), + Arguments.of(AttributeMap.builder().put(S3ClientContextParams.CROSS_REGION_ACCESS_ENABLED, false).build(), + S3CrossRegionAsyncClient.class, + false), + Arguments.of(AttributeMap.builder().put(S3ClientContextParams.CROSS_REGION_ACCESS_ENABLED, true).build() + , S3CrossRegionAsyncClient.class, + true) + ); + } +} diff --git a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionAsyncClientTest.java b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionAsyncClientTest.java index 59a0bea1bbe..38241184003 100644 --- a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionAsyncClientTest.java +++ b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionAsyncClientTest.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static software.amazon.awssdk.services.s3.internal.crossregion.S3DecoratorRedirectTestBase.CHANGED_CROSS_REGION; import static software.amazon.awssdk.services.s3.internal.crossregion.S3DecoratorRedirectTestBase.CROSS_REGION; import static software.amazon.awssdk.services.s3.internal.crossregion.S3DecoratorRedirectTestBase.OVERRIDE_CONFIGURED_REGION; @@ -54,6 +55,8 @@ import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.S3AsyncClientBuilder; import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.S3ServiceClientConfiguration; import software.amazon.awssdk.services.s3.endpoints.internal.DefaultS3EndpointProvider; import software.amazon.awssdk.services.s3.internal.crossregion.endpointprovider.BucketEndpointProvider; import software.amazon.awssdk.services.s3.model.GetObjectRequest; @@ -139,7 +142,7 @@ void paginatedOp_crossRegionClient_DoesIntercept(Consumer s void crossRegionClient_createdWithWrapping_SuccessfullyIntercepts(Consumer stubConsumer, Class endpointProviderType) { stubConsumer.accept(mockAsyncHttpClient); - S3AsyncClient crossRegionClient = clientBuilder().serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + S3AsyncClient crossRegionClient = clientBuilder().crossRegionAccessEnabled(true).build(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join(); assertThat(captureInterceptor.endpointProvider).isInstanceOf(endpointProviderType); } @@ -151,7 +154,7 @@ void crossRegionClient_CallsHeadObject_when_regionNameNotPresentInFallBackCall() customHttpResponse(301, CROSS_REGION.id()), successHttpResponse(), successHttpResponse()); S3AsyncClient crossRegionClient = - clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).crossRegionAccessEnabled(true).build(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join(); assertThat(captureInterceptor.endpointProvider).isInstanceOf(BucketEndpointProvider.class); @@ -191,7 +194,7 @@ void crossRegionClient_CallsHeadObjectErrors_shouldTerminateTheAPI() { successHttpResponse(), successHttpResponse()); S3AsyncClient crossRegionClient = clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION) - .serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + .crossRegionAccessEnabled(true).build(); assertThatExceptionOfType(CompletionException.class) .isThrownBy(() -> crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join()) @@ -216,7 +219,7 @@ void crossRegionClient_CallsHeadObjectWithNoRegion_shouldTerminateHeadBucketAPI( successHttpResponse(), successHttpResponse()); S3AsyncClient crossRegionClient = clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION) - .serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + .crossRegionAccessEnabled(true).build(); assertThatExceptionOfType(CompletionException.class) .isThrownBy(() -> crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join()) @@ -243,7 +246,7 @@ void crossRegionClient_cancelsTheThread_when_futureIsCancelled(){ customHttpResponse(301, CROSS_REGION.id()), successHttpResponse(), successHttpResponse()); S3AsyncClient crossRegionClient = - clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).crossRegionAccessEnabled(true).build(); CompletableFuture> completableFuture = crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY) , AsyncResponseTransformer.toBytes()); @@ -259,7 +262,7 @@ void crossRegionClient_when_redirectsAfterCaching() { customHttpResponse(301, CHANGED_CROSS_REGION.id()), successHttpResponse()); S3AsyncClient crossRegionClient = - clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).crossRegionAccessEnabled(true).build(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join(); @@ -290,7 +293,7 @@ void crossRegionClient_when_redirectsAfterCaching_withFallBackRedirectWithNoRegi customHttpResponse(301, CHANGED_CROSS_REGION.id()), successHttpResponse()); S3AsyncClient crossRegionClient = - clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).crossRegionAccessEnabled(true).build(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join(); @@ -317,15 +320,34 @@ void crossRegionClient_when_redirectsAfterCaching_withFallBackRedirectWithNoRegi @Test void standardOp_crossRegionClient_containUserAgent() { mockAsyncHttpClient.stubResponses(successHttpResponse()); - S3AsyncClient crossRegionClient = clientBuilder().serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + + S3AsyncClient crossRegionClient = clientBuilder().crossRegionAccessEnabled(true).build(); + crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join(); + assertThat(mockAsyncHttpClient.getLastRequest().firstMatchingHeader("User-Agent").get()).contains("hll/cross-region"); + } + + @Test + void standardOp_crossRegionClient_FromContextParamBuilder_containUserAgent(){ + mockAsyncHttpClient.stubResponses(successHttpResponse()); + S3AsyncClient crossRegionClient = clientBuilder().crossRegionAccessEnabled(true).build(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join(); assertThat(mockAsyncHttpClient.getLastRequest().firstMatchingHeader("User-Agent").get()).contains("hll/cross-region"); } + @ParameterizedTest + @MethodSource("stubResponses") + void crossRegionClient_fromParamBuilder_createdWithWrapping_SuccessfullyIntercepts(Consumer stubConsumer, + Class endpointProviderType) { + stubConsumer.accept(mockAsyncHttpClient); + S3AsyncClient crossRegionClient = clientBuilder().crossRegionAccessEnabled(true).build(); + crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join(); + assertThat(captureInterceptor.endpointProvider).isInstanceOf(endpointProviderType); + } + @Test void standardOp_simpleClient_doesNotContainCrossRegionUserAgent() { mockAsyncHttpClient.stubResponses(successHttpResponse()); - S3AsyncClient crossRegionClient = clientBuilder().serviceConfiguration(c -> c.crossRegionAccessEnabled(false)).build(); + S3AsyncClient crossRegionClient = clientBuilder().crossRegionAccessEnabled(false).build(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join(); assertThat(mockAsyncHttpClient.getLastRequest().firstMatchingHeader("User-Agent").get()).doesNotContain("hll/cross-region"); } diff --git a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionSyncClientTest.java b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionSyncClientTest.java index c163d89c3b2..f576d09d317 100644 --- a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionSyncClientTest.java +++ b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionSyncClientTest.java @@ -17,7 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.mockito.Mockito.verify; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static software.amazon.awssdk.services.s3.internal.crossregion.S3CrossRegionAsyncClientTest.customHttpResponse; import static software.amazon.awssdk.services.s3.internal.crossregion.S3CrossRegionAsyncClientTest.successHttpResponse; import static software.amazon.awssdk.services.s3.internal.crossregion.S3DecoratorRedirectTestBase.CHANGED_CROSS_REGION; @@ -29,7 +29,6 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -140,7 +139,9 @@ void paginatedOp_crossRegionClient_DoesNotIntercept(Consumer void crossRegionClient_createdWithWrapping_SuccessfullyIntercepts(Consumer stubConsumer, Class endpointProviderType) { stubConsumer.accept(mockSyncHttpClient); - S3Client crossRegionClient = clientBuilder().serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + + + S3Client crossRegionClient = clientBuilder().crossRegionAccessEnabled(true).build(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY)); assertThat(captureInterceptor.endpointProvider).isInstanceOf(endpointProviderType); } @@ -151,7 +152,7 @@ void standardOp_crossRegionClient_takesCustomEndpointProviderInRequest(Consumer< Class endpointProviderType, Region region) { stubConsumer.accept(mockSyncHttpClient); - S3Client crossRegionClient = clientBuilder().serviceConfiguration(c -> c.crossRegionAccessEnabled(true)) + S3Client crossRegionClient = clientBuilder().crossRegionAccessEnabled(true) .endpointProvider(new TestEndpointProvider()) .region(OVERRIDE_CONFIGURED_REGION) .build(); @@ -174,7 +175,7 @@ void standardOp_crossRegionClient_takesCustomEndpointProviderInClient(Consumer endpointProviderType, Region region) { stubConsumer.accept(mockSyncHttpClient); - S3Client crossRegionClient = clientBuilder().serviceConfiguration(c -> c.crossRegionAccessEnabled(true)) + S3Client crossRegionClient = clientBuilder().crossRegionAccessEnabled(true) .endpointProvider(new TestEndpointProvider()) .region(OVERRIDE_CONFIGURED_REGION) .build(); @@ -196,7 +197,7 @@ void crossRegionClient_CallsHeadObject_when_regionNameNotPresentInFallBackCall() customHttpResponse(301, CROSS_REGION.id() ), successHttpResponse(), successHttpResponse()); S3Client crossRegionClient = - clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).crossRegionAccessEnabled(true).build(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY)); assertThat(captureInterceptor.endpointProvider).isInstanceOf(BucketEndpointProvider.class); @@ -237,7 +238,7 @@ void crossRegionClient_when_redirectsAfterCaching() { customHttpResponse(301, CHANGED_CROSS_REGION.id()), successHttpResponse()); S3Client crossRegionClient = - clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).crossRegionAccessEnabled(true).build(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY)); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY)); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY)); @@ -267,7 +268,7 @@ void crossRegionClient_when_redirectsAfterCaching_withFallBackRedirectWithNoRegi customHttpResponse(301, CHANGED_CROSS_REGION.id()), successHttpResponse()); S3Client crossRegionClient = - clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).crossRegionAccessEnabled(true).build(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY)); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY)); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY)); @@ -295,7 +296,7 @@ void crossRegionClient_CallsHeadObjectErrors_shouldTerminateTheAPI() { customHttpResponse(400, null ), successHttpResponse(), successHttpResponse()); S3Client crossRegionClient = - clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).crossRegionAccessEnabled(true).build(); assertThatExceptionOfType(S3Exception.class) .isThrownBy(() -> crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY))) @@ -319,7 +320,7 @@ void crossRegionClient_CallsHeadObjectWithNoRegion_shouldTerminateHeadBucketAPI( customHttpResponse(301, null ), successHttpResponse(), successHttpResponse()); S3Client crossRegionClient = - clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + clientBuilder().endpointOverride(null).region(OVERRIDE_CONFIGURED_REGION).crossRegionAccessEnabled(true).build(); assertThatExceptionOfType(S3Exception.class) .isThrownBy(() -> crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY))) @@ -341,7 +342,7 @@ void crossRegionClient_CallsHeadObjectWithNoRegion_shouldTerminateHeadBucketAPI( @Test void standardOp_crossRegionClient_containUserAgent() { mockSyncHttpClient.stubResponses(successHttpResponse()); - S3Client crossRegionClient = clientBuilder().serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build(); + S3Client crossRegionClient = clientBuilder().crossRegionAccessEnabled(true).build(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY)); assertThat(mockSyncHttpClient.getLastRequest().firstMatchingHeader("User-Agent").get()).contains("hll/cross-region"); } @@ -349,7 +350,7 @@ void standardOp_crossRegionClient_containUserAgent() { @Test void standardOp_simpleClient_doesNotContainCrossRegionUserAgent() { mockSyncHttpClient.stubResponses(successHttpResponse()); - S3Client crossRegionClient = clientBuilder().serviceConfiguration(c -> c.crossRegionAccessEnabled(false)).build(); + S3Client crossRegionClient = clientBuilder().crossRegionAccessEnabled(false).build(); crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY)); assertThat(mockSyncHttpClient.getLastRequest().firstMatchingHeader("User-Agent").get()) .doesNotContain("hll/cross-region");