All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.plugins.pmd.util.ModuleDetector Maven / Gradle / Ivy

Go to download

This plug-in generates the trend report for PMD, an open source static code analysis program.

There is a newer version: 3.12
Show newest version
package hudson.plugins.pmd.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.digester.Digester;
import org.apache.commons.lang.StringUtils;
import org.xml.sax.SAXException;

/**
 * Detects module names by parsing the name of a source file, the Maven pom.xml file or the ANT build.xml file.
 *
 * @author Ulli Hafner
 */
public class ModuleDetector {
    /** Filename of Maven pom. */
    protected static final String MAVEN_POM = "pom.xml";
    /** Filename of Ant project file. */
    protected static final String ANT_PROJECT = "build.xml";
    /** Prefix of a maven target folder. */
    private static final String TARGET = "/target";
    /** The factory to create input streams with. */
    private FileInputStreamFactory factory = new DefaultFileInputStreamFactory();
    /** Maps file names to module names. */
    private final Map fileNameToModuleName;
    /** Sorted list of file name prefixes. */
    private final List prefixes;

    /**
     * Creates a new instance of {@link ModuleDetector}.
     */
    public ModuleDetector() {
        fileNameToModuleName = new HashMap();
        prefixes = new ArrayList();
    }

    /**
     * Creates a new instance of {@link ModuleDetector}.
     *
     * @param workspace
     *            the workspace to scan for maven pom.xml or ant build.xml files
     */
    public ModuleDetector(final File workspace) {
        this(workspace, new DefaultFileInputStreamFactory());
    }

    /**
     * Creates a new instance of {@link ModuleDetector}.
     *
     * @param workspace
     *            the workspace to scan for maven pom.xml or ant build.xml files
     * @param fileInputStreamFactory the value to set
     */
    public ModuleDetector(final File workspace, final FileInputStreamFactory fileInputStreamFactory) {
        setFileInputStreamFactory(fileInputStreamFactory);
        fileNameToModuleName = createFilesToModuleMapping(workspace);
        prefixes = new ArrayList(fileNameToModuleName.keySet());
        Collections.sort(prefixes);
    }

    /**
     * Sets the factory to the specified value.
     *
     * @param fileInputStreamFactory the value to set
     */
    public void setFileInputStreamFactory(final FileInputStreamFactory fileInputStreamFactory) {
        factory = fileInputStreamFactory;
    }

    /**
     * Returns a mapping of path prefixes to module names.
     *
     * @param workspace
     *            the workspace to start scanning for files
     * @return the mapping of path prefixes to module names
     */
    private Map createFilesToModuleMapping(final File workspace) {
        String[] projects = findMavenModules(workspace);
        Map mapping = new HashMap();
        if (projects.length > 0) {
            for (int i = 0; i < projects.length; i++) {
                String fileName = projects[i];
                String moduleName = parsePom(fileName);
                if (StringUtils.isNotBlank(moduleName)) {
                    mapping.put(StringUtils.substringBeforeLast(fileName, MAVEN_POM), moduleName);
                }
            }
        }
        if (mapping.isEmpty()) {
            projects = findAntProjects(workspace);
            for (int i = 0; i < projects.length; i++) {
                String fileName = projects[i];
                String moduleName = parseBuildXml(fileName);
                if (StringUtils.isNotBlank(moduleName)) {
                    mapping.put(StringUtils.substringBeforeLast(fileName, ANT_PROJECT), moduleName);
                }
            }
        }

        return mapping;
    }

    /**
     * Uses the path prefixes of pom.xml or build.xml files to guess a module
     * name for the specified file.
     *
     * @param originalFileName
     *            file name to guess a module for
     * @return a module name or an empty string
     */
    public String guessModuleName(final String originalFileName) {
        String fullPath = originalFileName.replace('\\', '/');

        String guessedModule = StringUtils.EMPTY;
        for (String path : prefixes) {
            if (fullPath.startsWith(path)) {
                guessedModule = fileNameToModuleName.get(path);
            }
        }
        return guessedModule;
    }

    /**
     * Returns the maven modules in the workspace.
     *
     * @param workspace the workspace
     * @return the maven modules in the workspace
     */
    private String[] findMavenModules(final File workspace) {
        return find(workspace, "**/" + MAVEN_POM);
    }

    /**
     * Returns the Ant projects in the workspace.
     *
     * @param workspace the workspace
     * @return the Ant projects in the workspace
     */
    private String[] findAntProjects(final File workspace) {
        return find(workspace, "**/" + ANT_PROJECT);
    }

    /**
     * Finds files of the matching pattern.
     *
     * @param path root path to scan in
     * @param pattern pattern of files
     * @return the found files
     */
    protected String[] find(final File path, final String pattern) {
        String[] relativeFileNames = new FileFinder(pattern).find(path);
        String[] absoluteFileNames = new String[relativeFileNames.length];

        String absolutePath = path.getAbsolutePath();
        for (int file = 0; file < absoluteFileNames.length; file++) {
            absoluteFileNames[file] = (absolutePath + "/" + relativeFileNames[file]).replace("\\", "/");
        }
        return absoluteFileNames;
    }

    /**
     * Guesses a module name based on the source folder or the content in the pom.xml or build.xml files.
     *
     * @param fileName
     *            the absolute path of the file (UNIX style) to guess the module
     *            for
     * @param isMavenBuild
     *            determines whether this build uses maven
     * @param isAntBuild
     *            determines whether this build uses maven
     * @return the guessed module name or an empty string if the name could not be
     *         resolved
     */
    public String guessModuleName(final String fileName, final boolean isMavenBuild, final boolean isAntBuild) {
        String unixName = fileName.replace("\\", "/");

        if (isMavenBuild) {
            String projectName = parsePom(unixName);
            if (StringUtils.isNotBlank(projectName)) {
                return projectName;
            }
        }
        String path = StringUtils.substringBeforeLast(unixName, "/");

        if (isAntBuild) {
            String projectName = parseBuildXml(path);
            if (StringUtils.isNotBlank(projectName)) {
                return projectName;
            }
        }

        if (path.contains("/")) {
            return StringUtils.substringAfterLast(path, "/");
        }
        else {
            return path;
        }
    }

    /**
     * Returns the project name stored in the build.xml.
     *
     * @param path
     *            root folder
     * @return the project name or an empty string if the name could not be
     *         resolved
     */
    private String parseBuildXml(final String path) {
        try {
            String fileName;
            if (StringUtils.isBlank(path)) {
                fileName = ANT_PROJECT;
            }
            else {
                fileName = path + "/build.xml";
            }
            InputStream pom = factory.create(fileName);

            Digester digester = new Digester();
            digester.setValidating(false);
            digester.setClassLoader(ModuleDetector.class.getClassLoader());

            digester.push(new StringBuffer());
            String xPath = "project";
            digester.addCallMethod(xPath, "append", 1);
            digester.addCallParam(xPath, 0, "name");

            StringBuffer result = (StringBuffer)digester.parse(pom);
            return result.toString();
        }
        catch (IOException exception) {
            // ignore
        }
        catch (SAXException exception) {
            // ignore
        }
        return StringUtils.EMPTY;
    }

    /**
     * Returns the project name stored in the POM.
     *
     * @param fileName
     *            maven module root folder
     * @return the project name or an empty string if the name could not be
     *         resolved
     */
    private String parsePom(final String fileName) {
        try {
            InputStream pom = null;
            if (fileName.endsWith(MAVEN_POM)) {
                pom = factory.create(fileName);
            }
            else if (fileName.contains(TARGET)) {
                String module = StringUtils.substringBeforeLast(fileName, TARGET);
                pom = factory.create(module + "/pom.xml");
            }
            if (pom != null) {
                Digester digester = new Digester();
                digester.setValidating(false);
                digester.setClassLoader(ModuleDetector.class.getClassLoader());

                digester.push(new StringBuffer());
                digester.addCallMethod("project/name", "append", 0);

                StringBuffer result = (StringBuffer)digester.parse(pom);
                return result.toString();
            }
        }
        catch (IOException exception) {
            // ignore
        }
        catch (SAXException exception) {
            // ignore
        }
        return StringUtils.EMPTY;
    }

    /**
     * A input stream factory based on a {@link FileInputStream}.
     */
    private static final class DefaultFileInputStreamFactory implements FileInputStreamFactory {
        /** {@inheritDoc} */
        public InputStream create(final String fileName) throws FileNotFoundException {
            return new FileInputStream(new File(fileName));
        }
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy