com.ariatemplates.attester.maven.ArtifactExtractor.java Source code

Java tutorial

Introduction

Here is the source code for com.ariatemplates.attester.maven.ArtifactExtractor.java

Source

/*
 * Copyright 2012 Amadeus s.a.s.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License 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 com.ariatemplates.attester.maven;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.handler.DefaultArtifactHandler;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.project.MavenProject;

/**
 * Extracts the zip dependencies of this plugin in a temporary directory named
 * according to the artifact. If a dependency is already extracted, it is not
 * extracted again.
 *
 * @goal extract-dependencies
 */
public class ArtifactExtractor extends AbstractMojo {

    /**
     * @parameter expression="${session}"
     * @readonly
     * @required
     *
     */
    protected MavenSession session;

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

    /**
     * Parent directory in which directories containing the extracted artifacts
     * will be created. If this parameter is not set, the temporary directory
     * defined in the <code>java.io.tmpdir</code> system property is used.
     *
     * @parameter
     */
    public File outputParentDirectory;

    /**
     * If set to true, files will be extracted directly in their final destination folder.
     * Otherwise, a temporary folder will first be created, then files will be extracted inside
     * that folder, and, finally, the folder will be renamed.
     *
     * @parameter
     */
    public boolean avoidRenamingTargetDirectory;

    public void execute() throws MojoExecutionException, MojoFailureException {
        try {
            Map<?, ?> context = getPluginContext();
            PluginDescriptor pluginDescriptor = (PluginDescriptor) context.get("pluginDescriptor");
            Model projectModel = project.getModel();
            for (Dependency dependency : pluginDescriptor.getPlugin().getDependencies()) {
                if ("zip".equalsIgnoreCase(dependency.getType())) {
                    String outputDirectory = inplaceExtractDependency(session.getLocalRepository(), dependency);
                    projectModel.addProperty(getPropertyName(dependency), outputDirectory);
                }
            }
        } catch (Exception e) {
            throw new MojoExecutionException("Error", e);
        }
    }

    public static String getPropertyName(Dependency dependency) {
        return "artifact.extracted:" + dependency.getManagementKey();
    }

    public static File getOutputDirectory(Artifact artifact) {
        return getOutputDirectory(artifact, null);
    }

    public static File getOutputDirectory(Artifact artifact, File parentDirectory) {
        if (parentDirectory == null) {
            parentDirectory = new File(System.getProperty("java.io.tmpdir"));
        }
        String name = artifact.getGroupId() + "-" + artifact.getArtifactId() + "-" + artifact.getVersion() + "-"
                + artifact.getClassifier();
        if (artifact.isSnapshot()) {
            name += "-" + artifact.getFile().lastModified();
        }
        File res = new File(parentDirectory, name);
        return res;
    }

    private boolean renameDirectory(File tempDirectory, File outputDirectory) throws InterruptedException {
        for (int remainingAttempts = 20; remainingAttempts > 0; remainingAttempts--) {
            if (outputDirectory.exists()) {
                // the output directory was created in the mean time
                // (probably by another build running in parallel)
                getLog().info("Another process probably extracted the artifact at the same time.");
                return true;
            } else if (tempDirectory.renameTo(outputDirectory)) {
                getLog().info("Renaming the folder succeeded!");
                return true;
            }
            // sleep a bit and retry, the failure may be temporary (file opened
            // by an anti-virus program...)
            getLog().warn("Renaming the folder failed! Will try again in 250ms...");
            Thread.sleep(250);
        }
        return false;
    }

    public String inplaceExtractDependency(ArtifactRepository localRepository, Dependency dependency)
            throws Exception {
        Artifact artifact = new DefaultArtifact(dependency.getGroupId(), dependency.getArtifactId(),
                dependency.getVersion(), dependency.getScope(), dependency.getType(), dependency.getClassifier(),
                new DefaultArtifactHandler("zip"));
        artifact = localRepository.find(artifact);
        File zipFile = artifact.getFile();
        File outputDirectory = getOutputDirectory(artifact, outputParentDirectory);
        if (outputDirectory.exists()) {
            // if the directory already exists, don't touch it (by the way, it
            // may currently be in use by some other process)
            getLog().info("Artifact " + artifact + " is already extracted in " + outputDirectory);
        } else {
            getLog().info("Extracting artifact " + artifact + " to " + outputDirectory);
            File tempDirectory = null;
            try {
                if (avoidRenamingTargetDirectory) {
                    unzip(zipFile, outputDirectory);
                } else {
                    // temporary directory where to extract
                    tempDirectory = File.createTempFile("extract", null, outputDirectory.getParentFile());
                    tempDirectory.delete(); // delete the file created by
                                            // createTempFile
                                            // (to replace it with a directory)
                    unzip(zipFile, tempDirectory);
                    // Move the temporary directory to its final location
                    if (!renameDirectory(tempDirectory, outputDirectory)) {
                        throw new Exception(
                                "Failed to rename directory " + tempDirectory + " to " + outputDirectory + ".");
                    }
                }
            } catch (Exception e) {
                getLog().error("An exception occurred while extracting the " + artifact + " artifact.", e);
                throw e;
            } finally {
                if (tempDirectory != null && tempDirectory.exists()) {
                    getLog().info("Deleting temporary directory " + tempDirectory);
                    FileUtils.deleteQuietly(tempDirectory);
                }
            }
        }
        return outputDirectory.getAbsolutePath();
    }

    public static void unzip(File zipFile, File outputFolder) throws IOException {
        ZipInputStream zipInputStream = null;
        try {
            ZipEntry entry = null;
            zipInputStream = new ZipInputStream(FileUtils.openInputStream(zipFile));
            while ((entry = zipInputStream.getNextEntry()) != null) {
                File outputFile = new File(outputFolder, entry.getName());

                if (entry.isDirectory()) {
                    outputFile.mkdirs();
                    continue;
                }

                OutputStream outputStream = null;
                try {
                    outputStream = FileUtils.openOutputStream(outputFile);
                    IOUtils.copy(zipInputStream, outputStream);
                    outputStream.close();
                } catch (IOException exception) {
                    outputFile.delete();
                    throw new IOException(exception);
                } finally {
                    IOUtils.closeQuietly(outputStream);
                }
            }
            zipInputStream.close();
        } finally {
            IOUtils.closeQuietly(zipInputStream);
        }
    }

}