org.fuin.esmp.EventStoreDownloadMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.fuin.esmp.EventStoreDownloadMojo.java

Source

/**
 * Copyright (C) 2015 Michael Schnell. All rights reserved. 
 * <http://www.fuin.org/>
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option) any
 * later version.
 *
 * This library 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 Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library. If not, see <http://www.gnu.org/licenses/>.
 */
package org.fuin.esmp;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.OS;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.input.CountingInputStream;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.fuin.utils4j.Utils4J;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Downloads the eventstore archive and unpacks it into a defined directory.
 */
@Mojo(name = "download", defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST, requiresProject = false)
public final class EventStoreDownloadMojo extends AbstractEventStoreMojo {

    private static final Logger LOG = LoggerFactory.getLogger(EventStoreDownloadMojo.class);

    private static final int MB = 1024 * 1024;

    @Override
    protected final void executeGoal() throws MojoExecutionException {

        // Do nothing if already in place
        if (getEventStoreDir().exists()) {
            LOG.info("Events store directory already exists: " + getEventStoreDir());
        } else {
            final File archive = downloadEventStoreArchive();
            unpack(archive);
        }
    }

    /**
     * Returns the file where the result of the download is located.
     * 
     * @return File where loaded bytes are stored.
     * 
     * @throws MojoExecutionException
     *             Error initializing the variables necessary to construct the
     *             result.
     */
    public final File getDownloadFile() throws MojoExecutionException {
        final String downloadUrl = getDownloadUrl();
        final String name = FilenameUtils.getName(downloadUrl);
        return new File(getEventStoreDir().getParentFile(), name);
    }

    private URL createDownloadURL() throws MojoExecutionException {
        try {
            return new URL(getDownloadUrl());
        } catch (final MalformedURLException ex) {
            throw new MojoExecutionException("Failed to construct download URL for the event store", ex);
        }
    }

    private File downloadEventStoreArchive() throws MojoExecutionException {

        final URL url = createDownloadURL();
        try {
            final File file = getDownloadFile();
            if (file.exists()) {
                LOG.info("Archive already exists in target directory: " + file);
            } else {
                LOG.info("Dowloading archive: " + url);
                // Cache the file locally in the temporary directory
                final File tmpFile = new File(Utils4J.getTempDir(), file.getName());
                if (!tmpFile.exists()) {
                    if (isProxyIgnored() == false) {
                        try {
                            setProxy(url);
                        } catch (URISyntaxException e) {
                            throw new MojoExecutionException("Failed to initialize the downloader: ", e);
                        }
                    }
                    download(url, tmpFile);
                    LOG.info("Archive downloaded to: " + tmpFile);
                }
                FileUtils.copyFile(tmpFile, file);
                LOG.info("Archive copied from '" + tmpFile + "' to:" + file);
            }
            return file;
        } catch (final IOException ex) {
            throw new MojoExecutionException("Error downloading event store archive: " + url, ex);
        }
    }

    private void download(final URL url, final File file) throws IOException {
        final InputStream in = new CountingInputStream(url.openStream()) {

            private int called = 0;

            @Override
            protected final void afterRead(final int n) {
                super.afterRead(n);
                called++;
                if ((called % 1000) == 0) {
                    LOG.info("{} - {} bytes", file.getName(), getCount());
                }
            }
        };
        try {
            FileUtils.copyInputStreamToFile(in, file);
        } finally {
            in.close();
        }
    }

    private void unpack(final File archive) throws MojoExecutionException {

        LOG.info("Unpack event store to target directory: " + getEventStoreDir());

        if (archive.getName().endsWith(".zip")) {
            // All files are in the root of the ZIP file (not in a sub folder as
            // with "tar.gz")
            final File destDir = getEventStoreDir();
            unzip(archive, destDir);
        } else if (archive.getName().endsWith(".tar.gz")) {
            final File destDir = getEventStoreDir().getParentFile();
            unTarGz(archive, destDir);
        } else {
            throw new MojoExecutionException("Cannot unpack file: " + archive.getName());
        }

    }

    private void unzip(final File zipFile, final File destDir) throws MojoExecutionException {

        try {
            final ZipFile zip = new ZipFile(zipFile);
            try {
                final Enumeration<? extends ZipEntry> enu = zip.entries();
                while (enu.hasMoreElements()) {
                    final ZipEntry entry = (ZipEntry) enu.nextElement();
                    final File file = new File(entry.getName());
                    if (file.isAbsolute()) {
                        throw new IllegalArgumentException(
                                "Only relative path entries are allowed! [" + entry.getName() + "]");
                    }
                    if (entry.isDirectory()) {
                        final File dir = new File(destDir, entry.getName());
                        createIfNecessary(dir);
                    } else {
                        final File outFile = new File(destDir, entry.getName());
                        createIfNecessary(outFile.getParentFile());
                        final InputStream in = new BufferedInputStream(zip.getInputStream(entry));
                        try {
                            final OutputStream out = new BufferedOutputStream(new FileOutputStream(outFile));
                            try {
                                final byte[] buf = new byte[4096];
                                int len;
                                while ((len = in.read(buf)) > 0) {
                                    out.write(buf, 0, len);
                                }
                            } finally {
                                out.close();
                            }
                        } finally {
                            in.close();
                        }
                    }
                }
            } finally {
                zip.close();
            }

        } catch (final IOException ex) {
            throw new MojoExecutionException("Error unzipping event store archive: " + zipFile, ex);
        }
    }

    private void unTarGz(final File archive, final File destDir) throws MojoExecutionException {

        try {
            final TarArchiveInputStream tarIn = new TarArchiveInputStream(
                    new GzipCompressorInputStream(new BufferedInputStream(new FileInputStream(archive))));
            try {
                TarArchiveEntry entry;
                while ((entry = (TarArchiveEntry) tarIn.getNextEntry()) != null) {
                    LOG.info("Extracting: " + entry.getName());
                    final File file = new File(destDir, entry.getName());
                    if (entry.isDirectory()) {
                        createIfNecessary(file);
                    } else {
                        int count;
                        final byte[] data = new byte[MB];
                        final FileOutputStream fos = new FileOutputStream(file);
                        final BufferedOutputStream dest = new BufferedOutputStream(fos, MB);
                        try {
                            while ((count = tarIn.read(data, 0, MB)) != -1) {
                                dest.write(data, 0, count);
                            }
                        } finally {
                            dest.close();
                        }
                        entry.getMode();
                    }
                    applyFileMode(file, new FileMode(entry.getMode()));
                }
            } finally {
                tarIn.close();
            }
        } catch (final IOException ex) {
            throw new MojoExecutionException("Error uncompressing event store archive: " + archive, ex);
        }
    }

    private static void createIfNecessary(final File dir) throws IOException {
        if (dir.exists()) {
            return;
        }
        if (!dir.mkdirs()) {
            throw new IOException("Error creating directory '" + dir + "'!");
        }
    }

    // CHECKSTYLE:OFF External code
    // Inspired by:
    // https://raw.githubusercontent.com/bluemel/RapidEnv/master/org.rapidbeans.rapidenv/src/org/rapidbeans/rapidenv/Unpacker.java
    private void applyFileMode(final File file, final FileMode fileMode) throws MojoExecutionException {

        if (OS.isFamilyUnix() || OS.isFamilyMac()) {
            final String smode = fileMode.toChmodStringFull();
            final CommandLine cmdLine = new CommandLine("chmod");
            cmdLine.addArgument(smode);
            cmdLine.addArgument(file.getAbsolutePath());
            final Executor executor = new DefaultExecutor();
            try {
                final int result = executor.execute(cmdLine);
                if (result != 0) {
                    throw new MojoExecutionException("Error # " + result + " while trying to set mode \"" + smode
                            + "\" for file: " + file.getAbsolutePath());
                }
            } catch (final IOException ex) {
                throw new MojoExecutionException(
                        "Error while trying to set mode \"" + smode + "\" for file: " + file.getAbsolutePath(), ex);
            }
        } else {
            file.setReadable(fileMode.isUr() || fileMode.isGr() || fileMode.isOr());
            file.setWritable(fileMode.isUw() || fileMode.isGw() || fileMode.isOw());
            file.setExecutable(fileMode.isUx() || fileMode.isGx() || fileMode.isOx());
        }
    }
    // CHECKSTYLE:ON

}