org.jahia.utils.maven.plugin.osgi.FindPackageUsesMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.jahia.utils.maven.plugin.osgi.FindPackageUsesMojo.java

Source

/**
 * ==========================================================================================
 * =                   JAHIA'S DUAL LICENSING - IMPORTANT INFORMATION                       =
 * ==========================================================================================
 *
 *                                 http://www.jahia.com
 *
 *     Copyright (C) 2002-2018 Jahia Solutions Group SA. All rights reserved.
 *
 *     THIS FILE IS AVAILABLE UNDER TWO DIFFERENT LICENSES:
 *     1/GPL OR 2/JSEL
 *
 *     1/ GPL
 *     ==================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE GPL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program 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 General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 *
 *     2/ JSEL - Commercial and Supported Versions of the program
 *     ===================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE JSEL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     Alternatively, commercial and supported versions of the program - also known as
 *     Enterprise Distributions - must be used in accordance with the terms and conditions
 *     contained in a separate written agreement between you and Jahia Solutions Group SA.
 *
 *     If you are unsure which license is appropriate for your use,
 *     please contact the sales department at sales@jahia.com.
 */
package org.jahia.utils.maven.plugin.osgi;

import org.apache.commons.io.IOUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.plugin.AbstractMojo;
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.jahia.utils.osgi.ClassDependencyTracker;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.jar.JarInputStream;

/**
 * A little utility goal to locate a package usage inside the project's dependencies, using BND to make sure we
 * scan the same way.
 *
 * @goal find-package-uses
 * @requiresDependencyResolution test
 */
public class FindPackageUsesMojo extends AbstractMojo {

    /**
     * @parameter default-value="${packageNames}"
     */
    protected List<String> packageNames = new ArrayList<String>();

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

    /**
     * The directory for the generated bundles.
     *
     * @parameter expression="${project.build.outputDirectory}"
     * @required
     */
    private File outputDirectory;

    /**
     * @parameter default-value="true"
     */
    private boolean searchInDependencies = true;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        if (packageNames == null || packageNames.size() == 0) {
            getLog().warn("No package names specified, will abort now !");
            return;
        }
        final Map<String, Map<String, Artifact>> packageResults = findPackageUses(packageNames,
                project.getArtifacts(), project, outputDirectory, searchInDependencies, getLog());
        getLog().info("=================================================================================");
        getLog().info("SEARCH RESULTS SUMMARY");
        getLog().info("---------------------------------------------------------------------------------");
        for (String packageName : packageNames) {
            if (!packageResults.containsKey(packageName)) {
                getLog().warn("Couldn't find " + packageName + " uses anywhere !");
            } else {
                getLog().info("Package " + packageName + " used in :");
                Map<String, Artifact> foundClasses = packageResults.get(packageName);
                for (Map.Entry<String, Artifact> foundClass : foundClasses.entrySet()) {
                    getLog().info("  " + foundClass.getKey() + " ( " + foundClass.getValue().getFile() + ")");
                }
            }
        }
    }

    public static Map<String, Map<String, Artifact>> findPackageUses(List<String> packageNames,
            Set<Artifact> artifacts, MavenProject project, File buildOutputDirectory, boolean searchInDependencies,
            Log log) {
        final Map<String, Map<String, Artifact>> packageResults = new TreeMap<String, Map<String, Artifact>>();

        log.info("Scanning project build directory...");

        if (buildOutputDirectory.exists()) {
            findPackageUsesInDirectory(packageNames, project, log, packageResults, buildOutputDirectory);
        }

        if (!searchInDependencies) {
            return packageResults;
        }

        log.info("Scanning project dependencies...");

        for (Artifact artifact : artifacts) {
            if (artifact.isOptional()) {
                log.debug("Processing optional dependency " + artifact + "...");
            }
            if (artifact.getType().equals("pom")) {
                log.warn("Skipping POM artifact " + artifact);
                continue;
            }
            if (!artifact.getType().equals("jar")) {
                log.warn("Found non JAR artifact " + artifact);
            }
            findPackageUsesInArtifact(packageNames, project, log, packageResults, artifact);
        }
        return packageResults;
    }

    public static void findPackageUsesInArtifact(List<String> packageNames, MavenProject project, Log log,
            Map<String, Map<String, Artifact>> packageResults, Artifact artifact) {
        boolean currentTrailWasDisplayed = false;
        int trailDepth = artifact.getDependencyTrail().size();
        for (String packageName : packageNames) {
            Map<String, Artifact> foundClasses = packageResults.get(packageName);
            if (foundClasses == null) {
                foundClasses = new TreeMap<String, Artifact>();
            }
            Set<String> classesThatHaveDependency = findClassesThatUsePackage(artifact.getFile(), packageName,
                    project, log);
            if (classesThatHaveDependency != null & classesThatHaveDependency.size() > 0) {
                List<String> trail = new ArrayList<String>(artifact.getDependencyTrail());
                if (artifact.isOptional()) {
                    trail.add("[optional]");
                }
                for (String classThatHasDependency : classesThatHaveDependency) {
                    if (!currentTrailWasDisplayed) {
                        displayTrailTree(project, artifact, log);
                        currentTrailWasDisplayed = true;
                    }
                    log.info(getPaddingString(trailDepth) + "+--> Found class " + classThatHasDependency
                            + " that uses package " + packageName);
                    foundClasses.put(classThatHasDependency, artifact);
                }
                packageResults.put(packageName, foundClasses);
            }
        }
    }

    public static void findPackageUsesInDirectory(List<String> packageNames, MavenProject project, Log log,
            Map<String, Map<String, Artifact>> packageResults, File directory) {
        for (String packageName : packageNames) {
            Map<String, Artifact> foundClasses = packageResults.get(packageName);
            if (foundClasses == null) {
                foundClasses = new TreeMap<String, Artifact>();
            }
            Set<String> classesThatHaveDependency = findClassesThatUsePackage(directory, packageName, project, log);
            if (classesThatHaveDependency != null & classesThatHaveDependency.size() > 0) {
                for (String classThatHasDependency : classesThatHaveDependency) {
                    log.info("+--> Found class " + classThatHasDependency + " that uses package " + packageName);
                    foundClasses.put(classThatHasDependency, project.getArtifact());
                }
                packageResults.put(packageName, foundClasses);
            }
        }
    }

    private static Set<String> findClassesThatUsePackage(File jarFile, String packageName, MavenProject project,
            Log log) {
        Set<String> classesThatHaveDependency = new TreeSet<String>();
        JarInputStream jarInputStream = null;
        if (jarFile == null) {
            log.warn("File is null !");
            return classesThatHaveDependency;
        }
        if (!jarFile.exists()) {
            log.warn("File " + jarFile + " does not exist !");
            return classesThatHaveDependency;
        }
        log.debug("Scanning JAR " + jarFile + "...");
        try {
            classesThatHaveDependency = ClassDependencyTracker.findDependencyInJar(jarFile, packageName,
                    project.getTestClasspathElements());
        } catch (IOException e) {
            e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
        } catch (DependencyResolutionRequiredException e) {
            e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
        } finally {
            IOUtils.closeQuietly(jarInputStream);
        }
        return classesThatHaveDependency;
    }

    private static void displayTrailTree(MavenProject project, Artifact artifact, Log log) {
        StringBuilder builder = new StringBuilder();
        int i = 0;
        for (String trailEntry : artifact.getDependencyTrail()) {
            builder.append(trailEntry);
            Artifact dependencyArtifact = findArtifactInProject(project, trailEntry, log);
            if (dependencyArtifact != null) {
                if (dependencyArtifact.isOptional()) {
                    builder.append(" [OPTIONAL]");
                }
                if (dependencyArtifact.getScope() != null
                        && dependencyArtifact.getScope().contains(Artifact.SCOPE_PROVIDED)) {
                    builder.append(" [PROVIDED]");
                }
            }
            if (i < artifact.getDependencyTrail().size() - 1) {
                log.info(builder.toString());
                builder = new StringBuilder();
                builder.append(getPaddingString(i));
                builder.append("+- ");
            }
            i++;
        }
        builder.append(" (" + artifact.getFile() + ") : ");
        log.info(builder.toString());
    }

    private static Artifact findArtifactInProject(MavenProject project, String artifactIdentifier, Log log) {
        List<Artifact> results = new ArrayList<Artifact>();
        if (artifactMatches(project.getArtifact(), artifactIdentifier)) {
            results.add(project.getArtifact());
        }
        for (Artifact artifact : project.getArtifacts()) {
            if (artifactMatches(artifact, artifactIdentifier)) {
                results.add(artifact);
            }
        }
        if (results.size() > 1) {
            log.warn("Found more than one matching dependency for identifier " + artifactIdentifier + ":");
            for (Artifact resultArtifact : results) {
                log.warn(" --> " + resultArtifact.toString());
            }
            return null;
        } else {
            if (results.size() == 1) {
                return results.get(0);
            } else {
                log.warn("Couldn't find project dependency for identifier " + artifactIdentifier + "!");
                return null;
            }
        }
    }

    private static boolean artifactMatches(Artifact artifact, String artifactIdentifier) {
        String[] artifactIdentifierParts = artifactIdentifier.split(":");
        String artifactGroupId = null;
        String artifactId = null;
        String artifactType = null;
        String artifactClassifier = null;
        String artifactVersion = null;
        artifactGroupId = artifactIdentifierParts[0];
        artifactId = artifactIdentifierParts[1];
        if (artifactIdentifierParts.length >= 5) {
            artifactType = artifactIdentifierParts[2];
            artifactClassifier = artifactIdentifierParts[3];
            artifactVersion = artifactIdentifierParts[4];
        } else {
            if (artifactIdentifierParts.length > 2) {
                artifactType = artifactIdentifierParts[2];
            }
            if (artifactIdentifierParts.length > 3) {
                artifactVersion = artifactIdentifierParts[3];
            }
        }
        if (!artifact.getGroupId().equals(artifactGroupId)) {
            return false;
        }
        if (!artifact.getArtifactId().equals(artifactId)) {
            return false;
        }
        if (artifactType != null) {
            if (!artifact.getType().equals(artifactType)) {
                System.out.print(artifact.toString() + " == " + artifactIdentifier + " ? ");
                System.out.println("Type didn't match : " + artifact.getType() + " != " + artifactType);
                return false;
            }
        }
        if (artifactClassifier != null) {
            if (!artifactClassifier.equals(artifact.getClassifier())) {
                System.out.print(artifact.toString() + " == " + artifactIdentifier + " ? ");
                System.out.println(
                        "Classifier didn't match : " + artifact.getClassifier() + " != " + artifactClassifier);
                return false;
            }

        }
        if (artifactVersion != null) {
            if (!artifact.getBaseVersion().equals(artifactVersion)) {
                System.out.print(artifact.toString() + " == " + artifactIdentifier + " ? ");
                System.out.println("Version didn't match : " + artifact.getVersion() + " != " + artifactVersion);
                return false;
            }
        }
        return true;
    }

    private static String getPaddingString(int i) {
        StringBuilder builder = new StringBuilder();
        for (int j = 0; j < i; j++) {
            builder.append("  ");
        }
        return builder.toString();
    }

    private String getTrail(Artifact artifact) {
        StringBuilder builder = new StringBuilder();
        int i = 0;
        for (String trailEntry : artifact.getDependencyTrail()) {
            builder.append(trailEntry);
            if (i < artifact.getDependencyTrail().size() - 1) {
                builder.append(" -> ");
            }
            i++;
        }
        builder.append(" (" + artifact.getFile() + ") ");
        return builder.toString();
    }

}