All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.amazon.awssdk.transfer.s3.internal.model.CrtFileUpload Maven / Gradle / Ivy

Go to download

The S3 Transfer Manager allows customers to easily and optimally transfer objects and directories to and from S3.

There is a newer version: 2.28.4
Show newest version
/*
 * 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.transfer.s3.internal.model;

import java.io.File;
import java.time.Instant;
import java.util.concurrent.CompletableFuture;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.crt.CrtRuntimeException;
import software.amazon.awssdk.crt.s3.ResumeToken;
import software.amazon.awssdk.services.s3.internal.crt.S3MetaRequestPauseObservable;
import software.amazon.awssdk.transfer.s3.model.CompletedFileUpload;
import software.amazon.awssdk.transfer.s3.model.FileUpload;
import software.amazon.awssdk.transfer.s3.model.ResumableFileUpload;
import software.amazon.awssdk.transfer.s3.model.UploadFileRequest;
import software.amazon.awssdk.transfer.s3.progress.TransferProgress;
import software.amazon.awssdk.utils.Lazy;
import software.amazon.awssdk.utils.Logger;
import software.amazon.awssdk.utils.ToString;
import software.amazon.awssdk.utils.Validate;

@SdkInternalApi
public final class CrtFileUpload implements FileUpload {
    private static final Logger log = Logger.loggerFor(CrtFileUpload.class);

    private final Lazy resumableFileUpload;
    private final CompletableFuture completionFuture;
    private final TransferProgress progress;
    private final UploadFileRequest request;
    private final S3MetaRequestPauseObservable observable;

    public CrtFileUpload(CompletableFuture completionFuture,
                         TransferProgress progress,
                         S3MetaRequestPauseObservable observable,
                         UploadFileRequest request) {
        this.completionFuture = Validate.paramNotNull(completionFuture, "completionFuture");
        this.progress = Validate.paramNotNull(progress, "progress");
        this.observable = Validate.paramNotNull(observable, "observable");
        this.request = Validate.paramNotNull(request, "request");
        this.resumableFileUpload = new Lazy<>(this::doPause);
    }

    @Override
    public ResumableFileUpload pause() {
        return resumableFileUpload.getValue();
    }

    private ResumableFileUpload doPause() {
        File sourceFile = request.source().toFile();

        boolean futureCompletedExceptionally = completionFuture.isCompletedExceptionally();
        if (completionFuture.isDone() && !futureCompletedExceptionally) {
            log.debug(() -> "The upload future was completed. There will be no ResumeToken returned.");

            Instant fileLastModified = Instant.ofEpochMilli(sourceFile.lastModified());
            return ResumableFileUpload.builder()
                                      .fileLastModified(fileLastModified)
                                      .fileLength(sourceFile.length())
                                      .uploadFileRequest(request)
                                      .build();
        }


        Instant fileLastModified = Instant.ofEpochMilli(sourceFile
                                                            .lastModified());
        ResumeToken token = null;
        try {
            token = observable.pause();
        } catch (CrtRuntimeException exception) {
            // CRT throws exception if it is a single part
            if (!exception.errorName.equals("AWS_ERROR_UNSUPPORTED_OPERATION")) {
                throw exception;
            }
        }

        completionFuture.cancel(true);
        if (token == null) {
            // TODO - remove once CRT handles future completed exceptionally to return ResumeToken
            if (futureCompletedExceptionally) {
                log.debug(() -> "The upload future was completed exceptionally and the ResumeToken returned by the "
                                + "S3 MetaRequest was null.");
            } else {
                log.debug(() -> "The upload hasn't started yet or it's a single object upload. There will be no ResumeToken "
                                + "returned");
            }

            return ResumableFileUpload.builder()
                                      .fileLastModified(fileLastModified)
                                      .fileLength(sourceFile.length())
                                      .uploadFileRequest(request)
                                      .build();
        }

        return ResumableFileUpload.builder()
                                  .multipartUploadId(token.getUploadId())
                                  .totalParts(token.getTotalNumParts())
                                  .transferredParts(token.getNumPartsCompleted())
                                  .partSizeInBytes(token.getPartSize())
                                  .fileLastModified(fileLastModified)
                                  .fileLength(sourceFile.length())
                                  .uploadFileRequest(request)
                                  .build();
    }

    @Override
    public CompletableFuture completionFuture() {
        return completionFuture;
    }

    @Override
    public TransferProgress progress() {
        return progress;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        CrtFileUpload that = (CrtFileUpload) o;

        if (!resumableFileUpload.equals(that.resumableFileUpload)) {
            return false;
        }
        if (!completionFuture.equals(that.completionFuture)) {
            return false;
        }
        if (!progress.equals(that.progress)) {
            return false;
        }
        if (!request.equals(that.request)) {
            return false;
        }
        return observable == that.observable;
    }

    @Override
    public int hashCode() {
        int result = resumableFileUpload.hashCode();
        result = 31 * result + completionFuture.hashCode();
        result = 31 * result + progress.hashCode();
        result = 31 * result + request.hashCode();
        result = 31 * result + observable.hashCode();
        return result;
    }

    @Override
    public String toString() {
        return ToString.builder("CrtFileUpload")
                       .add("completionFuture", completionFuture)
                       .add("progress", progress)
                       .add("request", request)
                       .build();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy