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 0cc74f08bdb9..e0b4c0502970 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 @@ -81,7 +81,6 @@ public TypeSpec poetSpec() { MultipartCustomization multipartCustomization = model.getCustomizationConfig().getMultipartCustomization(); if (multipartCustomization != null) { - builder.addMethod(multipartEnabledMethod(multipartCustomization)); builder.addMethod(multipartConfigMethods(multipartCustomization)); } @@ -159,18 +158,6 @@ private MethodSpec tokenProviderMethod() { .build(); } - private MethodSpec multipartEnabledMethod(MultipartCustomization multipartCustomization) { - return MethodSpec.methodBuilder("multipartEnabled") - .addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .returns(builderInterfaceName) - .addParameter(Boolean.class, "enabled") - .addStatement("clientContextParams.put($N, enabled)", - multipartCustomization.getContextParamEnabledKey()) - .addStatement("return this") - .build(); - } - private MethodSpec multipartConfigMethods(MultipartCustomization multipartCustomization) { ClassName mulitpartConfigClassName = PoetUtils.classNameFromFqcn(multipartCustomization.getMultipartConfigurationClass()); diff --git a/services-custom/s3-transfer-manager/src/main/java/software/amazon/awssdk/transfer/s3/internal/TransferManagerFactory.java b/services-custom/s3-transfer-manager/src/main/java/software/amazon/awssdk/transfer/s3/internal/TransferManagerFactory.java index a87d8d6fcd60..4cdc1d6b4b8c 100644 --- a/services-custom/s3-transfer-manager/src/main/java/software/amazon/awssdk/transfer/s3/internal/TransferManagerFactory.java +++ b/services-custom/s3-transfer-manager/src/main/java/software/amazon/awssdk/transfer/s3/internal/TransferManagerFactory.java @@ -52,11 +52,7 @@ public static S3TransferManager createTransferManager(DefaultBuilder tmBuilder) return new CrtS3TransferManager(transferConfiguration, s3AsyncClient, isDefaultS3AsyncClient); } - if (s3AsyncClient.getClass().getName().equals("software.amazon.awssdk.services.s3.DefaultS3AsyncClient")) { - log.warn(() -> "The provided DefaultS3AsyncClient is not an instance of S3CrtAsyncClient, and thus multipart" - + " upload/download feature is not enabled and resumable file upload is not supported. To benefit " - + "from maximum throughput, consider using S3AsyncClient.crtBuilder().build() instead."); - } else { + if (!Boolean.TRUE.equals(s3AsyncClient.serviceClientConfiguration().multipartEnabled())) { log.debug(() -> "The provided S3AsyncClient is not an instance of S3CrtAsyncClient, and thus multipart" + " upload/download feature may not be enabled and resumable file upload may not be supported."); } @@ -68,7 +64,9 @@ private static Supplier defaultS3AsyncClient() { if (crtInClasspath()) { return S3AsyncClient::crtCreate; } - return S3AsyncClient::create; + return () -> S3AsyncClient.builder() + .multipartEnabled(true) + .build(); } private static boolean crtInClasspath() { diff --git a/services-custom/s3-transfer-manager/src/test/java/software/amazon/awssdk/transfer/s3/internal/TransferManagerLoggingTest.java b/services-custom/s3-transfer-manager/src/test/java/software/amazon/awssdk/transfer/s3/internal/TransferManagerLoggingTest.java index 4f2be4d00063..cc53f67354c8 100644 --- a/services-custom/s3-transfer-manager/src/test/java/software/amazon/awssdk/transfer/s3/internal/TransferManagerLoggingTest.java +++ b/services-custom/s3-transfer-manager/src/test/java/software/amazon/awssdk/transfer/s3/internal/TransferManagerLoggingTest.java @@ -24,6 +24,8 @@ import org.apache.logging.log4j.core.LogEvent; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.Mockito; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; @@ -35,33 +37,66 @@ class TransferManagerLoggingTest { @Test void transferManager_withCrtClient_shouldNotLogWarnMessages() { - try (S3AsyncClient s3Crt = S3AsyncClient.crtBuilder() + try (S3AsyncClient s3AsyncClient = S3AsyncClient.crtBuilder() .region(Region.US_WEST_2) .credentialsProvider(() -> AwsBasicCredentials.create("foo", "bar")) .build(); - LogCaptor logCaptor = LogCaptor.create(Level.WARN); - S3TransferManager tm = S3TransferManager.builder().s3Client(s3Crt).build()) { + LogCaptor logCaptor = LogCaptor.create(Level.DEBUG); + S3TransferManager tm = S3TransferManager.builder().s3Client(s3AsyncClient).build()) { List events = logCaptor.loggedEvents(); assertThat(events).isEmpty(); } } @Test - void transferManager_withJavaClient_shouldLogWarnMessage() { + void transferManager_withCustomJavaClientWhenMultiPartEnabledIsNull_shouldLogDebugMessage() { + try (S3AsyncClient s3AsyncClient = S3AsyncClient.builder() + .region(Region.US_WEST_2) + .credentialsProvider(() -> AwsBasicCredentials.create("foo", "bar")) + .build(); + LogCaptor logCaptor = LogCaptor.create(Level.DEBUG); + S3TransferManager tm = S3TransferManager.builder().s3Client(s3AsyncClient).build()) { + List events = logCaptor.loggedEvents(); + assertLogged(events, Level.DEBUG, "The provided S3AsyncClient is not an instance of S3CrtAsyncClient, and thus multipart" + + " upload/download feature may not be enabled and resumable file upload may not be supported."); + } + } + + @Test + void transferManager_withCustomJavaClientWhenMultiPartEnabledIsFalse_shouldLogDebugMessage() { + try (S3AsyncClient s3AsyncClient = S3AsyncClient.builder() + .region(Region.US_WEST_2) + .credentialsProvider(() -> AwsBasicCredentials.create("foo", "bar")) + .multipartEnabled(false) + .build(); + LogCaptor logCaptor = LogCaptor.create(Level.DEBUG); + S3TransferManager tm = S3TransferManager.builder().s3Client(s3AsyncClient).build()) { + List events = logCaptor.loggedEvents(); + assertLogged(events, Level.DEBUG, "The provided S3AsyncClient is not an instance of S3CrtAsyncClient, and thus multipart" + + " upload/download feature may not be enabled and resumable file upload may not be supported."); + } + } + @Test + void transferManager_withDefaultJavaClient_shouldNotLogDebugMessage() { + try (LogCaptor logCaptor = LogCaptor.create(Level.DEBUG); + S3TransferManager tm = S3TransferManager.builder().build()) { + List events = logCaptor.loggedEvents(); + assertThat(events).isEmpty(); + } + } + @Test + void transferManager_withCustomJavaClientMultiPartEnabled_shouldNotLogDebugMessage() { try (S3AsyncClient s3Crt = S3AsyncClient.builder() .region(Region.US_WEST_2) .credentialsProvider(() -> AwsBasicCredentials.create("foo", "bar")) + .multipartEnabled(true) .build(); - LogCaptor logCaptor = LogCaptor.create(Level.WARN); + LogCaptor logCaptor = LogCaptor.create(Level.DEBUG); S3TransferManager tm = S3TransferManager.builder().s3Client(s3Crt).build()) { List events = logCaptor.loggedEvents(); - assertLogged(events, Level.WARN, "The provided DefaultS3AsyncClient is not an instance of S3CrtAsyncClient, and " - + "thus multipart upload/download feature is not enabled and resumable file upload" - + " is " - + "not supported. To benefit from maximum throughput, consider using " - + "S3AsyncClient.crtBuilder().build() instead."); + assertThat(events).isEmpty(); } } 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 fe2997a7d73c..7b042754bec5 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 @@ -33,8 +33,6 @@ public class S3AsyncClientDecorator { public static final AttributeMap.Key MULTIPART_CONFIGURATION_KEY = new AttributeMap.Key(MultipartConfiguration.class){}; - public static final AttributeMap.Key MULTIPART_ENABLED_KEY = - new AttributeMap.Key(Boolean.class){}; public S3AsyncClientDecorator() { } @@ -62,7 +60,7 @@ private Predicate isCrossRegionEnabledAsync(AttributeMap clientCo } private Predicate isMultipartEnable(AttributeMap clientContextParams) { - Boolean multipartEnabled = clientContextParams.get(MULTIPART_ENABLED_KEY); + Boolean multipartEnabled = clientContextParams.get(S3ClientContextParams.MULTIPART_ENABLED); return client -> multipartEnabled != null && multipartEnabled.booleanValue(); } } diff --git a/services/s3/src/main/resources/codegen-resources/customization.config b/services/s3/src/main/resources/codegen-resources/customization.config index 7bd3369c2b88..87f7b4d9c7b8 100644 --- a/services/s3/src/main/resources/codegen-resources/customization.config +++ b/services/s3/src/main/resources/codegen-resources/customization.config @@ -241,7 +241,6 @@ "multipartConfigurationClass": "software.amazon.awssdk.services.s3.multipart.MultipartConfiguration", "multipartConfigMethodDoc": "Configuration for multipart operation of this client.", "multipartEnableMethodDoc": "Enables automatic conversion of put and copy method to their equivalent multipart operation.", - "contextParamEnabledKey": "S3AsyncClientDecorator.MULTIPART_ENABLED_KEY", "contextParamConfigKey": "S3AsyncClientDecorator.MULTIPART_CONFIGURATION_KEY" }, "interceptors": [ @@ -271,6 +270,10 @@ "CrossRegionAccessEnabled":{ "documentation":"Enables cross-region bucket access for this client", "type":"boolean" + }, + "multipartEnabled":{ + "documentation":"Enables automatic conversion of put and copy method to their equivalent multipart operation.", + "type":"boolean" } }, "endpointAuthSchemeConfig": {