com.secristfamily.maven.plugin.ZipMojo.java Source code

Java tutorial

Introduction

Here is the source code for com.secristfamily.maven.plugin.ZipMojo.java

Source

package com.secristfamily.maven.plugin;

import java.io.File;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.maven.archiver.MavenArchiveConfiguration;
import org.apache.maven.archiver.MavenArchiver;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.codehaus.plexus.archiver.Archiver;
import org.codehaus.plexus.archiver.jar.JarArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;

/**
 * @goal zip
 * @requiresDependencyResolution runtime
 * @author Randy K. Secrist
 */
public class ZipMojo extends AbstractMojo {

    /**
     * The Maven project.
     * 
     * @parameter default-value="${project}"
     * @required
     * @readonly
     */
    private MavenProject project;

    /**
     * @component
     */
    private MavenProjectHelper projectHelper;

    /**
     * To look up Archiver/UnArchiver implementations
     * 
     * @component role="org.codehaus.plexus.archiver.manager.ArchiverManager"
     * @required
     */
    protected ArchiverManager archiverManager;

    /**
     * Directory containing the generated ZIP. (target/)
     * 
     * @parameter default-value="${project.build.directory}"
     * @required
     */
    private File outputDirectory;

    /**
     * Whether to use the defined directories as the base or the root
     * 
     * @parameter
     */
    private boolean basedirectory;

    /**
     * The directories and files to include within the archive.
     * 
     * @parameter
     */
    private File[] include;

    /**
     * Any files or directories matching any one of these regular expressions will not be included,
     * even if explicitly declared to be included in the include parameter.
     * 
     * @parameter
     */
    private List<String> excludeRegexList;

    /**
     * Directory containing the compiled classes. (target/classes)
     * 
     * @parameter default-value="${project.build.outputDirectory}"
     * @required
     */
    private File classesDirectory;

    /**
     * Flag which indicates if the mojo should incorporate dependencies into the ZIP archive.
     * 
     * @parameter default-value="true"
     */
    private boolean addDependencies;

    /**
     * Flag which indicates to the mojo if it should generate the primary artifact from the current
     * project.
     * 
     * @parameter default-value="false"
     */
    private boolean generatePrimaryArtifact;

    /**
     * ArtifactId of the primary dependency
     * 
     * @parameter
     */
    private String primaryArtifactId;

    /**
     * Name of the generated ZIP.
     * 
     * @parameter alias="zipName" default-value="${project.build.finalName}"
     * @required
     */
    private String finalName;

    /**
     * Classifier to add to the artifact generated. If given, the artifact will be an attachment
     * instead.
     * 
     * @parameter
     */
    private String classifier;

    /**
     * The Jar archiver.
     * 
     * @component role="org.codehaus.plexus.archiver.Archiver" roleHint="jar"
     * @required
     */
    private JarArchiver jarArchiver;

    /**
     * The maven archiver to use.
     * 
     * @parameter
     */
    private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();

    private static final String[] DEFAULT_EXCLUDES = new String[] { "**/package.html" };

    private static final String[] DEFAULT_INCLUDES = new String[] { "**/**" };

    protected final MavenProject getProject() {
        return project;
    }

    protected String getClassifier() {
        return classifier;
    }

    /**
     * Executes this POM plugin.
     */
    public void execute() throws MojoExecutionException, MojoFailureException {
        getLog().info("Creating ZIP...");

        File zipFile = createArchive();

        String classifier = getClassifier();
        if (classifier != null)
            projectHelper.attachArtifact(getProject(), "zip", classifier, zipFile);
        else
            getProject().getArtifact().setFile(zipFile);
    }

    protected static File getJarFile(File basedir, String finalName, String classifier) {
        return getFile(basedir, finalName, classifier, ".jar");
    }

    protected static File getZipFile(File basedir, String finalName, String classifier) {
        return getFile(basedir, finalName, classifier, ".zip");
    }

    protected static File getFile(File basedir, String finalName, String classifier, String extension) {
        if (classifier == null)
            classifier = "";
        else if (classifier.trim().length() > 0 && !classifier.startsWith("-"))
            classifier = "-" + classifier;
        return new File(basedir, finalName + classifier + extension);
    }

    public Archiver getArchiver() throws MojoExecutionException {
        try {
            return this.archiverManager.getArchiver("zip");
        } catch (NoSuchArchiverException e) {
            throw new MojoExecutionException("Could not locate archiver: ", e);
        }
    }

    /**
     * Generates the ZIP.
     * 
     * @todo Add license files in META-INF directory.
     */
    public File createArchive() throws MojoExecutionException, MojoFailureException {
        File destFile = getZipFile(outputDirectory, finalName, getClassifier());

        Archiver archive = this.getArchiver();
        archive.setDestFile(destFile);

        // Create Workspace
        File tempDir = new File(outputDirectory, "temp");
        if (!tempDir.exists())
            tempDir.mkdirs();
        boolean addTempDir = false;

        // Generates a primary artifact (from the current project) and adds it to the ZIP.
        // Only compatibile with JAR artifacts, (Utilizes the JAR plugin)
        if (generatePrimaryArtifact == true) {
            addTempDir = true;
            File jarFile = getJarFile(tempDir, finalName, getClassifier());
            this.createMainJarArchive(jarFile, classesDirectory);
        }

        // Copy artifacts to temp/lib directory (primaryDependency to temp)
        if (addDependencies) {
            Set<Artifact> dependencies = this.getDependencies();
            if (dependencies != null && dependencies.size() > 0) {
                addTempDir = true;
                File lib = new File(tempDir, "lib");
                if (!lib.exists())
                    lib.mkdirs();
                for (Artifact a : dependencies) {
                    if (primaryArtifactId != null && a.getArtifactId().equals(primaryArtifactId)) {
                        // add runtime dependencies not declared in primaryArtifact due to circular
                        // nature
                        if (this.getProject().getDependencies().size() > 1) {
                            addLocalDependencies(a.getFile(), tempDir);
                        }
                        FileUtils.copyFile(a.getFile(), new File(lib.getParentFile(), a.getFile().getName()));
                    } else if (!a.getScope().equals("test")) { // only adds non test dependencies.
                        FileUtils.copyFile(a.getFile(), new File(lib, a.getFile().getName()));
                    }
                }
            }
        }

        if (include != null) {
            addTempDir = true;
            if (basedirectory) {
                for (File f : include) {
                    File[] files = f.listFiles();
                    if (files != null) {
                        for (File child : files) {
                            copyToWorkspace(tempDir, child);
                        }
                    }
                }
            } else {
                for (File f : include) {
                    copyToWorkspace(tempDir, f);
                }
            }
        }

        try {
            // Add Dependencies to ZIP
            if (addTempDir)
                archive.addDirectory(tempDir);

            // Write File
            archive.createArchive();
        } catch (Throwable e) {
            throw new MojoExecutionException("Problem creating archive: ", e);
        } finally {
            FileUtils.deleteDirectory(tempDir);
        }

        return destFile;
    }

    /**
     * Copies the file into the workspace directory only if it does not match the exclude regular
     * expression, if one is given.
     * 
     * @param tempDir -
     *            the workspace directory
     * @param f -
     *            the file to copy
     * @throws MojoExecutionException
     */
    private void copyToWorkspace(File tempDir, File f) throws MojoExecutionException {
        String fName = f.getName();
        if (excludeDelegate.exclude(fName)) {
            return;
        }

        if (f.isDirectory())
            FileUtils.copyDirectory(f, new File(tempDir, fName), excludeDelegate);
        else if (f.isFile())
            FileUtils.copyFile(f, new File(tempDir, fName));
    }

    /**
     * Adds the dependencies of this project to a primary artifact. (Essentially combines two jar
     * files).
     * 
     * @param primaryArtifact
     *            The primary artifact to modify.
     * @param tempDir
     *            The temporary directory space to operate within.
     * @throws MojoExecutionException
     *             If any problems occur during the merge.
     */
    protected void addLocalDependencies(File primaryArtifact, File tempDir) throws MojoExecutionException {
        File tmp = new File(tempDir, "tmp");
        FileUtils.explodeZip(primaryArtifact, tmp);
        FileUtils.deleteDirectory(new File(tmp, "META-INF"));
        try {
            createMainJarArchive(primaryArtifact, tmp);
        } catch (Throwable e) {
            getLog().error(e);
        } finally {
            FileUtils.deleteDirectory(tmp);
        }
    }

    /**
     * Creates a JarArchive where the contents are the specified directory.
     * 
     * @param jarFile
     *            The JAR file to create.
     * @param directory
     *            The directory to include in the JAR file.
     * @throws MojoExecutionException
     *             If any problems occur during the creation.
     */
    public void createMainJarArchive(File jarFile, File directory) throws MojoExecutionException {
        try {
            MavenArchiver archiver = new MavenArchiver();
            archiver.setArchiver(jarArchiver);
            archiver.setOutputFile(jarFile);
            if (!directory.exists()) {
                getLog().warn("JAR will be empty - no content was marked for inclusion!");
            } else {
                archiver.getArchiver().addDirectory(directory, DEFAULT_INCLUDES, DEFAULT_EXCLUDES);
            }
            archiver.createArchive(project, archive);
        } catch (Throwable e) {
            throw new MojoExecutionException("Problem creating executable jar: ", e);
        }
        return;
    }

    /**
     * Retrieves all artifact dependencies.
     * 
     * @return A HashSet of artifacts
     */
    protected Set<Artifact> getDependencies() {
        MavenProject project = getProject();

        Set<Artifact> dependenciesSet = new HashSet<Artifact>();

        if (project.getArtifact() != null && project.getArtifact().getFile() != null)
            dependenciesSet.add(project.getArtifact());

        // As of version 1.5, project dependencies require runtime resolution:
        // see requiresDependencyResolution definition at top of class.
        Set projectArtifacts = project.getArtifacts();
        if (projectArtifacts != null)
            dependenciesSet.addAll(projectArtifacts);

        this.filterArtifacts(dependenciesSet);
        return dependenciesSet;
    }

    protected void filterArtifacts(Set<Artifact> artifacts) {
        for (Iterator i = artifacts.iterator(); i.hasNext();) {
            Artifact a = (Artifact) i.next();
            String fname = a.getFile().getName();
            String ext = fname.substring(fname.length() - 3, fname.length());
            if (!"jar".equalsIgnoreCase(ext))
                i.remove();
        }
    }

    private Exclusion excludeDelegate = new Exclusion();

    public class Exclusion {
        public boolean exclude(String candidate) {
            if (ZipMojo.this.excludeRegexList != null) {
                for (String regex : ZipMojo.this.excludeRegexList) {
                    if (candidate.matches(regex)) {
                        return true;
                    }
                }
            }
            return false;
        }
    }

}