net.sf.buildbox.maven.contentcheck.LicenseShowMojo.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.buildbox.maven.contentcheck.LicenseShowMojo.java

Source

package net.sf.buildbox.maven.contentcheck;

import static net.sf.buildbox.maven.contentcheck.PathUtils.stripJARNameFromPath;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sf.buildbox.maven.contentcheck.dependencies.CsvOutput;
import net.sf.buildbox.maven.contentcheck.dependencies.LicenseMappingParser;
import net.sf.buildbox.maven.contentcheck.dependencies.LicenseOutput;
import net.sf.buildbox.maven.contentcheck.dependencies.LogOutput;
import net.sf.buildbox.maven.contentcheck.introspection.DefaultIntrospector;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.manager.WagonManager;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
import org.apache.maven.artifact.resolver.ArtifactCollector;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.model.License;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.report.projectinfo.dependencies.Dependencies;
import org.apache.maven.report.projectinfo.dependencies.RepositoryUtils;
import org.apache.maven.settings.Settings;
import org.apache.maven.shared.dependency.tree.DependencyNode;
import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder;
import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException;
import org.apache.maven.shared.jar.classes.JarClassesAnalysis;

/**
 * This MOJO shows license information for an archive entries. Artifact resolving
 * and the rest of Maven repo magic taken from <a href="http://maven.apache.org/plugins/maven-project-info-reports-plugin/index.html">Maven Project Info Reports Plugin</a>.
 * The MOJO shows license information only for entities that matches criteria
 * defined by {@link #getCheckFilesPattern()} and {@link #isIgnoreVendorArchives()}.
 * <p>
 * The MOJO's output is printed by default to console log and also to CSV file
 * <cite>${project.build.directory}/licenses.csv</cite>.
 * <p>
 * License information is gathered from dependency's POM, but a project may define
 * additional mapping between files in a project archive and licenses. This mapping
 * file is <cite>src/main/license.mapping.json</cite> and its structure is JSON.
 * <h4>Additional license information</h4>
 * <pre><code>
 * {
 * "licenses": [
 *       {
 *          "name" : "License name",
 *           "url"  : "License text URL",
 *           "files": [
 *               "file name"
 *            ]
 *       }
 *  ]
 * }
 * </code></pre>
 * <h4>Example</h4>
 * <pre><code>
 * {
 * "licenses": [
 *
 *       {
 *           "name"  : "The LGPL license 2.1",
 *           "url"   : "http://www.gnu.org/licenses/lgpl-2.1.html",
 *           "files" : [
 *                         "aspectwerkz-nodeps-jdk5-2.2.1.jar"
 *           ]
 *       },
 *
 *       {
 *           "name"  : "The public domain",
 *           "url"   : "http://creativecommons.org/licenses/publicdomain/",
 *           "files" : [
 *               "jsr166x-1.0.jar",
 *               "xyz.jar"
 *           ]
 *       }
 *   ]
 * }
 * </code></pre>
 *
 * @goal show-licenses
 */
public class LicenseShowMojo extends AbstractArchiveContentMojo {

    /**
     * The license mapping file. This file may define additional license information
     * for JARs that are not recognized.
     *
     * @parameter default-value="src/main/license.mapping.json"
     */
    private File licenseMappingFile;

    /**
     * If true print the result of check to a CSV file in project build directory.
     * See {@link #csvOutputFile}
     *
     * @parameter default-value="true"
     */
    private boolean csvOutput;

    /**
     * The CSV output file that is used when {@link #csvOutput} is turned on.
     *
     * @parameter default-value="${project.build.directory}/licenses.csv"
     */
    private File csvOutputFile;

    /**
     * Artifact collector component.
     *
     * @component
     */
    private ArtifactCollector collector;

    /**
     * Artifact Factory component.
     *
     * @component
     */
    private ArtifactFactory factory;

    /**
     * Dependency tree builder component.
     *
     * @since 2.1
     * @component
     */
    private DependencyTreeBuilder dependencyTreeBuilder;

    /**
     * Artifact metadata source component.
     *
     * @component
     */
    private ArtifactMetadataSource artifactMetadataSource;

    /**
     * Jar classes analyzer component.
     *
     * @since 2.1
     * @component
     */
    private JarClassesAnalysis classesAnalyzer;

    /**
     * Local Repository.
     *
     * @parameter expression="${localRepository}"
     * @required
     * @readonly
     */
    private ArtifactRepository localRepository;

    /**
     * Maven Project Builder component.
     *
     * @component
     */
    private MavenProjectBuilder mavenProjectBuilder;

    /**
     * The current user system settings for use in Maven.
     *
     * @parameter expression="${settings}"
     * @required
     * @readonly
     * @since 2.3
     */
    protected Settings settings;

    /**
     * Wagon manager component.
     *
     * @since 2.1
     * @component
     */
    private WagonManager wagonManager;

    /**
     * Artifact Resolver component.
     *
     * @component
     */
    protected ArtifactResolver resolver;

    /**
     * Repository metadata component.
     *
     * @since 2.1
     * @component
     */
    private RepositoryMetadataManager repositoryMetadataManager;

    /**
     * @see net.sf.buildbox.maven.contentcheck.AbstractArchiveContentMojo#doExecute()
     */
    @Override
    protected void doExecute() throws IOException, MojoExecutionException, MojoFailureException {
        List<MavenProject> mavenProjectForDependencies = getMavenProjectForDependencies();

        DefaultIntrospector introspector = new DefaultIntrospector(getLog(), isIgnoreVendorArchives(),
                getVendorId(), getManifestVendorEntry(), getCheckFilesPattern());
        introspector.readArchive(getArchive());

        Set<String> archiveEntries = new LinkedHashSet<String>(introspector.getArchiveEntries());
        Map<String, List<License>> entries = new LinkedHashMap<String, List<License>>();

        Map<String, List<License>> additionalLicenseInformation = new LinkedHashMap<String, List<License>>();
        if (licenseMappingFile != null && licenseMappingFile.exists()) {
            //read additional license information
            LicenseMappingParser licenseMappingParser = new LicenseMappingParser(getLog(), licenseMappingFile);
            additionalLicenseInformation.putAll(licenseMappingParser.parseLicenseMappingFile());
        }

        getLog().info("Comparing the archive content with Maven project artifacts");
        for (String archiveEntry : archiveEntries) {
            List<License> licenses = null; //these licenses will be associated with the given archive entry

            for (MavenProject mavenProject : mavenProjectForDependencies) {
                mavenProject.getGroupId();
                String artifactId = mavenProject.getArtifactId();
                String version = mavenProject.getVersion();
                String jarName = artifactId + "-" + version + ".jar"; //guess jar name
                if (archiveEntry.endsWith(jarName)) {
                    @SuppressWarnings("unchecked")
                    List<License> _licenses = mavenProject.getLicenses();
                    licenses = _licenses == null || _licenses.size() == 0 ? null : _licenses;
                    break;
                }
            }

            List<License> licensesMappingFile = additionalLicenseInformation
                    .get(stripJARNameFromPath(archiveEntry));

            if (licenses == null && licensesMappingFile == null) {//misising license information
                getLog().debug(String.format(
                        "Cannot resolve license information for archive entry %s neither from the POM file nor the file for license mapping",
                        archiveEntry));
                //archive entry must be present even if there is no a matching Maven Project
                entries.put(archiveEntry, Collections.<License>emptyList());
            } else if (licenses != null && licensesMappingFile != null) {//licenses specified in both - POM and license mapping file
                getLog().warn(String.format(
                        "The license information for file %s are defined in the POM file and also in the file for license mapping. Using license information from the the file for license mapping.",
                        archiveEntry));
                entries.put(archiveEntry, licensesMappingFile); //mapping manually specified licenses precedes licenses from POM
            } else if (licenses != null) {//license information in POM
                entries.put(archiveEntry, licenses);//license
            } else {
                //license information in mapping file
                //put additional license information to the object that holds this information
                entries.put(archiveEntry, licensesMappingFile);
            }
        }

        LicenseOutput logOutput = new LogOutput(getLog());
        logOutput.output(entries);

        if (csvOutput) {
            CsvOutput csvOutput = new CsvOutput(getLog(), csvOutputFile);
            csvOutput.output(entries);
        }
    }

    private List<MavenProject> getMavenProjectForDependencies()
            throws MojoExecutionException, MojoFailureException {
        DependencyNode dependencyTreeNode = resolveProject();
        MavenProject project = getMavenProject();
        Dependencies dependencies = new Dependencies(project, dependencyTreeNode, classesAnalyzer);
        Log log = getLog();
        RepositoryUtils repoUtils = new RepositoryUtils(log, wagonManager, settings, mavenProjectBuilder, factory,
                resolver, project.getRemoteArtifactRepositories(), project.getPluginArtifactRepositories(),
                localRepository, repositoryMetadataManager);
        Artifact projectArtifact = project.getArtifact();
        log.info(String.format("Resolving project %s:%s:%s dependencies", projectArtifact.getGroupId(),
                projectArtifact.getArtifactId(), projectArtifact.getVersion()));
        List<Artifact> allDependencies = dependencies.getAllDependencies();
        List<MavenProject> mavenProjects = new ArrayList<MavenProject>();
        for (Artifact artifact : allDependencies) {
            log.debug(String.format("Resolving project information for %s:%s:%s", artifact.getGroupId(),
                    artifact.getArtifactId(), artifact.getVersion()));
            try {
                MavenProject mavenProject = repoUtils.getMavenProjectFromRepository(artifact);
                mavenProjects.add(mavenProject);
            } catch (ProjectBuildingException e) {
                throw new MojoFailureException(
                        String.format("Cannot get project information for artifact %s:%s:%s from repository",
                                artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()),
                        e);
            }
        }
        return mavenProjects;
    }

    /**
     * @return resolve the dependency tree
     */
    private DependencyNode resolveProject() {
        try {
            ArtifactFilter artifactFilter = new ScopeArtifactFilter(Artifact.SCOPE_TEST);
            return dependencyTreeBuilder.buildDependencyTree(getMavenProject(), localRepository, factory,
                    artifactMetadataSource, artifactFilter, collector);
        } catch (DependencyTreeBuilderException e) {
            getLog().error("Unable to build dependency tree.", e);
            return null;
        }
    }

    /**
     * MavenProject placeholder for JARs that we are not able to connect with
     * existing MavenProjects.
     */
    public static class NullMavenProject extends MavenProject {
        @Override
        public List getLicenses() {
            return Collections.EMPTY_LIST;
        }

    }
}