com.github.kaklakariada.aws.sam.task.S3UploadTask.java Source code

Java tutorial

Introduction

Here is the source code for com.github.kaklakariada.aws.sam.task.S3UploadTask.java

Source

/**
 * aws-sam-gradle - Gradle plugin for deploying AWS Serverless Application Models
 * Copyright (C) 2017 Christoph Pirkl <christoph at users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.github.kaklakariada.aws.sam.task;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.time.Instant;

import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.TaskAction;

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.TransferManagerBuilder;
import com.amazonaws.services.s3.transfer.Upload;
import com.github.kaklakariada.aws.sam.DeploymentException;
import com.github.kaklakariada.aws.sam.config.SamConfig;

public class S3UploadTask extends DefaultTask {

    @InputFile
    public File file;

    @Input
    public SamConfig config;

    @Internal
    private AmazonS3 s3Client;

    public S3UploadTask() {
        getOutputs().upToDateWhen(task -> objectExistsInBucket(calculateS3Key()));
    }

    private static byte[] createChecksum(File file) {
        try (InputStream fis = new FileInputStream(file)) {
            final byte[] buffer = new byte[1024];
            final MessageDigest complete = MessageDigest.getInstance("MD5");
            int numRead;

            do {
                numRead = fis.read(buffer);
                if (numRead > 0) {
                    complete.update(buffer, 0, numRead);
                }
            } while (numRead != -1);

            return complete.digest();
        } catch (final IOException | NoSuchAlgorithmException e) {
            throw new DeploymentException("Error calculating md5 sum for file " + file, e);
        }
    }

    private static String getMD5Checksum(File file) {
        final byte[] b = createChecksum(file);
        return convertBytesToString(b);
    }

    private static String convertBytesToString(final byte[] b) {
        final StringBuilder result = new StringBuilder();
        for (int i = 0; i < b.length; i++) {
            result.append(Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1));
        }
        return result.toString();
    }

    @TaskAction
    public void uploadFileToS3() {
        upload(calculateS3Key());
    }

    private AmazonS3 getS3Client() {
        if (s3Client == null) {
            s3Client = config.getAwsClientFactory().create(AmazonS3Client.builder());
        }
        return s3Client;
    }

    @Internal
    public String getS3Url() {
        return "s3://" + config.getDeploymentBucket() + "/" + calculateS3Key();
    }

    private String calculateS3Key() {
        final String version = getProject().getVersion().toString();
        final String md5Checksum = getMD5Checksum(file);
        return getProject().getName() + "/" + version + "/" + md5Checksum + "/" + file.getName();
    }

    private void upload(final String key) {
        if (!objectExistsInBucket(key)) {
            transferFileToS3(key);
        }
    }

    private boolean objectExistsInBucket(final String key) {
        return getS3Client().doesObjectExist(config.getDeploymentBucket(), key);
    }

    private void transferFileToS3(final String key) {
        final long fileSizeMb = file.length() / (1024 * 1024);
        getLogger().lifecycle("Uploading {} MB from file {} to {}...", fileSizeMb, file, getS3Url());
        final TransferManager transferManager = createTransferManager();
        final Instant start = Instant.now();
        final Upload upload = transferManager.upload(config.getDeploymentBucket(), key, file);
        try {
            upload.waitForCompletion();
            final Duration uploadDuration = Duration.between(start, Instant.now());
            getLogger().lifecycle("Uploaded {} to {} in {}", file, getS3Url(), uploadDuration);
        } catch (final InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new AssertionError("Upload interrupted", e);
        }
    }

    private TransferManager createTransferManager() {
        return TransferManagerBuilder.standard().withS3Client(getS3Client()).build();
    }
}