com.tracermedia.maven.plugins.CreateVersionMojo.java Source code

Java tutorial

Introduction

Here is the source code for com.tracermedia.maven.plugins.CreateVersionMojo.java

Source

/**
 * Copyright (c) 2011, Pykl Studios <admin@pykl.org>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.tracermedia.maven.plugins;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import com.amazonaws.services.elasticbeanstalk.model.ApplicationVersionDescription;
import com.amazonaws.services.elasticbeanstalk.model.CreateApplicationVersionRequest;
import com.amazonaws.services.elasticbeanstalk.model.CreateApplicationVersionResult;
import com.amazonaws.services.elasticbeanstalk.model.DescribeApplicationVersionsResult;
import com.amazonaws.services.elasticbeanstalk.model.S3Location;
import com.amazonaws.services.elasticbeanstalk.model.UpdateEnvironmentRequest;
import com.amazonaws.services.elasticbeanstalk.model.UpdateEnvironmentResult;
import com.amazonaws.services.s3.internal.Mimetypes;
import com.amazonaws.services.s3.internal.ProgressReportingInputStream;
import com.amazonaws.services.s3.internal.RepeatableFileInputStream;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.ProgressEvent;
import com.amazonaws.services.s3.model.ProgressListener;
import com.amazonaws.services.s3.model.PutObjectRequest;
import org.apache.maven.model.Build;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;

/**
 * Deploys a new version of the application to the Amazon Elastic Beanstalk service.
 *
 * @goal create-version
 */
public class CreateVersionMojo extends AbstractBeanstalkMojo {

    protected static final DateFormat DF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

    /**
     * The name of the application version to deploy. If the specified application has no associated
     * application versions, If not specified, AWS Elastic Beanstalk attempts to launch the most
     * recently created application version.
     *
     * @parameter expression="${versionLabel}"
     */
    protected String versionLabel;

    /**
     * The Amazon S3 bucket that identify the location of the source bundle for this version.
     * If not specified, AWS Elastic Beanstalk uses a sample application.
     *
     * @parameter expression="${s3Bucket}"
     */
    protected String s3Bucket;

    /**
     * The name of the environment to update.
     *
     * @parameter expression="${environmentName}"
     * @required
     */
    protected String environmentName;

    /**
     * The Amazon S3 key that identify the location of the source bundle for this version.
     * If not specified, a key is generated using the application name and a timestamp.
     *
     * @parameter expression="${s3Key}"
     */
    protected String s3Key;

    /**
     * The maven project.
     *
     * @parameter expression="${project}"
     * @required
     * @readonly
     */
    protected MavenProject project;

    public CreateVersionMojo() {
        DF.setTimeZone(TimeZone.getTimeZone("GMT"));
    }

    public void execute() throws MojoExecutionException, MojoFailureException {
        final Date now = new Date();

        if (!project.getPackaging().equalsIgnoreCase("war")
                && !project.getPackaging().equalsIgnoreCase("uberwar")) {
            throw new MojoExecutionException(
                    "Only WAR projects can be deployed to Amazon Beanstalk. Not " + project.getPackaging());
        }

        System.out.println("Existing versions:");
        for (ApplicationVersionDescription version : getVersions()) {
            if (version.getApplicationName().equals(applicationName)) {
                System.out.println(String.format("App Name: %25s, version: %20s, S3: %s/%s",
                        version.getApplicationName(), version.getVersionLabel(),
                        version.getSourceBundle().getS3Bucket(), version.getSourceBundle().getS3Key()));
            }
        }

        final Build build = project.getBuild();

        // It would be much better to use project.getPackaging() instead of hardcoding "war". But
        // the Mojo we use to combine multiple WAR files has a package of 'uberwar'.
        String artifactPath = String.format("%s/%s.%s", build.getDirectory(), build.getFinalName(), "war");

        // Need to push the artifact to S3. Place in the s3Bucket using the s3Key. If the key is
        // not specified, it is generated by using the applicationName and appending a timestamp.
        if (s3Key == null) {
            s3Key = applicationName + '-' + DF.format(now);
        }
        try {
            copyFileToS3(s3Bucket, s3Key, new File(artifactPath));
        } catch (IOException e) {
            throw new MojoFailureException("Failed to copy file to Amazon S3", e);
        }

        // If a version label has not been set, we will use the applicationKey and timestamp.
        if (versionLabel == null) {
            versionLabel = applicationName + '-' + DF.format(now);
        }

        // Create the new version of the application.
        createApplicationVersion(applicationName, versionLabel, s3Bucket, s3Key);

        updateEnvironmentVersion(environmentName, versionLabel);
    }

    protected List<ApplicationVersionDescription> getVersions() {
        final DescribeApplicationVersionsResult versionsResult = getBeanstalkClient().describeApplicationVersions();

        return versionsResult.getApplicationVersions();
    }

    protected void createApplicationVersion(String applicationName, String versionLabel, String s3Bucket,
            String s3Key) {
        final CreateApplicationVersionRequest versionRequest = new CreateApplicationVersionRequest(applicationName,
                versionLabel);

        if (s3Bucket != null && s3Key != null) {
            final S3Location location = new S3Location(s3Bucket, s3Key);
            versionRequest.setSourceBundle(location);
        } else {
            System.err.println("Warning: Deploying sample application because S3 location "
                    + "is not specified. (Hint: s3Bucket, s3Key).");
        }

        final CreateApplicationVersionResult versionResult = getBeanstalkClient()
                .createApplicationVersion(versionRequest);

        System.out.println(String.format("Deployed application [%s/%s] to Amazon Beanstalk.",
                versionResult.getApplicationVersion().getApplicationName(),
                versionResult.getApplicationVersion().getVersionLabel()));
    }

    protected void updateEnvironmentVersion(String environmentName, String versionLabel) {
        final UpdateEnvironmentRequest envRequest = new UpdateEnvironmentRequest()
                .withEnvironmentName(environmentName).withVersionLabel(versionLabel);

        final UpdateEnvironmentResult envResult = getBeanstalkClient().updateEnvironment(envRequest);

        System.out.println(String.format(
                "Updated environment [%s] with new version of %s (%s). Health: %s, status: %s, Endpoint: %s",
                envResult.getEnvironmentName(), envResult.getApplicationName(), versionLabel, envResult.getHealth(),
                envResult.getStatus(), envResult.getEndpointURL()));
    }

    protected void copyFileToS3(final String s3Bucket, final String s3Key, final File file) throws IOException {

        final ObjectMetadata meta = new ObjectMetadata();

        InputStream in = new FileInputStream(file);
        try {
            meta.setContentLength(file.length());
            meta.setContentType(Mimetypes.getInstance().getMimetype(file));
        } finally {
            in.close();
        }

        in = new ProgressReportingInputStream(new RepeatableFileInputStream(file), new ProgressListener() {
            int lastPercent = -1;
            int bytes = 0;

            public void progressChanged(ProgressEvent progressEvent) {
                bytes += progressEvent.getBytesTransfered();
                double percent = 100.0 * bytes / meta.getContentLength();
                if ((int) percent != lastPercent) {
                    System.out.print(
                            String.format("\rCopying file [%s] to S3, bucket: %s, key: %s, progress: %.0f%%   ",
                                    file.getName(), s3Bucket, s3Key, percent));
                    lastPercent = (int) percent;
                }
            }
        });

        try {
            final PutObjectRequest request = new PutObjectRequest(s3Bucket, s3Key, in, meta);
            getS3Client().putObject(request);
            System.out.println(String.format("\rCopying file [%s] to S3, bucket: %s, key: %s, progress: %.0f%%   ",
                    file.getName(), s3Bucket, s3Key, 100.0));
        } finally {
            in.close();
        }
    }

}