diff --git a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven-tm/after/src/main/java/foo/bar/TransferManagerS3.java b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven-tm/after/src/main/java/foo/bar/TransferManagerS3.java index 974e9627a1b2..c4971ff63b1e 100644 --- a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven-tm/after/src/main/java/foo/bar/TransferManagerS3.java +++ b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven-tm/after/src/main/java/foo/bar/TransferManagerS3.java @@ -28,16 +28,22 @@ import software.amazon.awssdk.transfer.s3.model.Copy; import software.amazon.awssdk.transfer.s3.model.CopyRequest; import software.amazon.awssdk.transfer.s3.model.DirectoryDownload; +import software.amazon.awssdk.transfer.s3.model.DirectoryUpload; import software.amazon.awssdk.transfer.s3.model.DownloadDirectoryRequest; import software.amazon.awssdk.transfer.s3.model.DownloadFileRequest; import software.amazon.awssdk.transfer.s3.model.FileDownload; import software.amazon.awssdk.transfer.s3.model.FileUpload; import software.amazon.awssdk.transfer.s3.model.ResumableFileDownload; import software.amazon.awssdk.transfer.s3.model.ResumableFileUpload; +import software.amazon.awssdk.transfer.s3.model.ResumableTransfer; +import software.amazon.awssdk.transfer.s3.model.UploadDirectoryRequest; import software.amazon.awssdk.transfer.s3.model.UploadFileRequest; import software.amazon.awssdk.transfer.s3.model.UploadRequest; +import software.amazon.awssdk.transfer.s3.progress.TransferProgress; import java.io.File; +import java.io.IOException; +import java.io.OutputStream; import java.time.Duration; public class TransferManagerS3 { @@ -93,8 +99,19 @@ void downloadDirectory(S3TransferManager tm, File destination) { tm.close(); } + void uploadDirectory(S3TransferManager tm) { + DirectoryUpload fileUpload1 = tm.uploadDirectory(UploadDirectoryRequest.builder().bucket("bucket").s3Prefix("prefix").source(file.toPath()).maxDepth(true ? Integer.MAX_VALUE : 1).build()); + } + void resume(S3TransferManager tm, ResumableFileDownload persistableDownload, ResumableFileUpload persistableUpload) { FileDownload download = tm.resumeDownloadFile(persistableDownload); FileUpload upload = tm.resumeUploadFile(persistableUpload); } -} + + void POJO_methods(ResumableTransfer transfer, OutputStream outputStream, TransferProgress progress) throws IOException { + String s = transfer.serializeToString(); + transfer.serializeToOutputStream(outputStream); + + long bytesTransferred = progress.snapshot().transferredBytes(); + } +} \ No newline at end of file diff --git a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven-tm/before/src/main/java/foo/bar/TransferManagerS3.java b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven-tm/before/src/main/java/foo/bar/TransferManagerS3.java index 89c8f427955b..8657cfd51f5c 100644 --- a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven-tm/before/src/main/java/foo/bar/TransferManagerS3.java +++ b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven-tm/before/src/main/java/foo/bar/TransferManagerS3.java @@ -23,12 +23,17 @@ import com.amazonaws.services.s3.transfer.Copy; import com.amazonaws.services.s3.transfer.Download; import com.amazonaws.services.s3.transfer.MultipleFileDownload; +import com.amazonaws.services.s3.transfer.MultipleFileUpload; import com.amazonaws.services.s3.transfer.PersistableDownload; +import com.amazonaws.services.s3.transfer.PersistableTransfer; import com.amazonaws.services.s3.transfer.PersistableUpload; import com.amazonaws.services.s3.transfer.TransferManager; import com.amazonaws.services.s3.transfer.TransferManagerBuilder; +import com.amazonaws.services.s3.transfer.TransferProgress; import com.amazonaws.services.s3.transfer.Upload; import java.io.File; +import java.io.IOException; +import java.io.OutputStream; public class TransferManagerS3 { @@ -78,8 +83,19 @@ void downloadDirectory(TransferManager tm, File destination) { tm.shutdownNow(); } + void uploadDirectory(TransferManager tm) { + MultipleFileUpload fileUpload1 = tm.uploadDirectory("bucket", "prefix", file, true); + } + void resume(TransferManager tm, PersistableDownload persistableDownload, PersistableUpload persistableUpload) { Download download = tm.resumeDownload(persistableDownload); Upload upload = tm.resumeUpload(persistableUpload); } -} + + void POJO_methods(PersistableTransfer transfer, OutputStream outputStream, TransferProgress progress) throws IOException { + String s = transfer.serialize(); + transfer.serialize(outputStream); + + long bytesTransferred = progress.getBytesTransferred(); + } +} \ No newline at end of file diff --git a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/S3AddImportsAndComments.java b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/S3AddImportsAndComments.java index ff8a55c2597d..6f14bbeadb77 100644 --- a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/S3AddImportsAndComments.java +++ b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/S3AddImportsAndComments.java @@ -58,7 +58,6 @@ public class S3AddImportsAndComments extends Recipe { private static final MethodMatcher GET_EXPIRY_TIME = v1EnMethodMatcher("S3EventNotification.RestoreEventDataEntity " + "getLifecycleRestorationExpiryTime(..)"); - private static final Pattern CANNED_ACL = Pattern.compile(V1_S3_MODEL_PKG + "CannedAccessControlList"); private static final Pattern GET_OBJECT_REQUEST = Pattern.compile(V1_S3_MODEL_PKG + "GetObjectRequest"); private static final Pattern CREATE_BUCKET_REQUEST = Pattern.compile(V1_S3_MODEL_PKG + "CreateBucketRequest"); diff --git a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/S3TmAddComments.java b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/S3TmAddComments.java new file mode 100644 index 000000000000..5a1b0b527c8e --- /dev/null +++ b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/S3TmAddComments.java @@ -0,0 +1,122 @@ +/* + * 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.v2migration; + +import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.V1_TM_PKG; +import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.V2_S3_CLIENT; +import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.V2_S3_MODEL_PKG; +import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.V2_TM_CLIENT; +import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.createComments; +import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.v2TmMethodMatcher; + +import java.util.regex.Pattern; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import software.amazon.awssdk.annotations.SdkInternalApi; + +@SdkInternalApi +public class S3TmAddComments extends Recipe { + + private static final Pattern S3_TM = Pattern.compile(V2_TM_CLIENT); + private static final Pattern S3_CLIENT = Pattern.compile(V2_S3_CLIENT); + + private static final MethodMatcher COPY = v2TmMethodMatcher("copy(..)"); + private static final MethodMatcher DOWNLOAD = v2TmMethodMatcher(String.format("download(%sGetObjectRequest, java.io.File, " + + "%sinternal.S3ProgressListener, ..)", + V2_S3_MODEL_PKG, V1_TM_PKG)); + private static final MethodMatcher DOWNLOAD_DIRECTORY = v2TmMethodMatcher("downloadDirectory(..)"); + private static final MethodMatcher UPLOAD = v2TmMethodMatcher("upload(..)"); + private static final MethodMatcher UPLOAD_DIRECTORY = v2TmMethodMatcher("uploadDirectory(..)"); + + @Override + public String getDisplayName() { + return "Add imports and comments to unsupported S3 transfer manager transforms."; + } + + @Override + public String getDescription() { + return "Add imports and comments to unsupported S3 transfer manager transforms."; + } + + @Override + public TreeVisitor getVisitor() { + return new S3TmAddComments.Visitor(); + } + + private static class Visitor extends JavaIsoVisitor { + + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + if (COPY.matches(method) && (method.getArguments().size() == 2 || method.getArguments().size() == 3)) { + String comment = "Migration for TransferStateChangeListener is not supported by the migration tool. Please " + + "manually migrate the code using TransferListener in v2"; + return method.withComments(createComments(comment)); + } + if (DOWNLOAD.matches(method)) { + String comment = "Migration for S3ProgressListener is not supported by the migration tool. Please manually " + + "migrate the code using TransferListener in v2"; + return method.withComments(createComments(comment)); + } + if (DOWNLOAD_DIRECTORY.matches(method) && method.getArguments().size() > 3) { + String comment = "Migration for KeyFilter is not supported by the migration tool. Please " + + "manually migrate the code using DownloadFilter in v2"; + return method.withComments(createComments(comment)); + } + if (UPLOAD.matches(method) && method.getArguments().size() == 4) { + String comment = "Migration for InputStream and ObjectMetadata as argument for upload is not supported by the " + + "migration tool."; + return method.withComments(createComments(comment)); + } + if (UPLOAD.matches(method) && method.getArguments().size() == 2) { + String comment = "Migration for S3ProgressListener is not supported by the migration tool. Please manually " + + "migrate the code using TransferListener in v2"; + return method.withComments(createComments(comment)); + } + if (UPLOAD_DIRECTORY.matches(method) && method.getArguments().size() > 4) { + String comment = "Migration for ObjectMetadataProvider as argument for uploadDirectory is not supported by the " + + "migration tool."; + return method.withComments(createComments(comment)); + } + + return method; + } + + @Override + public J.NewClass visitNewClass(J.NewClass newClass, ExecutionContext ctx) { + JavaType type = newClass.getType(); + if (!(type instanceof JavaType.FullyQualified)) { + return newClass; + } + + if (type.isAssignableFrom(S3_TM) && + !newClass.getArguments().isEmpty() && + newClass.getArguments().get(0).getType() != null) { + if (newClass.getArguments().get(0).getType().isAssignableFrom(S3_CLIENT)) { + String comment = "S3TransferManager requires S3AsyncClient in v2. Please create a new S3AsyncClient " + + "instance for v2 S3TransferManager."; + return newClass.withComments(createComments(comment)); + } + } + + return newClass; + } + } +} diff --git a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/TransferManagerMethodsToV2.java b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/TransferManagerMethodsToV2.java index 161a3387171f..749d94d1ed8a 100644 --- a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/TransferManagerMethodsToV2.java +++ b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/TransferManagerMethodsToV2.java @@ -53,6 +53,8 @@ public class TransferManagerMethodsToV2 extends Recipe { private static final MethodMatcher DOWNLOAD_DIR = v2TmMethodMatcher("downloadDirectory(String, String, java.io.File)"); + private static final MethodMatcher UPLOAD_DIR = v2TmMethodMatcher("uploadDirectory(String, String, java.io.File, boolean)"); + private static final Pattern S3_TM_CREDENTIAL = Pattern.compile(V2_TM_CLIENT); private static final Pattern V2_AWSCREDENTAIL = Pattern.compile("software.amazon.awssdk.auth.credentials.AwsCredentials"); private static final Pattern V2_CREDENTIAL_PROVIDER = Pattern.compile("software.amazon.awssdk.auth.credentials" @@ -110,6 +112,10 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext execu method = transformDownloadDirectory(method); return super.visitMethodInvocation(method, executionContext); } + if (UPLOAD_DIR.matches(method, false)) { + method = transformUploadDirectory(method); + return super.visitMethodInvocation(method, executionContext); + } return super.visitMethodInvocation(method, executionContext); } @@ -165,11 +171,24 @@ private J.MethodInvocation transformDownloadDirectory(J.MethodInvocation method) method.getArguments().get(0), method.getArguments().get(1), method.getArguments().get(2)); - addTmImport("DirectoryDownload"); addTmImport("DownloadDirectoryRequest"); return method; } + private J.MethodInvocation transformUploadDirectory(J.MethodInvocation method) { + String v2Method = "#{any()}.uploadDirectory(UploadDirectoryRequest.builder()" + + ".bucket(#{any()}).s3Prefix(#{any()}).source(#{any()}.toPath())" + + ".maxDepth(#{any()} ? Integer.MAX_VALUE : 1).build())"; + + method = JavaTemplate.builder(v2Method).build() + .apply(getCursor(), method.getCoordinates().replace(), method.getSelect(), + method.getArguments().get(0), method.getArguments().get(1), + method.getArguments().get(2), method.getArguments().get(3)); + + addTmImport("UploadDirectoryRequest"); + return method; + } + private J.MethodInvocation transformUploadWithBucketKeyFile(J.MethodInvocation method) { String v2Method = "#{any()}.uploadFile(UploadFileRequest.builder()" + ".putObjectRequest(PutObjectRequest.builder().bucket(#{any()}).key(#{any()}).build())" diff --git a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/S3TransformUtils.java b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/S3TransformUtils.java index 2a4895952edc..87981c4f8bca 100644 --- a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/S3TransformUtils.java +++ b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/S3TransformUtils.java @@ -38,6 +38,7 @@ public final class S3TransformUtils { public static final String V1_S3_MODEL_PKG = "com.amazonaws.services.s3.model."; public static final String V1_S3_PKG = "com.amazonaws.services.s3."; public static final String V1_EN_PKG = "com.amazonaws.services.s3.event."; + public static final String V1_TM_PKG = "com.amazonaws.services.s3.transfer."; public static final String V2_S3_CLIENT = "software.amazon.awssdk.services.s3.S3Client"; public static final String V2_S3_MODEL_PKG = "software.amazon.awssdk.services.s3.model."; diff --git a/v2-migration/src/main/resources/META-INF/rewrite/aws-sdk-java-v1-to-v2-with-tm.yml b/v2-migration/src/main/resources/META-INF/rewrite/aws-sdk-java-v1-to-v2-with-tm.yml index 5068d764e29a..9769969f3748 100644 --- a/v2-migration/src/main/resources/META-INF/rewrite/aws-sdk-java-v1-to-v2-with-tm.yml +++ b/v2-migration/src/main/resources/META-INF/rewrite/aws-sdk-java-v1-to-v2-with-tm.yml @@ -53,5 +53,6 @@ recipeList: - software.amazon.awssdk.v2migration.S3NonStreamingRequestToV2Complex - software.amazon.awssdk.v2migration.S3PutObjectRequestToV2 - software.amazon.awssdk.v2migration.SettersToBuilderV2 + - software.amazon.awssdk.v2migration.S3TmAddComments - software.amazon.awssdk.v2migration.ChangeTransferManagerSimpleMethods - software.amazon.awssdk.v2migration.TransferManagerMethodsToV2 \ No newline at end of file diff --git a/v2-migration/src/main/resources/META-INF/rewrite/change-transfer-manager-simple-methods.yml b/v2-migration/src/main/resources/META-INF/rewrite/change-transfer-manager-simple-methods.yml index e06beb03f632..8fbc8dee0856 100644 --- a/v2-migration/src/main/resources/META-INF/rewrite/change-transfer-manager-simple-methods.yml +++ b/v2-migration/src/main/resources/META-INF/rewrite/change-transfer-manager-simple-methods.yml @@ -25,4 +25,22 @@ recipeList: newMethodName: resumeUploadFile - org.openrewrite.java.ChangeMethodName: methodPattern: software.amazon.awssdk.transfer.s3.S3TransferManager shutdownNow() - newMethodName: close \ No newline at end of file + newMethodName: close + - org.openrewrite.java.ChangeMethodName: + methodPattern: software.amazon.awssdk.transfer.s3.model.Transfer getProgress() + newMethodName: progress + - org.openrewrite.java.ChangeMethodName: + methodPattern: software.amazon.awssdk.transfer.s3.model.ResumableTransfer serialize() + newMethodName: serializeToString + - org.openrewrite.java.ChangeMethodName: + methodPattern: software.amazon.awssdk.transfer.s3.model.ResumableTransfer serialize(java.io.OutputStream) + newMethodName: serializeToOutputStream + - org.openrewrite.java.ChangeMethodName: + methodPattern: software.amazon.awssdk.transfer.s3.progress.TransferProgress getBytesTransferred() + newMethodName: snapshot().transferredBytes + - org.openrewrite.java.ChangeMethodName: + methodPattern: software.amazon.awssdk.transfer.s3.progress.TransferProgress getTotalBytesToTransfer() + newMethodName: snapshot().totalBytes + - org.openrewrite.java.ChangeMethodName: + methodPattern: software.amazon.awssdk.transfer.s3.progress.TransferProgress getPercentTransferred() + newMethodName: snapshot().ratioTransferred \ No newline at end of file