org.codehaus.mojo.javancss.NcssReportMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.codehaus.mojo.javancss.NcssReportMojo.java

Source

package org.codehaus.mojo.javancss;

/*
 * 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.
 */

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;

import org.apache.maven.model.ReportPlugin;
import org.apache.maven.project.MavenProject;
import org.apache.maven.reporting.AbstractMavenReport;
import org.apache.maven.reporting.MavenReportException;
import org.codehaus.doxia.site.renderer.SiteRenderer;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.PathTool;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;

/**
 * Generates a JavaNCSS report based on this module's source code.
 *
 * @goal report
 * @author <a href="jeanlaurentATgmail.com">Jean-Laurent de Morlhon</a>
 * @version $Id$
 */
public class NcssReportMojo extends AbstractMavenReport {
    private static final String OUTPUT_NAME = "javancss";

    /**
     * Specifies the directory where the HTML report will be generated.
     *
     * @parameter expression="${project.reporting.outputDirectory}"
     * @required
     * @readonly
     */
    private File outputDirectory;

    /**
     * Specifies the directory where the XML report will be generated.
     *
     * @parameter default-value="${project.build.directory}"
     * @required
     */
    private File xmlOutputDirectory;

    /**
     * Specifies the location of the source files to be used.
     *
     * @parameter expression="${project.build.sourceDirectory}"
     * @required
     * @readonly
     */
    private File sourceDirectory;

    /**
     * Specifies the encoding of the source files.
     *
     * @parameter expression="${encoding}" default-value="${project.build.sourceEncoding}"
     */
    private String sourceEncoding;

    /**
     * Specifies the maximum number of lines to take into account into the reports.
     *
     * @parameter default-value="30"
     * @required
     */
    private int lineThreshold;

    /**
     * Specified the name of the temporary file generated by JavaNCSS prior report generation.
     *
     * @parameter default-value="javancss-raw-report.xml"
     * @required
     */
    private String tempFileName;

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

    /**
     * @component role="org.codehaus.doxia.site.renderer.SiteRenderer"
     * @required
     * @readonly
     */
    private SiteRenderer siteRenderer;

    /**
     * The projects in the reactor for aggregation report.
     *
     * @parameter expression="${reactorProjects}"
     * @readonly
     */
    private List reactorProjects;

    /**
     * Link the violation line numbers to the source xref. Defaults to true and will link automatically if jxr plugin is
     * being used.
     *
     * @parameter expression="${linkXRef}" default-value="true"
     */
    private boolean linkXRef;

    /**
     * Location of the Xrefs to link to.
     *
     * @parameter default-value="${project.build.directory}/site/xref"
     */
    private File xrefLocation;

    /**
     * List of ant-style patterns used to specify the java sources that should be included when running JavaNCSS. If
     * this is not specified, all .java files in the project source directories are included.
     *
     * @parameter
     */
    private String[] includes;

    /**
     * List of ant-style patterns used to specify the java sources that should be excluded when running JavaNCSS. If
     * this is not specified, no files in the project source directories are excluded.
     *
     * @parameter
     */
    private String[] excludes;

    /**
     * Gets the source files encoding.
     *
     * @return The source file encoding.
     */
    protected String getSourceEncoding() {
        return sourceEncoding;
    }

    /**
     * @see org.apache.maven.reporting.MavenReport#executeReport(java.util.Locale)
     */
    public void executeReport(Locale locale) throws MavenReportException {
        if (!canGenerateReport()) {
            return;
        }

        if (canGenerateSingleReport()) {
            generateSingleReport(locale);
        }
        if (canGenerateAggregateReport()) {
            generateAggregateReport(locale);
        }
    }

    private void generateAggregateReport(Locale locale) throws MavenReportException {
        // All this work just to get "target" so that we can scan the filesystem for
        // child javancss xml files...
        String basedir = project.getBasedir().toString();
        String output = xmlOutputDirectory.toString();
        if (getLog().isDebugEnabled()) {
            getLog().debug("basedir: " + basedir);
            getLog().debug("output: " + output);
        }
        String relative = null;
        if (output.startsWith(basedir)) {
            relative = output.substring(basedir.length() + 1);
        } else {
            getLog().error("Unable to aggregate report because I can't "
                    + "determine the relative location of the XML report");
            return;
        }
        getLog().debug("relative: " + relative);
        List reports = new ArrayList();
        for (Iterator it = reactorProjects.iterator(); it.hasNext();) {
            MavenProject child = (MavenProject) it.next();
            File xmlReport = new File(child.getBasedir() + File.separator + relative, tempFileName);
            if (xmlReport.exists()) {
                reports.add(new ModuleReport(child, loadDocument(xmlReport)));
            } else {
                getLog().debug("xml file not found: " + xmlReport);
            }
        }
        getLog().debug("Aggregating " + reports.size() + " JavaNCSS reports");

        // parse the freshly generated file and write the report
        NcssAggregateReportGenerator reportGenerator = new NcssAggregateReportGenerator(getSink(),
                getBundle(locale), getLog());
        reportGenerator.doReport(locale, reports, lineThreshold);
    }

    private boolean isIncludeExcludeUsed() {
        return ((excludes != null) || (includes != null));
    }

    private void generateSingleReport(Locale locale) throws MavenReportException {
        if (getLog().isDebugEnabled()) {
            getLog().debug("Calling NCSSExecuter with src    : " + sourceDirectory);
            getLog().debug("Calling NCSSExecuter with output : " + buildOutputFileName());
            getLog().debug("Calling NCSSExecuter with includes : " + includes);
            getLog().debug("Calling NCSSExecuter with excludes : " + excludes);
            getLog().debug("Calling NCSSExecuter with encoding : " + getSourceEncoding());
        }
        // run javaNCss and produce an temp xml file
        NcssExecuter ncssExecuter;
        if (isIncludeExcludeUsed()) {
            ncssExecuter = new NcssExecuter(scanForSources(), buildOutputFileName());
        } else {
            ncssExecuter = new NcssExecuter(sourceDirectory, buildOutputFileName());
        }
        ncssExecuter.setEncoding(getSourceEncoding()); // in case of null value, JavaNCSS uses platform encoding, as
        // expected

        ncssExecuter.execute();
        if (!isTempReportGenerated()) {
            throw new MavenReportException("Can't process temp ncss xml file.");
        }
        // parse the freshly generated file and write the report
        NcssReportGenerator reportGenerator = new NcssReportGenerator(getSink(), getBundle(locale), getLog(),
                constructXRefLocation());
        reportGenerator.doReport(loadDocument(), lineThreshold);
    }

    /**
     * Load the xml file generated by javancss.
     */
    private Document loadDocument(File file) throws MavenReportException {
        try {
            SAXReader saxReader = new SAXReader();
            return saxReader.read(ReaderFactory.newXmlReader(file));
        } catch (DocumentException de) {
            throw new MavenReportException(de.getMessage(), de);
        } catch (IOException ioe) {
            throw new MavenReportException(ioe.getMessage(), ioe);
        }
    }

    private Document loadDocument() throws MavenReportException {
        return loadDocument(new File(buildOutputFileName()));
    }

    /**
     * Check that the expected temporary file generated by JavaNCSS exists.
     *
     * @return <code>true</code> if the temporary report exists, <code>false</code> otherwise.
     */
    private boolean isTempReportGenerated() {
        return new File(buildOutputFileName()).exists();
    }

    /**
     * @see org.apache.maven.reporting.MavenReport#canGenerateReport()
     */
    public boolean canGenerateReport() {
        return (canGenerateSingleReport() || canGenerateAggregateReport());
    }

    private boolean canGenerateAggregateReport() {
        if (project.getModules().size() == 0) {
            // no child modules
            return false;
        }
        if (sourceDirectory != null && sourceDirectory.exists()) {
            // only non-source projects can aggregate
            String[] sources = scanForSources();
            return !((sources != null) && (sources.length > 0));
        }
        return true;
    }

    private boolean canGenerateSingleReport() {
        if (sourceDirectory == null || !sourceDirectory.exists()) {
            return false;
        }
        // now that we know we have a valid existing source directory
        // we check if any *.java files are existing.
        String[] sources = scanForSources();
        return (sources != null) && (sources.length > 0);
    }

    /**
     * gets a list of all files in the source directory.
     *
     * @return the list of all files in the source directory;
     */
    private String[] scanForSources() {
        String[] defaultIncludes = { "**\\*.java" };
        DirectoryScanner ds = new DirectoryScanner();
        if (includes == null) {
            ds.setIncludes(defaultIncludes);
        } else {
            ds.setIncludes(includes);
        }
        if (excludes != null) {
            ds.setExcludes(excludes);
        }
        ds.setBasedir(sourceDirectory);
        getLog().debug("Scanning base directory " + sourceDirectory);
        ds.scan();
        int maxFiles = ds.getIncludedFiles().length;
        String[] result = new String[maxFiles];
        for (int i = 0; i < maxFiles; i++) {
            result[i] = sourceDirectory + File.separator + ds.getIncludedFiles()[i];
        }
        return result;
    }

    /**
     * Build a path for the output filename.
     *
     * @return A String representation of the output filename.
     */
    /* package */String buildOutputFileName() {
        return getXmlOutputDirectory() + File.separator + tempFileName;
    }

    /**
     * @see org.apache.maven.reporting.MavenReport#getName(java.util.Locale)
     */
    public String getName(Locale locale) {
        return getBundle(locale).getString("report.javancss.name");
    }

    /**
     * @see org.apache.maven.reporting.MavenReport#getDescription(java.util.Locale)
     */
    public String getDescription(Locale locale) {
        return getBundle(locale).getString("report.javancss.description");
    }

    /**
     * @see org.apache.maven.reporting.AbstractMavenReport#getOutputDirectory()
     */
    protected String getOutputDirectory() {
        return outputDirectory.getAbsolutePath();
    }

    protected String getXmlOutputDirectory() {
        return xmlOutputDirectory.getAbsolutePath();
    }

    /**
     * @see org.apache.maven.reporting.AbstractMavenReport#getProject()
     */
    protected MavenProject getProject() {
        return project;
    }

    /**
     * @see org.apache.maven.reporting.AbstractMavenReport#getSiteRenderer()
     */
    protected SiteRenderer getSiteRenderer() {
        return siteRenderer;
    }

    /**
     * @see org.apache.maven.reporting.MavenReport#getOutputName()
     */
    public String getOutputName() {
        return OUTPUT_NAME;
    }

    /**
     * Getter for the source directory
     *
     * @return the source directory as a File object.
     */
    protected File getSourceDirectory() {
        return sourceDirectory;
    }

    // helper to retrieve the right bundle
    private static ResourceBundle getBundle(Locale locale) {
        return ResourceBundle.getBundle("javancss-report", locale, NcssReportMojo.class.getClassLoader());
    }

    // blatantly copied from maven pmd plugin
    protected String constructXRefLocation() {
        String location = null;
        if (linkXRef) {
            String relativePath = PathTool.getRelativePath(outputDirectory.getAbsolutePath(),
                    xrefLocation.getAbsolutePath());
            if (StringUtils.isEmpty(relativePath)) {
                relativePath = ".";
            }
            relativePath = relativePath + "/" + xrefLocation.getName();
            if (xrefLocation.exists()) {
                // XRef was already generated by manual execution of a lifecycle binding
                location = relativePath;
            } else {
                // Not yet generated - check if the report is on its way
                for (Iterator reports = project.getReportPlugins().iterator(); reports.hasNext();) {
                    ReportPlugin plugin = (ReportPlugin) reports.next();

                    String artifactId = plugin.getArtifactId();
                    if ("maven-jxr-plugin".equals(artifactId) || "jxr-maven-plugin".equals(artifactId)) {
                        location = relativePath;
                    }
                }
            }

            if (location == null) {
                getLog().warn("Unable to locate Source XRef to link to - DISABLED");
            }
        }
        return location;
    }
}