com.github.jrh3k5.flume.mojo.plugin.AbstractFlumePluginMojo.java Source code

Java tutorial

Introduction

Here is the source code for com.github.jrh3k5.flume.mojo.plugin.AbstractFlumePluginMojo.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.github.jrh3k5.flume.mojo.plugin;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
import org.apache.maven.shared.dependency.graph.DependencyNode;

import com.github.jrh3k5.flume.mojo.plugin.io.ArchiveUtils;
import com.github.jrh3k5.flume.mojo.plugin.plexus.MojoLogger;

/**
 * Skeleton definition of a plugin that assembles a Flume plugin archive.
 * 
 * @author Joshua Hyde
 */
public abstract class AbstractFlumePluginMojo extends AbstractMojo {
    private final ArtifactFilter providedArtifactFilter = new ScopeArtifactFilter(Artifact.SCOPE_RUNTIME);

    /**
     * An {@link ArtifactRepository} used to resolve an artifact into an actual file.
     */
    @Parameter(required = true, readonly = true, defaultValue = "${localRepository}")
    private ArtifactRepository artifactRepository;

    /**
     * An {@link ArtifactResolver} used to copy dependencies.
     */
    @Component
    private ArtifactResolver artifactResolver;

    /**
     * Indicate whether or not the assembly should be attached to the project.
     */
    @Parameter(required = true, defaultValue = "true")
    private boolean attach;

    /**
     * The suffix to be appended to the Flume plugin file.
     */
    @Parameter(required = true, defaultValue = "flume-plugin")
    private String classifierSuffix;

    /**
     * A {@link DependencyGraphBuilder} used to assemble the dependency graph of the project consuming this plugin.
     */
    @Component(hint = "default")
    private DependencyGraphBuilder dependencyGraphBuilder;

    /**
     * The directory to which the final artifact should be written to.
     */
    @Parameter(required = true, defaultValue = "${project.build.directory}")
    private File outputDirectory;

    /**
     * The location where the plugin assembly will be staged prior to completion.
     */
    @Parameter(required = true, defaultValue = "${project.build.directory}/flume-plugins")
    private File pluginsStagingDirectory;

    /**
     * A representation of the project executing this plugin.
     */
    @Parameter(required = true, readonly = true, defaultValue = "${project}")
    private MavenProject project;

    /**
     * A {@link MavenProjectHelper} used to attach the created assembly to the deployment.
     */
    @Component(hint = "default")
    private MavenProjectHelper projectHelper;

    /**
     * A {@link List} of {@link ArtifactRepository} objects representing the remote repositories for artifacts.
     */
    @Parameter(required = true, readonly = true, defaultValue = "${project.remoteArtifactRepositories}")
    private List<ArtifactRepository> remoteArtifactRepositories;

    /**
     * A {@link List} of {@link Exclusion} objects representing the artifacts to be excluded from assembly.
     */
    @Parameter
    private List<Exclusion> exclusions = Collections.emptyList();

    /**
     * Format the name of an artifact.
     * 
     * @param artifact
     *            The {@link Artifact} whose name is to be formatted.
     * @return A formatted identifier of the given {@link Artifact}.
     */
    protected static String formatIdentifier(Artifact artifact) {
        return String.format("%s:%s:%s:%s", artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(),
                artifact.getType());
    }

    /**
     * Format the name of a Maven project.
     * 
     * @param mavenProject
     *            The {@link MavenProject} whose name is to be formatted.
     * @return A formatted identifier of the given {@link MavenProject}.
     */
    protected static String formatIdentifier(MavenProject mavenProject) {
        return String.format("%s:%s:%s:%s", mavenProject.getGroupId(), mavenProject.getArtifactId(),
                mavenProject.getVersion(), mavenProject.getPackaging());
    }

    /**
     * Build a Flume plugin.
     * 
     * @param pluginLibrary
     *            A {@link File} representing the library that is to copied into the {@code lib/} directory of the plugin.
     * @param mavenProject
     *            A {@link MavenProject} representing the project from which dependency information should be read.
     * @throws MojoExecutionException
     *             If any errors occur during the bundling of the plugin archive.
     */
    protected void buildFlumePluginArchive(File pluginLibrary, MavenProject mavenProject)
            throws MojoExecutionException {
        final String pluginName = getPluginName();
        // Create the directory into which the libraries will be copied
        final File pluginStagingDirectory = new File(pluginsStagingDirectory,
                String.format("%s-staging", pluginName));
        final File stagingDirectory = new File(pluginStagingDirectory, pluginName);
        try {
            FileUtils.forceMkdir(stagingDirectory);
        } catch (IOException e) {
            throw new MojoExecutionException("Failed to create directory: " + stagingDirectory.getAbsolutePath(),
                    e);
        }

        final File libDirectory = new File(stagingDirectory, "lib");
        // Copy the primary library
        try {
            FileUtils.copyFile(pluginLibrary, new File(libDirectory, pluginLibrary.getName()));
        } catch (IOException e) {
            throw new MojoExecutionException(
                    "Failed to copy primary artifact to staging lib directory: " + libDirectory.getAbsolutePath(),
                    e);
        }

        // Copy the dependencies of the plugin into the libext directory
        final File libExtDirectory = new File(stagingDirectory, "libext");
        final AndArtifactFilter joinFilter = new AndArtifactFilter();
        joinFilter.add(providedArtifactFilter);
        joinFilter.add(new ExclusionArtifactFilter(exclusions));
        for (DependencyNode resolvedDependency : resolveDependencies(mavenProject, joinFilter)) {
            copyPluginDependency(resolvedDependency, libExtDirectory);
        }

        // Because of the way that Maven represents dependency trees, the above logic may copy the given plugin library into libext - remove it if so
        final File pluginLibraryLibExt = new File(libExtDirectory, pluginLibrary.getName());
        if (pluginLibraryLibExt.exists()) {
            try {
                FileUtils.forceDelete(pluginLibraryLibExt);
            } catch (IOException e) {
                throw new MojoExecutionException("Failed to delete file: " + pluginLibraryLibExt.getAbsolutePath(),
                        e);
            }
        }

        String classifier = null;
        // If the plugin name is the same as the artifact, then don't bother over-complicating the classifier
        if (project.getArtifactId().equals(pluginName)) {
            classifier = classifierSuffix;
        } else {
            classifier = String.format("%s-%s", pluginName, classifierSuffix);
        }
        final ArchiveUtils archiveUtils = ArchiveUtils.getInstance(new MojoLogger(getLog(), getClass()));
        // Create the TAR
        final File tarFile = new File(pluginStagingDirectory,
                String.format("%s-%s-%s.tar", project.getArtifactId(), project.getVersion(), classifier));
        try {
            archiveUtils.tarDirectory(pluginStagingDirectory, tarFile);
        } catch (IOException e) {
            throw new MojoExecutionException(String.format("Failed to TAR directory %s to file %s",
                    stagingDirectory.getAbsolutePath(), tarFile.getAbsolutePath()), e);
        }

        // GZIP the TAR file
        final File gzipFile = new File(outputDirectory, String.format("%s.gz", tarFile.getName()));
        try {
            archiveUtils.gzipFile(tarFile, gzipFile);
        } catch (IOException e) {
            throw new MojoExecutionException(String.format("Failed to gzip TAR file %s to %s",
                    tarFile.getAbsolutePath(), gzipFile.getAbsolutePath()), e);
        }

        // Attach the artifact, if configured to do so
        if (attach) {
            projectHelper.attachArtifact(project, "tar.gz", classifier, gzipFile);
        }
    }

    /**
     * Get the artifact repository.
     * 
     * @return An {@link ArtifactRepository}.
     */
    protected ArtifactRepository getArtifactRepository() {
        return artifactRepository;
    }

    /**
     * Get the Maven project.
     * 
     * @return A {@link MavenProject} object representing the current project.
     */
    protected MavenProject getProject() {
        return project;
    }

    /**
     * Get a list of remote repositories that can contain dependencies.
     * 
     * @return A {@link List} of {@link ArtifactRepository} objects representing the remote artifact repositories.
     */
    protected List<ArtifactRepository> getRemoteArtifactRepositories() {
        return remoteArtifactRepositories;
    }

    /**
     * Get the name of the plugin to be assembled.
     * 
     * @return The name of the plugin to be assembled.
     */
    protected abstract String getPluginName();

    /**
     * Resolve dependencies of a project matching the given filter.
     * 
     * @param mavenProject
     *            The {@link MavenProject} whose dependency tree is to be read.
     * @param artifactFilter
     *            An {@link ArtifactFilter} that will determine what artifacts are to qualify.
     * @return A {@link List} of {@link DependencyNode} objects representing the matching dependencies.
     * @throws MojoExecutionException
     *             If any errors occur while trying to resolve the dependencies.
     */
    protected List<DependencyNode> resolveDependencies(MavenProject mavenProject, ArtifactFilter artifactFilter)
            throws MojoExecutionException {
        try {
            return dependencyGraphBuilder.buildDependencyGraph(project, artifactFilter).getChildren();
        } catch (DependencyGraphBuilderException e) {
            throw new MojoExecutionException(
                    String.format("Failed to build dependency graph for project %s", formatIdentifier(project)), e);
        }
    }

    /**
     * Copy the given plugin dependency - and all of its children - to the {@code libext/} directory.
     * 
     * @param dependencyNode
     *            The {@link DependencyNode} whose artifact and children are to be copied.
     * @param libExtDirectory
     *            A {@link File} representing the directory to which the libraries are to be copied.
     * @throws MojoExecutionException
     *             If any errors occur during the copying.
     */
    private void copyPluginDependency(DependencyNode dependencyNode, File libExtDirectory)
            throws MojoExecutionException {
        final Artifact resolvedArtifact = artifactRepository.find(dependencyNode.getArtifact());
        try {
            FileUtils.copyFile(resolvedArtifact.getFile(),
                    new File(libExtDirectory, resolvedArtifact.getFile().getName()));
        } catch (IOException e) {
            throw new MojoExecutionException(String.format("Failed to copy artifact %s to %s.",
                    formatIdentifier(resolvedArtifact), libExtDirectory.getAbsolutePath()), e);
        }
        // Recursively copy all other libraries
        for (DependencyNode child : dependencyNode.getChildren()) {
            copyPluginDependency(child, libExtDirectory);
        }
    }
}