diff --git a/.changes/next-release/feature-AWSSDKforJavav2-7624538.json b/.changes/next-release/feature-AWSSDKforJavav2-7624538.json new file mode 100644 index 000000000000..b7496b6fbb0c --- /dev/null +++ b/.changes/next-release/feature-AWSSDKforJavav2-7624538.json @@ -0,0 +1,6 @@ +{ + "type": "feature", + "category": "AWS SDK for Java v2", + "contributor": "anirudh9391", + "description": "Allowing SDK plugins to read and modify S3's crossRegionEnabled and SQS's checksumValidationEnabled" +} 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 8ee1fe842d42..0cc74f08bdb9 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 @@ -138,7 +138,7 @@ private MethodSpec buildClientMethod() { builder.addStatement("$1T client = new $2T(clientConfiguration)", clientInterfaceName, clientClassName); if (model.asyncClientDecoratorClassName().isPresent()) { - builder.addStatement("return new $T().decorate(client, clientConfiguration, clientContextParams.copy().build())", + builder.addStatement("return new $T().decorate(client, clientConfiguration)", PoetUtils.classNameFromFqcn(model.asyncClientDecoratorClassName().get())); } else { builder.addStatement("return client"); 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 645f8aae5afa..5fc251b73d46 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 @@ -130,7 +130,7 @@ private MethodSpec buildClientMethod() { builder.addStatement("$1T client = new $2T(clientConfiguration)", clientInterfaceName, clientClassName); if (model.syncClientDecoratorClassName().isPresent()) { - builder.addStatement("return new $T().decorate(client, clientConfiguration, clientContextParams.copy().build())", + builder.addStatement("return new $T().decorate(client, clientConfiguration)", PoetUtils.classNameFromFqcn(model.syncClientDecoratorClassName().get())); } else { builder.addStatement("return client"); 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 edc838d52069..95cb77412076 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 @@ -34,6 +34,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -47,6 +49,7 @@ import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.model.intermediate.OperationModel; import software.amazon.awssdk.codegen.model.intermediate.Protocol; +import software.amazon.awssdk.codegen.model.service.ClientContextParam; import software.amazon.awssdk.codegen.poet.PoetExtension; import software.amazon.awssdk.codegen.poet.PoetUtils; import software.amazon.awssdk.codegen.poet.auth.scheme.AuthSchemeSpecUtils; @@ -56,6 +59,7 @@ import software.amazon.awssdk.codegen.poet.client.specs.QueryProtocolSpec; import software.amazon.awssdk.codegen.poet.client.specs.XmlProtocolSpec; import software.amazon.awssdk.codegen.poet.model.ServiceClientConfigurationUtils; +import software.amazon.awssdk.codegen.poet.rules.EndpointRulesSpecUtils; import software.amazon.awssdk.core.RequestOverrideConfiguration; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.SdkRequest; @@ -69,8 +73,11 @@ import software.amazon.awssdk.metrics.MetricCollector; import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.metrics.NoOpMetricCollector; +import software.amazon.awssdk.utils.AttributeMap; +import software.amazon.awssdk.utils.CollectionUtils; import software.amazon.awssdk.utils.CompletableFutureUtils; import software.amazon.awssdk.utils.Logger; +import software.amazon.awssdk.utils.Validate; public class SyncClientClass extends SyncClientInterface { @@ -418,7 +425,7 @@ protected MethodSpec.Builder waiterOperationBody(MethodSpec.Builder builder) { poetExtensions.getSyncWaiterInterface()); } - protected static MethodSpec updateSdkClientConfigurationMethod( + protected MethodSpec updateSdkClientConfigurationMethod( TypeName serviceClientConfigurationBuilderClassName, boolean shouldAddClientReference) { MethodSpec.Builder builder = MethodSpec.methodBuilder("updateSdkClientConfiguration") @@ -442,9 +449,34 @@ protected static MethodSpec updateSdkClientConfigurationMethod( .addStatement("$1T serviceConfigBuilder = new $1T(configuration)", serviceClientConfigurationBuilderClassName) .beginControlFlow("for ($T plugin : plugins)", SdkPlugin.class) .addStatement("plugin.configureClient(serviceConfigBuilder)") - .endControlFlow() - .addStatement("return configuration.build()"); + .endControlFlow(); + EndpointRulesSpecUtils endpointRulesSpecUtils = new EndpointRulesSpecUtils(this.model); + + if (model.getCustomizationConfig() == null || + CollectionUtils.isNullOrEmpty(model.getCustomizationConfig().getCustomClientContextParams())) { + builder.addStatement("return configuration.build()"); + return builder.build(); + } + + Map customClientConfigParams = model.getCustomizationConfig().getCustomClientContextParams(); + + builder.addCode("$1T newContextParams = configuration.option($2T.CLIENT_CONTEXT_PARAMS);\n" + + "$1T originalContextParams = clientConfiguration.option($2T.CLIENT_CONTEXT_PARAMS);", + AttributeMap.class, SdkClientOption.class); + + builder.addCode("newContextParams = (newContextParams != null) ? newContextParams : $1T.empty();\n" + + "originalContextParams = originalContextParams != null ? originalContextParams : $1T.empty();", + AttributeMap.class); + + customClientConfigParams.forEach((n, m) -> { + String keyName = model.getNamingStrategy().getEnumValueName(n); + builder.addStatement("$1T.validState($2T.equals(originalContextParams.get($3T.$4N), newContextParams.get($3T.$4N))," + + " $5S)", + Validate.class, Objects.class, endpointRulesSpecUtils.clientContextParamsName(), keyName, + keyName + " cannot be modified by request level plugins"); + }); + builder.addStatement("return configuration.build()"); return builder.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 ff7bb09df89d..b4c325123332 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 @@ -22,6 +22,7 @@ import com.squareup.javapoet.TypeName; import com.squareup.javapoet.WildcardTypeName; import java.net.URI; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -31,6 +32,7 @@ import software.amazon.awssdk.awscore.client.config.AwsClientOption; 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.client.config.ClientOption; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; @@ -41,12 +43,14 @@ import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.Validate; public class ServiceClientConfigurationUtils { private final AuthSchemeSpecUtils authSchemeSpecUtils; private final ClassName configurationClassName; private final ClassName configurationBuilderClassName; + private final EndpointRulesSpecUtils endpointRulesSpecUtils; private final List fields; public ServiceClientConfigurationUtils(IntermediateModel model) { @@ -56,7 +60,8 @@ public ServiceClientConfigurationUtils(IntermediateModel model) { configurationBuilderClassName = ClassName.get(model.getMetadata().getFullClientInternalPackageName(), serviceId + "ServiceClientConfigurationBuilder"); authSchemeSpecUtils = new AuthSchemeSpecUtils(model); - fields = fields(); + endpointRulesSpecUtils = new EndpointRulesSpecUtils(model); + fields = fields(model); } /** @@ -81,8 +86,10 @@ public List serviceClientConfigurationFields() { return Collections.unmodifiableList(fields); } - private List fields() { - return Arrays.asList( + private List fields(IntermediateModel model) { + List fields = new ArrayList<>(); + + fields.addAll(Arrays.asList( overrideConfigurationField(), endpointOverrideField(), endpointProviderField(), @@ -90,7 +97,33 @@ private List fields() { credentialsProviderField(), authSchemesField(), authSchemeProviderField() - ); + )); + fields.addAll(addCustomClientParams(model)); + return fields; + } + + private List addCustomClientParams(IntermediateModel model) { + List customClientParamFields = new ArrayList<>(); + + if (model.getCustomizationConfig() != null && model.getCustomizationConfig().getCustomClientContextParams() != null) { + model.getCustomizationConfig().getCustomClientContextParams().forEach((n, m) -> { + + String paramName = endpointRulesSpecUtils.paramMethodName(n); + String keyName = model.getNamingStrategy().getEnumValueName(n); + TypeName type = endpointRulesSpecUtils.toJavaType(m.getType()); + + customClientParamFields.add(fieldBuilder(paramName, type) + .doc(m.getDocumentation()) + .isInherited(false) + .localSetter(basicLocalSetterCode(paramName)) + .localGetter(basicLocalGetterCode(paramName)) + .configSetter(customClientConfigParamSetter(paramName, keyName)) + .configGetter(customClientConfigParamGetter(keyName)) + .build()); + }); + } + + return customClientParamFields; } private Field overrideConfigurationField() { @@ -268,6 +301,27 @@ private CodeBlock authSchemeProviderConfigGetter() { .build(); } + private CodeBlock customClientConfigParamSetter(String parameterName, String keyName) { + return CodeBlock.builder() + .addStatement("config.option($1T.CLIENT_CONTEXT_PARAMS, " + + "config.computeOptionIfAbsent($1T.CLIENT_CONTEXT_PARAMS, $2T::empty)" + + ".toBuilder().put($3T.$4N, $5N).build())", + SdkClientOption.class, + AttributeMap.class, + endpointRulesSpecUtils.clientContextParamsName(), + keyName, parameterName) + .addStatement("return this") + .build(); + } + + private CodeBlock customClientConfigParamGetter(String keyName) { + return CodeBlock.builder() + .addStatement("return config.computeOptionIfAbsent($T.CLIENT_CONTEXT_PARAMS, $T::empty)\n" + + ".get($T.$N)", SdkClientOption.class, AttributeMap.class, + endpointRulesSpecUtils.clientContextParamsName(), keyName) + .build(); + } + private CodeBlock basicLocalSetterCode(String fieldName) { return CodeBlock.builder() .addStatement("this.$1N = $1N", fieldName) 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 3cd1628a8e7c..9e4b2f83fa3b 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 @@ -34,6 +34,6 @@ protected final JsonAsyncClient buildClient() { SdkClientConfiguration clientConfiguration = super.asyncClientConfiguration(); this.validateClientOptions(clientConfiguration); JsonAsyncClient client = new DefaultJsonAsyncClient(clientConfiguration); - return new AsyncClientDecorator().decorate(client, clientConfiguration, clientContextParams.copy().build()); + return new AsyncClientDecorator().decorate(client, clientConfiguration); } } 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 722bcdb27539..e65a80caf0a5 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 @@ -34,6 +34,6 @@ protected final JsonClient buildClient() { SdkClientConfiguration clientConfiguration = super.syncClientConfiguration(); this.validateClientOptions(clientConfiguration); JsonClient client = new DefaultJsonClient(clientConfiguration); - return new SyncClientDecorator().decorate(client, clientConfiguration, clientContextParams.copy().build()); + return new SyncClientDecorator().decorate(client, clientConfiguration); } } diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3AsyncClientDecorator.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3AsyncClientDecorator.java index b751cb29c1b0..fe2997a7d73c 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3AsyncClientDecorator.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3AsyncClientDecorator.java @@ -20,6 +20,7 @@ import java.util.function.Predicate; import software.amazon.awssdk.annotations.SdkInternalApi; 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.endpoints.S3ClientContextParams; import software.amazon.awssdk.services.s3.internal.crossregion.S3CrossRegionAsyncClient; @@ -39,8 +40,8 @@ public S3AsyncClientDecorator() { } public S3AsyncClient decorate(S3AsyncClient base, - SdkClientConfiguration clientConfiguration, - AttributeMap clientContextParams) { + SdkClientConfiguration clientConfiguration) { + AttributeMap clientContextParams = clientConfiguration.option(SdkClientOption.CLIENT_CONTEXT_PARAMS); List> decorators = new ArrayList<>(); decorators.add(ConditionalDecorator.create( isCrossRegionEnabledAsync(clientContextParams), diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3SyncClientDecorator.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3SyncClientDecorator.java index 0aa80cd5e253..6b3d7409989e 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3SyncClientDecorator.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/client/S3SyncClientDecorator.java @@ -20,6 +20,7 @@ import java.util.function.Predicate; import software.amazon.awssdk.annotations.SdkInternalApi; 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.endpoints.S3ClientContextParams; import software.amazon.awssdk.services.s3.internal.crossregion.S3CrossRegionSyncClient; @@ -33,8 +34,8 @@ public S3SyncClientDecorator() { } public S3Client decorate(S3Client base, - SdkClientConfiguration clientConfiguration, - AttributeMap clientContextParams) { + SdkClientConfiguration clientConfiguration) { + AttributeMap clientContextParams = clientConfiguration.option(SdkClientOption.CLIENT_CONTEXT_PARAMS); List> decorators = new ArrayList<>(); decorators.add(ConditionalDecorator.create(isCrossRegionEnabledSync(clientContextParams), S3CrossRegionSyncClient::new)); 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 index 6a6b86896457..9a98cc1ba679 100644 --- 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 @@ -22,6 +22,9 @@ 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.ClientOption; +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.endpoints.S3ClientContextParams; @@ -33,14 +36,13 @@ public class ClientDecorationFactoryTest { - AttributeMap.Builder clientContextParams = AttributeMap.builder(); + static SdkClientConfiguration.Builder clientConfiguration = SdkClientConfiguration.builder(); @ParameterizedTest @MethodSource("syncTestCases") - - void syncClientTest(AttributeMap clientContextParams, Class clazz, boolean isClass) { + void syncClientTest(SdkClientConfiguration clientConfiguration, Class clazz, boolean isClass) { S3SyncClientDecorator decorator = new S3SyncClientDecorator(); - S3Client decorateClient = decorator.decorate(S3Client.create(), null, clientContextParams); + S3Client decorateClient = decorator.decorate(S3Client.create(), clientConfiguration); if (isClass) { assertThat(decorateClient).isInstanceOf(clazz); } else { @@ -50,10 +52,10 @@ void syncClientTest(AttributeMap clientContextParams, Class clazz, boole @ParameterizedTest @MethodSource("asyncTestCases") - void asyncClientTest(AttributeMap clientContextParams, Class clazz, boolean isClass) { + void asyncClientTest(SdkClientConfiguration clientConfiguration, Class clazz, boolean isClass) { S3AsyncClientDecorator decorator = new S3AsyncClientDecorator(); S3AsyncClient decoratedClient = decorator.decorate(S3AsyncClient.create(), - null ,clientContextParams); + clientConfiguration); if (isClass) { assertThat(decoratedClient).isInstanceOf(clazz); } else { @@ -64,24 +66,28 @@ void asyncClientTest(AttributeMap clientContextParams, Class clazz, bool 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(), + Arguments.of(clientConfiguration.option(SdkClientOption.CLIENT_CONTEXT_PARAMS, AttributeMap.builder().build()).build(), S3CrossRegionSyncClient.class, false), + Arguments.of(clientConfiguration.option(SdkClientOption.CLIENT_CONTEXT_PARAMS, + AttributeMap.builder().put(S3ClientContextParams.CROSS_REGION_ACCESS_ENABLED, false).build()).build(), S3CrossRegionSyncClient.class, false), - Arguments.of(AttributeMap.builder().put(S3ClientContextParams.CROSS_REGION_ACCESS_ENABLED, true).build(), + Arguments.of(clientConfiguration.option(SdkClientOption.CLIENT_CONTEXT_PARAMS, + AttributeMap.builder().put(S3ClientContextParams.CROSS_REGION_ACCESS_ENABLED, true).build()).build(), S3CrossRegionSyncClient.class, true) ); } private static Stream asyncTestCases() { return Stream.of( - Arguments.of(AttributeMap.builder().build(), + Arguments.of(clientConfiguration.option(SdkClientOption.CLIENT_CONTEXT_PARAMS, AttributeMap.builder().build()).build(), S3CrossRegionAsyncClient.class, false), - Arguments.of(AttributeMap.builder().put(S3ClientContextParams.CROSS_REGION_ACCESS_ENABLED, false).build(), + Arguments.of(clientConfiguration.option(SdkClientOption.CLIENT_CONTEXT_PARAMS, + AttributeMap.builder().put(S3ClientContextParams.CROSS_REGION_ACCESS_ENABLED, false).build()).build(), S3CrossRegionAsyncClient.class, false), - Arguments.of(AttributeMap.builder().put(S3ClientContextParams.CROSS_REGION_ACCESS_ENABLED, true).build() - , S3CrossRegionAsyncClient.class, + Arguments.of(clientConfiguration.option(SdkClientOption.CLIENT_CONTEXT_PARAMS, + AttributeMap.builder().put(S3ClientContextParams.CROSS_REGION_ACCESS_ENABLED, true).build()).build(), + S3CrossRegionAsyncClient.class, true) ); } diff --git a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/customclientcontextparams/S3CustomClientConfigParamsTest.java b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/customclientcontextparams/S3CustomClientConfigParamsTest.java new file mode 100644 index 000000000000..706546319763 --- /dev/null +++ b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/customclientcontextparams/S3CustomClientConfigParamsTest.java @@ -0,0 +1,80 @@ +/* + * 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.customclientcontextparams; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; + +public class S3CustomClientConfigParamsTest { + + @Test + public void test_setCrossRegionAccessOnClient() { + S3Client s3Client = S3Client.builder() + .crossRegionAccessEnabled(true).build(); + + assertTrue(s3Client.serviceClientConfiguration().crossRegionAccessEnabled()); + } + + @Test + public void test_defaultCrossRegionAccess_equalsNull() { + S3Client s3Client = S3Client.builder(). + build(); + + assertNull(s3Client.serviceClientConfiguration().crossRegionAccessEnabled()); + } + + @Test + public void test_setCrossRegionAccess_through_clientLevelPlugin() { + S3Client s3Client = S3Client.builder() + .addPlugin(new TestCustomClientParamPlugin()).build(); + + assertTrue(s3Client.serviceClientConfiguration().crossRegionAccessEnabled()); + } + + @Test + public void test_setCrossRegionAccess_through_clientLevelPlugin_and_OnClient_verify_pluginOverride() { + S3Client s3Client = S3Client.builder() + .crossRegionAccessEnabled(false) + .addPlugin(new TestCustomClientParamPlugin()).build(); + + assertTrue(s3Client.serviceClientConfiguration().crossRegionAccessEnabled()); + } + + @Test + public void setCrossRegionAccess_through_requestLevelPlugin_throwsIllegalStateException() { + + GetObjectRequest getObjectRequest = GetObjectRequest.builder() + .overrideConfiguration(o -> o.addPlugin(new TestCustomClientParamPlugin())) + .build(); + + + S3Client s3Client = S3Client.builder() + .crossRegionAccessEnabled(false) + .build(); + + try { + s3Client.getObject(getObjectRequest); + } catch (Exception e) { + assertTrue(e instanceof IllegalStateException); + assertEquals(e.getMessage(), "CROSS_REGION_ACCESS_ENABLED cannot be modified by request level plugins"); + } + } +} diff --git a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/customclientcontextparams/TestCustomClientParamPlugin.java b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/customclientcontextparams/TestCustomClientParamPlugin.java new file mode 100644 index 000000000000..135bf9c8490a --- /dev/null +++ b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/customclientcontextparams/TestCustomClientParamPlugin.java @@ -0,0 +1,28 @@ +/* + * 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.customclientcontextparams; + +import software.amazon.awssdk.core.SdkPlugin; +import software.amazon.awssdk.core.SdkServiceClientConfiguration; +import software.amazon.awssdk.services.s3.S3ServiceClientConfiguration; + +public class TestCustomClientParamPlugin implements SdkPlugin { + @Override + public void configureClient(SdkServiceClientConfiguration.Builder config) { + S3ServiceClientConfiguration.Builder s3Config = (S3ServiceClientConfiguration.Builder) config; + s3Config.crossRegionAccessEnabled(true); + } +}