Coverage Report - org.apache.maven.plugin.checkstyle.CheckstyleReport
 
Classes in this File Line Coverage Branch Coverage Complexity
CheckstyleReport
74%
193/258
53%
84/156
5.913
 
 1  
 package org.apache.maven.plugin.checkstyle;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.ByteArrayInputStream;
 23  
 import java.io.ByteArrayOutputStream;
 24  
 import java.io.File;
 25  
 import java.io.FileInputStream;
 26  
 import java.io.FileNotFoundException;
 27  
 import java.io.FileOutputStream;
 28  
 import java.io.IOException;
 29  
 import java.io.OutputStream;
 30  
 import java.net.MalformedURLException;
 31  
 import java.net.URL;
 32  
 import java.net.URLClassLoader;
 33  
 import java.util.ArrayList;
 34  
 import java.util.Calendar;
 35  
 import java.util.Collections;
 36  
 import java.util.HashMap;
 37  
 import java.util.Iterator;
 38  
 import java.util.List;
 39  
 import java.util.Locale;
 40  
 import java.util.Map;
 41  
 import java.util.Properties;
 42  
 import java.util.ResourceBundle;
 43  
 
 44  
 import org.apache.maven.artifact.DependencyResolutionRequiredException;
 45  
 import org.apache.maven.doxia.siterenderer.Renderer;
 46  
 import org.apache.maven.doxia.tools.SiteTool;
 47  
 import org.apache.maven.model.ReportPlugin;
 48  
 import org.apache.maven.plugin.checkstyle.rss.CheckstyleRssGenerator;
 49  
 import org.apache.maven.plugin.checkstyle.rss.CheckstyleRssGeneratorRequest;
 50  
 import org.apache.maven.project.MavenProject;
 51  
 import org.apache.maven.reporting.AbstractMavenReport;
 52  
 import org.apache.maven.reporting.MavenReportException;
 53  
 import org.codehaus.plexus.resource.ResourceManager;
 54  
 import org.codehaus.plexus.resource.loader.FileResourceCreationException;
 55  
 import org.codehaus.plexus.resource.loader.FileResourceLoader;
 56  
 import org.codehaus.plexus.util.FileUtils;
 57  
 import org.codehaus.plexus.util.PathTool;
 58  
 import org.codehaus.plexus.util.StringUtils;
 59  
 
 60  
 import com.puppycrawl.tools.checkstyle.Checker;
 61  
 import com.puppycrawl.tools.checkstyle.ConfigurationLoader;
 62  
 import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
 63  
 import com.puppycrawl.tools.checkstyle.DefaultLogger;
 64  
 import com.puppycrawl.tools.checkstyle.PackageNamesLoader;
 65  
 import com.puppycrawl.tools.checkstyle.PropertiesExpander;
 66  
 import com.puppycrawl.tools.checkstyle.XMLLogger;
 67  
 import com.puppycrawl.tools.checkstyle.api.AuditListener;
 68  
 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
 69  
 import com.puppycrawl.tools.checkstyle.api.Configuration;
 70  
 import com.puppycrawl.tools.checkstyle.api.FilterSet;
 71  
 import com.puppycrawl.tools.checkstyle.filters.SuppressionsLoader;
 72  
 
 73  
 /**
 74  
  * Perform a Checkstyle analysis, and generate a report on violations.
 75  
  *
 76  
  * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
 77  
  * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
 78  
  * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
 79  
  * @version $Id$
 80  
  * @goal checkstyle
 81  
  * @requiresDependencyResolution compile
 82  
  */
 83  10
 public class CheckstyleReport
 84  
     extends AbstractMavenReport
 85  
 {
 86  
     public static final String PLUGIN_RESOURCES = "org/apache/maven/plugin/checkstyle";
 87  
 
 88  
     /**
 89  
      * @deprecated Remove with format parameter.
 90  
      */
 91  
     private static final Map FORMAT_TO_CONFIG_LOCATION;
 92  
 
 93  
     static
 94  
     {
 95  1
         Map fmt2Cfg = new HashMap();
 96  
 
 97  1
         fmt2Cfg.put( "sun", "config/sun_checks.xml" );
 98  1
         fmt2Cfg.put( "turbine", "config/turbine_checks.xml" );
 99  1
         fmt2Cfg.put( "avalon", "config/avalon_checks.xml" );
 100  1
         fmt2Cfg.put( "maven", "config/maven_checks.xml" );
 101  
 
 102  1
         FORMAT_TO_CONFIG_LOCATION = Collections.unmodifiableMap( fmt2Cfg );
 103  
     }
 104  
 
 105  
     /**
 106  
      * Skip entire check.
 107  
      *
 108  
      * @parameter expression="${checkstyle.skip}" default-value="false"
 109  
      * @since 2.2
 110  
      */
 111  
     private boolean skip;
 112  
 
 113  
     /**
 114  
      * The output directory for the report. Note that this parameter is only
 115  
      * evaluated if the goal is run directly from the command line. If the goal
 116  
      * is run indirectly as part of a site generation, the output directory
 117  
      * configured in Maven Site Plugin is used instead.
 118  
      *
 119  
      * @parameter default-value="${project.reporting.outputDirectory}"
 120  
      * @required
 121  
      */
 122  
     private File outputDirectory;
 123  
 
 124  
     /**
 125  
      * Specifies if the Rules summary should be enabled or not.
 126  
      *
 127  
      * @parameter expression="${checkstyle.enable.rules.summary}"
 128  
      *            default-value="true"
 129  
      */
 130  
     private boolean enableRulesSummary;
 131  
 
 132  
     /**
 133  
      * Specifies if the Severity summary should be enabled or not.
 134  
      *
 135  
      * @parameter expression="${checkstyle.enable.severity.summary}"
 136  
      *            default-value="true"
 137  
      */
 138  
     private boolean enableSeveritySummary;
 139  
 
 140  
     /**
 141  
      * Specifies if the Files summary should be enabled or not.
 142  
      *
 143  
      * @parameter expression="${checkstyle.enable.files.summary}"
 144  
      *            default-value="true"
 145  
      */
 146  
     private boolean enableFilesSummary;
 147  
 
 148  
     /**
 149  
      * Specifies if the RSS should be enabled or not.
 150  
      *
 151  
      * @parameter expression="${checkstyle.enable.rss}" default-value="true"
 152  
      */
 153  
     private boolean enableRSS;
 154  
 
 155  
     /**
 156  
      * Specifies the names filter of the source files to be used for Checkstyle.
 157  
      *
 158  
      * @parameter expression="${checkstyle.includes}" default-value="**\/*.java"
 159  
      * @required
 160  
      */
 161  
     private String includes;
 162  
 
 163  
     /**
 164  
      * Specifies the names filter of the source files to be excluded for
 165  
      * Checkstyle.
 166  
      *
 167  
      * @parameter expression="${checkstyle.excludes}"
 168  
      */
 169  
     private String excludes;
 170  
 
 171  
     /**
 172  
      * <p>
 173  
      * Specifies the location of the XML configuration to use.
 174  
      * </p>
 175  
      *
 176  
      * <p>
 177  
      * Potential values are a filesystem path, a URL, or a classpath resource.
 178  
      * This parameter expects that the contents of the location conform to the
 179  
      * xml format (Checkstyle <a
 180  
      * href="http://checkstyle.sourceforge.net/config.html#Modules">Checker
 181  
      * module</a>) configuration of rulesets.
 182  
      * </p>
 183  
      *
 184  
      * <p>
 185  
      * This parameter is resolved as resource, URL, then file. If successfully
 186  
      * resolved, the contents of the configuration is copied into the
 187  
      * <code>${project.build.directory}/checkstyle-configuration.xml</code>
 188  
      * file before being passed to Checkstyle as a configuration.
 189  
      * </p>
 190  
      *
 191  
      * <p>
 192  
      * There are 4 predefined rulesets.
 193  
      * </p>
 194  
      *
 195  
      * <ul>
 196  
      * <li><code>config/sun_checks.xml</code>: Sun Checks.</li>
 197  
      * <li><code>config/turbine_checks.xml</code>: Turbine Checks.</li>
 198  
      * <li><code>config/avalon_checks.xml</code>: Avalon Checks.</li>
 199  
      * <li><code>config/maven_checks.xml</code>: Maven Source Checks.</li>
 200  
      * </ul>
 201  
      *
 202  
      * @parameter expression="${checkstyle.config.location}"
 203  
      *            default-value="config/sun_checks.xml"
 204  
      */
 205  
     private String configLocation;
 206  
 
 207  
     /**
 208  
      * Specifies what predefined check set to use. Available sets are "sun" (for
 209  
      * the Sun coding conventions), "turbine", and "avalon".
 210  
      *
 211  
      * @parameter default-value="sun"
 212  
      * @deprecated Use configLocation instead.
 213  
      */
 214  
     private String format;
 215  
 
 216  
     /**
 217  
      * <p>
 218  
      * Specifies the location of the properties file.
 219  
      * </p>
 220  
      *
 221  
      * <p>
 222  
      * This parameter is resolved as URL, File then resource. If successfully
 223  
      * resolved, the contents of the properties location is copied into the
 224  
      * <code>${project.build.directory}/checkstyle-checker.properties</code>
 225  
      * file before being passed to Checkstyle for loading.
 226  
      * </p>
 227  
      *
 228  
      * <p>
 229  
      * The contents of the <code>propertiesLocation</code> will be made
 230  
      * available to Checkstyle for specifying values for parameters within the
 231  
      * xml configuration (specified in the <code>configLocation</code>
 232  
      * parameter).
 233  
      * </p>
 234  
      *
 235  
      * @parameter expression="${checkstyle.properties.location}"
 236  
      * @since 2.0-beta-2
 237  
      */
 238  
     private String propertiesLocation;
 239  
 
 240  
     /**
 241  
      * Specifies the location of the Checkstyle properties file that will be used to
 242  
      * check the source.
 243  
      *
 244  
      * @parameter
 245  
      * @deprecated Use propertiesLocation instead.
 246  
      */
 247  
     private File propertiesFile;
 248  
 
 249  
     /**
 250  
      * Specifies the URL of the Checkstyle properties that will be used to check
 251  
      * the source.
 252  
      *
 253  
      * @parameter
 254  
      * @deprecated Use propertiesLocation instead.
 255  
      */
 256  
     private URL propertiesURL;
 257  
 
 258  
     /**
 259  
      * Allows for specifying raw property expansion information.
 260  
      *
 261  
      * @parameter
 262  
      */
 263  
     private String propertyExpansion;
 264  
 
 265  
     /**
 266  
      * <p>
 267  
      * Specifies the location of the License file (a.k.a. the header file) that
 268  
      * can be used by Checkstyle to verify that source code has the correct
 269  
      * license header.
 270  
      * </p>
 271  
      * <p>
 272  
      * You need to use ${checkstyle.header.file} in your Checkstyle xml
 273  
      * configuration to reference the name of this header file.
 274  
      * </p>
 275  
      * <p>
 276  
      * For instance:
 277  
      * </p>
 278  
      * <p>
 279  
      * <code>
 280  
      * &lt;module name="RegexpHeader">
 281  
      *   &lt;property name="headerFile" value="${checkstyle.header.file}"/>
 282  
      * &lt;/module>
 283  
      * </code>
 284  
      * </p>
 285  
      *
 286  
      * @parameter expression="${checkstyle.header.file}"
 287  
      *            default-value="LICENSE.txt"
 288  
      * @since 2.0-beta-2
 289  
      */
 290  
     private String headerLocation;
 291  
 
 292  
     /**
 293  
      * Specifies the location of the License file (a.k.a. the header file) that
 294  
      * is used by Checkstyle to verify that source code has the correct
 295  
      * license header.
 296  
      *
 297  
      * @parameter expression="${basedir}/LICENSE.txt"
 298  
      * @deprecated Use headerLocation instead.
 299  
      */
 300  
     private File headerFile;
 301  
 
 302  
     /**
 303  
      * Specifies the cache file used to speed up Checkstyle on successive runs.
 304  
      *
 305  
      * @parameter default-value="${project.build.directory}/checkstyle-cachefile"
 306  
      */
 307  
     private String cacheFile;
 308  
 
 309  
     /**
 310  
      * If <code>null</code>, the Checkstyle plugin will display violations on stdout.
 311  
      * Otherwise, a text file will be created with the violations.
 312  
      *
 313  
      * @parameter
 314  
      */
 315  
     private File useFile;
 316  
 
 317  
     /**
 318  
      * SiteTool.
 319  
      *
 320  
      * @since 2.2
 321  
      * @component role="org.apache.maven.doxia.tools.SiteTool"
 322  
      * @required
 323  
      * @readonly
 324  
      */
 325  
     protected SiteTool siteTool;
 326  
 
 327  
     /**
 328  
      * <p>
 329  
      * Specifies the location of the suppressions XML file to use.
 330  
      * </p>
 331  
      *
 332  
      * <p>
 333  
      * This parameter is resolved as resource, URL, then file. If successfully
 334  
      * resolved, the contents of the suppressions XML is copied into the
 335  
      * <code>${project.build.directory}/checkstyle-supressions.xml</code> file
 336  
      * before being passed to Checkstyle for loading.
 337  
      * </p>
 338  
      *
 339  
      * <p>
 340  
      * See <code>suppressionsFileExpression</code> for the property that will
 341  
      * be made available to your checkstyle configuration.
 342  
      * </p>
 343  
      *
 344  
      * @parameter expression="${checkstyle.suppressions.location}"
 345  
      * @since 2.0-beta-2
 346  
      */
 347  
     private String suppressionsLocation;
 348  
 
 349  
     /**
 350  
      * The key to be used in the properties for the suppressions file.
 351  
      *
 352  
      * @parameter expression="${checkstyle.suppression.expression}"
 353  
      *            default-value="checkstyle.suppressions.file"
 354  
      * @since 2.1
 355  
      */
 356  
     private String suppressionsFileExpression;
 357  
 
 358  
     /**
 359  
      * Specifies the location of the suppressions XML file to use. The plugin
 360  
      * defines a Checkstyle property named
 361  
      * <code>checkstyle.suppressions.file</code> with the value of this
 362  
      * property. This allows using the Checkstyle property in your own custom
 363  
      * checkstyle configuration file when specifying a suppressions file.
 364  
      *
 365  
      * @parameter
 366  
      * @deprecated Use suppressionsLocation instead.
 367  
      */
 368  
     private String suppressionsFile;
 369  
 
 370  
     /**
 371  
      * Specifies the path and filename to save the checkstyle output. The format
 372  
      * of the output file is determined by the <code>outputFileFormat</code>
 373  
      * parameter.
 374  
      *
 375  
      * @parameter expression="${checkstyle.output.file}"
 376  
      *            default-value="${project.build.directory}/checkstyle-result.xml"
 377  
      */
 378  
     private File outputFile;
 379  
 
 380  
     /**
 381  
      * Specifies the format of the output to be used when writing to the output
 382  
      * file. Valid values are "plain" and "xml".
 383  
      *
 384  
      * @parameter expression="${checkstyle.output.format}" default-value="xml"
 385  
      */
 386  
     private String outputFileFormat;
 387  
 
 388  
     /**
 389  
      * <p>
 390  
      * Specifies the location of the package names XML to be used to configure
 391  
      * the Checkstyle <a
 392  
      * href="http://checkstyle.sourceforge.net/config.html#Packages">Packages</a>.
 393  
      * </p>
 394  
      *
 395  
      * <p>
 396  
      * This parameter is resolved as resource, URL, then file. If resolved to a
 397  
      * resource, or a URL, the contents of the package names XML is copied into
 398  
      * the <code>${project.build.directory}/checkstyle-packagenames.xml</code>
 399  
      * file before being passed to Checkstyle for loading.
 400  
      * </p>
 401  
      *
 402  
      * @parameter
 403  
      * @since 2.0-beta-2
 404  
      */
 405  
     private String packageNamesLocation;
 406  
 
 407  
     /**
 408  
      * Specifies the location of the package names XML to be used to configure
 409  
      * Checkstyle.
 410  
      *
 411  
      * @parameter
 412  
      * @deprecated Use packageNamesLocation instead.
 413  
      */
 414  
     private String packageNamesFile;
 415  
 
 416  
     /**
 417  
      * Specifies if the build should fail upon a violation.
 418  
      *
 419  
      * @parameter default-value="false"
 420  
      */
 421  
     private boolean failsOnError;
 422  
 
 423  
     /**
 424  
      * Specifies the location of the source directory to be used for Checkstyle.
 425  
      *
 426  
      * @parameter default-value="${project.build.sourceDirectory}"
 427  
      * @required
 428  
      */
 429  
     private File sourceDirectory;
 430  
 
 431  
     /**
 432  
      * Specifies the location of the test source directory to be used for
 433  
      * Checkstyle.
 434  
      *
 435  
      * @parameter default-value="${project.build.testSourceDirectory}"
 436  
      * @since 2.2
 437  
      */
 438  
     private File testSourceDirectory;
 439  
 
 440  
     /**
 441  
      * Include or not the test source directory to be used for Checkstyle.
 442  
      *
 443  
      * @parameter default-value="${false}"
 444  
      * @since 2.2
 445  
      */
 446  
     private boolean includeTestSourceDirectory;
 447  
 
 448  
     /**
 449  
      * The Maven Project Object.
 450  
      *
 451  
      * @parameter default-value="${project}"
 452  
      * @required
 453  
      * @readonly
 454  
      */
 455  
     private MavenProject project;
 456  
 
 457  
     /**
 458  
      * Output errors to console.
 459  
      *
 460  
      * @parameter default-value="false"
 461  
      */
 462  
     private boolean consoleOutput;
 463  
 
 464  
     /**
 465  
      * Link the violation line numbers to the source xref. Will link
 466  
      * automatically if Maven JXR plugin is being used.
 467  
      *
 468  
      * @parameter expression="${linkXRef}" default-value="true"
 469  
      * @since 2.1
 470  
      */
 471  
     private boolean linkXRef;
 472  
 
 473  
     /**
 474  
      * Location of the Xrefs to link to.
 475  
      *
 476  
      * @parameter default-value="${project.reporting.outputDirectory}/xref"
 477  
      */
 478  
     private File xrefLocation;
 479  
 
 480  
     /**
 481  
      * The file encoding to use when reading the source files. If the property <code>project.build.sourceEncoding</code>
 482  
      * is not set, the platform default encoding is used. <strong>Note:</strong> This parameter always overrides the
 483  
      * property <code>charset</code> from Checkstyle's <code>TreeWalker</code> module.
 484  
      *
 485  
      * @parameter expression="${encoding}" default-value="${project.build.sourceEncoding}"
 486  
      * @since 2.2
 487  
      */
 488  
     private String encoding;
 489  
 
 490  
     /**
 491  
      * @component
 492  
      * @required
 493  
      * @readonly
 494  
      */
 495  
     private Renderer siteRenderer;
 496  
     
 497  1
     private static final File[] EMPTY_FILE_ARRAY = new File[0];
 498  
 
 499  
     private ByteArrayOutputStream stringOutputStream;
 500  
 
 501  
     /**
 502  
      * @component
 503  
      * @required
 504  
      * @readonly
 505  
      */
 506  
     private ResourceManager locator;
 507  
     
 508  
     /**
 509  
      * CheckstyleRssGenerator.
 510  
      *
 511  
      * @since 2.4
 512  
      * @component role="org.apache.maven.plugin.checkstyle.rss.CheckstyleRssGenerator" role-hint="default"
 513  
      * @required
 514  
      * @readonly
 515  
      */
 516  
     protected CheckstyleRssGenerator checkstyleRssGenerator;    
 517  
 
 518  
     /** {@inheritDoc} */
 519  
     public String getName( Locale locale )
 520  
     {
 521  2
         return getBundle( locale ).getString( "report.checkstyle.name" );
 522  
     }
 523  
 
 524  
     /** {@inheritDoc} */
 525  
     public String getDescription( Locale locale )
 526  
     {
 527  0
         return getBundle( locale ).getString( "report.checkstyle.description" );
 528  
     }
 529  
 
 530  
     /** {@inheritDoc} */
 531  
     protected String getOutputDirectory()
 532  
     {
 533  32
         return outputDirectory.getAbsolutePath();
 534  
     }
 535  
 
 536  
     /** {@inheritDoc} */
 537  
     protected MavenProject getProject()
 538  
     {
 539  6
         return project;
 540  
     }
 541  
 
 542  
     /** {@inheritDoc} */
 543  
     protected Renderer getSiteRenderer()
 544  
     {
 545  16
         return siteRenderer;
 546  
     }
 547  
 
 548  
     /** {@inheritDoc} */
 549  
     public void executeReport( Locale locale )
 550  
         throws MavenReportException
 551  
     {
 552  10
         if ( !skip )
 553  
         {
 554  10
             mergeDeprecatedInfo();
 555  
 
 556  10
             locator.addSearchPath( FileResourceLoader.ID, project.getFile().getParentFile().getAbsolutePath() );
 557  10
             locator.addSearchPath( "url", "" );
 558  
 
 559  10
             locator.setOutputDirectory( new File( project.getBuild().getDirectory() ) );
 560  
 
 561  10
             if ( !canGenerateReport() )
 562  
             {
 563  1
                 getLog().info( "Source directory does not exist - skipping report." );
 564  1
                 return;
 565  
             }
 566  
 
 567  
             // for when we start using maven-shared-io and
 568  
             // maven-shared-monitor...
 569  
             // locator = new Locator( new MojoLogMonitorAdaptor( getLog() ) );
 570  
 
 571  
             // locator = new Locator( getLog(), new File(
 572  
             // project.getBuild().getDirectory() ) );
 573  
 
 574  9
             ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
 575  
 
 576  
             try
 577  
             {
 578  
                 // checkstyle will always use the context classloader in order
 579  
                 // to load resources (dtds),
 580  
                 // so we have to fix it
 581  11
                 ClassLoader checkstyleClassLoader = PackageNamesLoader.class.getClassLoader();
 582  9
                 Thread.currentThread().setContextClassLoader( checkstyleClassLoader );
 583  
 
 584  
 
 585  9
                 String configFile = getConfigFile();
 586  9
                 Properties overridingProperties = getOverridingProperties();
 587  
                 Configuration config;
 588  
                 CheckstyleResults results;
 589  
 
 590  9
                 config = ConfigurationLoader.loadConfiguration( configFile,
 591  
                                                                 new PropertiesExpander( overridingProperties ) );
 592  9
                 String effectiveEncoding =
 593  
                     StringUtils.isNotEmpty( encoding ) ? encoding : System.getProperty( "file.encoding", "UTF-8" );
 594  9
                 if ( StringUtils.isEmpty( encoding ) )
 595  
                 {
 596  0
                     getLog().warn(
 597  
                                    "File encoding has not been set, using platform encoding " + effectiveEncoding
 598  
                                        + ", i.e. build is platform dependent!" );
 599  
                 }
 600  9
                 Configuration[] modules = config.getChildren();
 601  69
                 for ( int i = 0; i < modules.length; i++ )
 602  
                 {
 603  60
                     Configuration module = modules[i];
 604  60
                     if ( "Checker".equals( module.getName() )
 605  
                         || "com.puppycrawl.tools.checkstyle.Checker".equals( module.getName() ) )
 606  
                     {
 607  0
                         if ( module instanceof DefaultConfiguration )
 608  
                         {
 609  0
                             ( (DefaultConfiguration) module ).addAttribute( "charset", effectiveEncoding );
 610  
                         }
 611  
                         else
 612  
                         {
 613  0
                             getLog().warn( "Failed to configure file encoding on module " + module );
 614  
                         }
 615  
                     }
 616  60
                     if ("TreeWalker".equals(module.getName())
 617  
                         || "com.puppycrawl.tools.checkstyle.TreeWalker".equals(module.getName()))
 618  
                     {
 619  9
                         if (module instanceof DefaultConfiguration)
 620  
                         {
 621  9
                             ((DefaultConfiguration) module).addAttribute("cacheFile", cacheFile);
 622  
                         }
 623  
                         else
 624  
                         {
 625  0
                             getLog().warn("Failed to configure cache file on module " + module);
 626  
                         }
 627  
                     }
 628  
                 }
 629  
 
 630  9
                 results = executeCheckstyle( config );
 631  
 
 632  7
                 ResourceBundle bundle = getBundle( locale );
 633  7
                 generateReportStatics();
 634  7
                 generateMainReport( results, config, bundle );
 635  7
                 if ( enableRSS )
 636  
                 {
 637  7
                     CheckstyleRssGeneratorRequest request =
 638  
                         new CheckstyleRssGeneratorRequest( this.project, this.getCopyright(), outputDirectory, getLog() );
 639  7
                     checkstyleRssGenerator.generateRSS( results, request );
 640  
                 }
 641  
 
 642  
             }
 643  0
             catch ( CheckstyleException e )
 644  
             {
 645  0
                 throw new MavenReportException( "Failed during checkstyle configuration", e );
 646  
             }
 647  
             finally
 648  
             {
 649  
                 //be sure to restore original context classloader
 650  9
                 Thread.currentThread().setContextClassLoader( currentClassLoader );
 651  7
             }
 652  
         }
 653  7
     }
 654  
 
 655  
     private void generateReportStatics()
 656  
         throws MavenReportException
 657  
     {
 658  7
         ReportResource rresource = new ReportResource( PLUGIN_RESOURCES, outputDirectory );
 659  
         try
 660  
         {
 661  7
             rresource.copy( "images/rss.png" );
 662  
         }
 663  0
         catch ( IOException e )
 664  
         {
 665  0
             throw new MavenReportException( "Unable to copy static resources.", e );
 666  7
         }
 667  7
     }
 668  
 
 669  
     
 670  
     private String getCopyright()
 671  
     {
 672  
         String copyright;
 673  7
         int currentYear = Calendar.getInstance().get( Calendar.YEAR );
 674  7
         if ( StringUtils.isNotEmpty( project.getInceptionYear() )
 675  
             && !String.valueOf( currentYear ).equals( project.getInceptionYear() ) )
 676  
         {
 677  7
             copyright = project.getInceptionYear() + " - " + currentYear;
 678  
         }
 679  
         else
 680  
         {
 681  0
             copyright = String.valueOf( currentYear );
 682  
         }
 683  
 
 684  7
         if ( ( project.getOrganization() != null ) && StringUtils.isNotEmpty( project.getOrganization().getName() ) )
 685  
         {
 686  7
             copyright = copyright + " " + project.getOrganization().getName();
 687  
         }
 688  7
         return copyright;
 689  
     }
 690  
 
 691  
     private void generateMainReport( CheckstyleResults results, Configuration config, ResourceBundle bundle )
 692  
     {
 693  7
         CheckstyleReportGenerator generator = new CheckstyleReportGenerator( getSink(), bundle, project.getBasedir(), siteTool );
 694  
 
 695  7
         generator.setLog( getLog() );
 696  7
         generator.setEnableRulesSummary( enableRulesSummary );
 697  7
         generator.setEnableSeveritySummary( enableSeveritySummary );
 698  7
         generator.setEnableFilesSummary( enableFilesSummary );
 699  7
         generator.setEnableRSS( enableRSS );
 700  7
         generator.setCheckstyleConfig( config );
 701  7
         if ( linkXRef )
 702  
         {
 703  7
             String relativePath = PathTool.getRelativePath( getOutputDirectory(), xrefLocation.getAbsolutePath() );
 704  7
             if ( StringUtils.isEmpty( relativePath ) )
 705  
             {
 706  7
                 relativePath = ".";
 707  
             }
 708  7
             relativePath = relativePath + "/" + xrefLocation.getName();
 709  7
             if ( xrefLocation.exists() )
 710  
             {
 711  
                 // XRef was already generated by manual execution of a lifecycle
 712  
                 // binding
 713  1
                 generator.setXrefLocation( relativePath );
 714  
             }
 715  
             else
 716  
             {
 717  
                 // Not yet generated - check if the report is on its way
 718  6
                 for ( Iterator reports = getProject().getReportPlugins().iterator(); reports.hasNext(); )
 719  
                 {
 720  6
                     ReportPlugin report = (ReportPlugin) reports.next();
 721  
 
 722  6
                     String artifactId = report.getArtifactId();
 723  6
                     if ( "maven-jxr-plugin".equals( artifactId ) || "jxr-maven-plugin".equals( artifactId ) )
 724  
                     {
 725  6
                         generator.setXrefLocation( relativePath );
 726  
                     }
 727  6
                 }
 728  
             }
 729  
 
 730  7
             if ( generator.getXrefLocation() == null )
 731  
             {
 732  0
                 getLog().warn( "Unable to locate Source XRef to link to - DISABLED" );
 733  
             }
 734  
         }
 735  7
         generator.generateReport( results );
 736  7
     }
 737  
 
 738  
     /**
 739  
      * Merge in the deprecated parameters to the new ones, unless the new
 740  
      * parameters have values.
 741  
      *
 742  
      * @deprecated Remove when deprecated params are removed.
 743  
      */
 744  
     private void mergeDeprecatedInfo()
 745  
     {
 746  10
         if ( "config/sun_checks.xml".equals( configLocation ) && !"sun".equals( format ) )
 747  
         {
 748  1
             configLocation = (String) FORMAT_TO_CONFIG_LOCATION.get( format );
 749  
         }
 750  
 
 751  10
         if ( StringUtils.isEmpty( propertiesLocation ) )
 752  
         {
 753  10
             if ( propertiesFile != null )
 754  
             {
 755  0
                 propertiesLocation = propertiesFile.getPath();
 756  
             }
 757  10
             else if ( propertiesURL != null )
 758  
             {
 759  0
                 propertiesLocation = propertiesURL.toExternalForm();
 760  
             }
 761  
         }
 762  
 
 763  10
         if ( "LICENSE.txt".equals( headerLocation ) )
 764  
         {
 765  1
             File defaultHeaderFile = new File( project.getBasedir(), "LICENSE.txt" );
 766  1
             if ( !defaultHeaderFile.equals( headerFile ) )
 767  
             {
 768  1
                 headerLocation = headerFile.getPath();
 769  
             }
 770  
         }
 771  
 
 772  10
         if ( StringUtils.isEmpty( suppressionsLocation ) )
 773  
         {
 774  10
             suppressionsLocation = suppressionsFile;
 775  
         }
 776  
 
 777  10
         if ( StringUtils.isEmpty( packageNamesLocation ) )
 778  
         {
 779  10
             packageNamesLocation = packageNamesFile;
 780  
         }
 781  10
     }
 782  
 
 783  
     private CheckstyleResults executeCheckstyle( Configuration config )
 784  
         throws MavenReportException, CheckstyleException
 785  
     {
 786  
         File[] files;
 787  
         try
 788  
         {
 789  9
             files = getFilesToProcess( includes, excludes );
 790  
         }
 791  0
         catch ( IOException e )
 792  
         {
 793  0
             throw new MavenReportException( "Error getting files to process", e );
 794  9
         }
 795  
 
 796  9
         FilterSet filterSet = getSuppressions();
 797  
 
 798  9
         Checker checker = new Checker();
 799  
 
 800  
         // setup classloader, needed to avoid "Unable to get class information
 801  
         // for ..." errors
 802  
         List classPathStrings;
 803  9
         List outputDirectories = new ArrayList();
 804  
         try
 805  
         {
 806  9
             classPathStrings = this.project.getCompileClasspathElements();
 807  8
             outputDirectories.add( this.project.getBuild().getOutputDirectory() );
 808  
 
 809  8
             if ( includeTestSourceDirectory && ( testSourceDirectory != null ) && ( testSourceDirectory.exists() )
 810  
                 && ( testSourceDirectory.isDirectory() ) )
 811  
             {
 812  0
                 classPathStrings = this.project.getTestClasspathElements();
 813  0
                 outputDirectories.add( this.project.getBuild().getTestOutputDirectory() );
 814  
             }
 815  
         }
 816  1
         catch ( DependencyResolutionRequiredException e )
 817  
         {
 818  1
             throw new MavenReportException( e.getMessage(), e );
 819  8
         }
 820  
 
 821  8
         List urls = new ArrayList( classPathStrings.size() );
 822  
 
 823  8
         Iterator iter = classPathStrings.iterator();
 824  16
         while ( iter.hasNext() )
 825  
         {
 826  
             try
 827  
             {
 828  8
                 urls.add( new File( ( (String) iter.next() ) ).toURL() );
 829  
             }
 830  0
             catch ( MalformedURLException e )
 831  
             {
 832  0
                 throw new MavenReportException( e.getMessage(), e );
 833  8
             }
 834  
         }
 835  
 
 836  8
         Iterator iterator = outputDirectories.iterator();
 837  16
         while ( iterator.hasNext() )
 838  
         {
 839  
             try
 840  
             {
 841  8
                 String outputDirectoryString = (String) iterator.next();
 842  8
                 if ( outputDirectoryString != null )
 843  
                 {
 844  0
                     File outputDirectoryFile = new File( outputDirectoryString );
 845  0
                     if ( outputDirectoryFile.exists() )
 846  
                     {
 847  0
                         URL outputDirectoryUrl = outputDirectoryFile.toURL();
 848  0
                         getLog().debug( "Adding the outputDirectory " + outputDirectoryUrl.toString()
 849  
                             + " to the Checkstyle class path" );
 850  0
                         urls.add( outputDirectoryUrl );
 851  
                     }
 852  
                 }
 853  
             }
 854  0
             catch ( MalformedURLException e )
 855  
             {
 856  0
                 throw new MavenReportException( e.getMessage(), e );
 857  8
             }
 858  
         }
 859  
 
 860  8
         URLClassLoader projectClassLoader = new URLClassLoader( (URL[]) urls.toArray( new URL[urls.size()] ), null );
 861  8
         checker.setClassloader( projectClassLoader );
 862  
 
 863  8
         checker.setModuleClassLoader( Thread.currentThread().getContextClassLoader() );
 864  
 
 865  8
         if ( filterSet != null )
 866  
         {
 867  0
             checker.addFilter( filterSet );
 868  
         }
 869  
 
 870  8
         checker.configure( config );
 871  
 
 872  8
         AuditListener listener = getListener();
 873  
 
 874  8
         if ( listener != null )
 875  
         {
 876  8
             checker.addListener( listener );
 877  
         }
 878  
 
 879  8
         if ( consoleOutput )
 880  
         {
 881  2
             checker.addListener( getConsoleListener() );
 882  
         }
 883  
 
 884  8
         CheckstyleReportListener sinkListener = new CheckstyleReportListener( sourceDirectory );
 885  8
         if ( includeTestSourceDirectory && ( testSourceDirectory != null ) && ( testSourceDirectory.exists() )
 886  
             && ( testSourceDirectory.isDirectory() ) )
 887  
         {
 888  0
             sinkListener.addSourceDirectory( testSourceDirectory );
 889  
         }
 890  
 
 891  8
         checker.addListener( sinkListener );
 892  
 
 893  8
         ArrayList filesList = new ArrayList();
 894  16
         for (int i = 0; i < files.length; i++) {
 895  8
             filesList.add(files[i]);
 896  
         }
 897  8
         int nbErrors = checker.process( filesList );
 898  
 
 899  8
         checker.destroy();
 900  
 
 901  8
         if ( stringOutputStream != null )
 902  
         {
 903  1
             getLog().info( stringOutputStream.toString() );
 904  
         }
 905  
 
 906  8
         if ( failsOnError && nbErrors > 0 )
 907  
         {
 908  
             // TODO: should be a failure, not an error. Report is not meant to
 909  
             // throw an exception here (so site would
 910  
             // work regardless of config), but should record this information
 911  1
             throw new MavenReportException( "There are " + nbErrors + " checkstyle errors." );
 912  
         }
 913  7
         else if ( nbErrors > 0 )
 914  
         {
 915  7
             getLog().info( "There are " + nbErrors + " checkstyle errors." );
 916  
         }
 917  
 
 918  7
         return sinkListener.getResults();
 919  
     }
 920  
 
 921  
     /** {@inheritDoc} */
 922  
     public String getOutputName()
 923  
     {
 924  25
         return "checkstyle";
 925  
     }
 926  
 
 927  
     private AuditListener getListener()
 928  
         throws MavenReportException
 929  
     {
 930  8
         AuditListener listener = null;
 931  
 
 932  8
         if ( StringUtils.isNotEmpty( outputFileFormat ) )
 933  
         {
 934  8
             File resultFile = outputFile;
 935  
 
 936  8
             OutputStream out = getOutputStream( resultFile );
 937  
 
 938  8
             if ( "xml".equals( outputFileFormat ) )
 939  
             {
 940  7
                 listener = new XMLLogger( out, true );
 941  
             }
 942  1
             else if ( "plain".equals( outputFileFormat ) )
 943  
             {
 944  1
                 listener = new DefaultLogger( out, true );
 945  
             }
 946  
             else
 947  
             {
 948  
                 // TODO: failure if not a report
 949  0
                 throw new MavenReportException( "Invalid output file format: (" + outputFileFormat
 950  
                     + "). Must be 'plain' or 'xml'." );
 951  
             }
 952  
         }
 953  
 
 954  8
         return listener;
 955  
     }
 956  
 
 957  
     private OutputStream getOutputStream( File file )
 958  
         throws MavenReportException
 959  
     {
 960  9
         File parentFile = file.getAbsoluteFile().getParentFile();
 961  
 
 962  9
         if ( !parentFile.exists() )
 963  
         {
 964  0
             parentFile.mkdirs();
 965  
         }
 966  
 
 967  
         FileOutputStream fileOutputStream;
 968  
         try
 969  
         {
 970  9
             fileOutputStream = new FileOutputStream( file );
 971  
         }
 972  0
         catch ( FileNotFoundException e )
 973  
         {
 974  0
             throw new MavenReportException( "Unable to create output stream: " + file, e );
 975  9
         }
 976  9
         return fileOutputStream;
 977  
     }
 978  
 
 979  
     private File[] getFilesToProcess( String includes, String excludes )
 980  
         throws IOException
 981  
     {
 982  9
         StringBuffer excludesStr = new StringBuffer();
 983  
 
 984  9
         if ( StringUtils.isNotEmpty( excludes ) )
 985  
         {
 986  0
             excludesStr.append( excludes );
 987  
         }
 988  
 
 989  9
         String[] defaultExcludes = FileUtils.getDefaultExcludes();
 990  180
         for ( int i = 0; i < defaultExcludes.length; i++ )
 991  
         {
 992  171
             if ( excludesStr.length() > 0 )
 993  
             {
 994  162
                 excludesStr.append( "," );
 995  
             }
 996  
 
 997  171
             excludesStr.append( defaultExcludes[i] );
 998  
         }
 999  
 
 1000  9
         List files = FileUtils.getFiles( sourceDirectory, includes, excludesStr.toString() );
 1001  9
         if ( includeTestSourceDirectory && ( testSourceDirectory != null ) && ( testSourceDirectory.exists() )
 1002  
             && ( testSourceDirectory.isDirectory() ) )
 1003  
         {
 1004  0
             files.addAll( FileUtils.getFiles( testSourceDirectory, includes, excludesStr.toString() ) );
 1005  
         }
 1006  
 
 1007  9
         return (File[]) files.toArray( EMPTY_FILE_ARRAY );
 1008  
     }
 1009  
 
 1010  
     private Properties getOverridingProperties()
 1011  
         throws MavenReportException
 1012  
     {
 1013  9
         Properties p = new Properties();
 1014  
 
 1015  
         try
 1016  
         {
 1017  9
             File propertiesFile = locator.resolveLocation( propertiesLocation, "checkstyle-checker.properties" );
 1018  
 
 1019  9
             if ( propertiesFile != null )
 1020  
             {
 1021  0
                 p.load( new FileInputStream( propertiesFile ) );
 1022  
             }
 1023  
 
 1024  9
             if ( StringUtils.isNotEmpty( propertyExpansion ) )
 1025  
             {
 1026  
                 // Convert \ to \\, so that p.load will convert it back properly
 1027  0
                 propertyExpansion = StringUtils.replace( propertyExpansion, "\\", "\\\\" );
 1028  0
                 p.load( new ByteArrayInputStream( propertyExpansion.getBytes() ) );
 1029  
             }
 1030  
 
 1031  
             // Workaround for MCHECKSTYLE-48
 1032  
             // Make sure that "config/maven-header.txt" is the default value
 1033  
             // for headerLocation, if configLocation="config/maven_checks.xml"
 1034  9
             if ( "config/maven_checks.xml".equals( configLocation ) )
 1035  
             {
 1036  1
                 if ( "LICENSE.txt".equals( headerLocation ) )
 1037  
                 {
 1038  0
                     headerLocation = "config/maven-header.txt";
 1039  
                 }
 1040  
             }
 1041  9
             if ( StringUtils.isNotEmpty( headerLocation ) )
 1042  
             {
 1043  
                 try
 1044  
                 {
 1045  9
                     File headerFile = locator.resolveLocation( headerLocation, "checkstyle-header.txt" );
 1046  
 
 1047  9
                     if ( headerFile != null )
 1048  
                     {
 1049  9
                         p.setProperty( "checkstyle.header.file", headerFile.getAbsolutePath() );
 1050  
                     }
 1051  
                 }
 1052  0
                 catch ( IOException e )
 1053  
                 {
 1054  0
                     throw new MavenReportException( "Unable to process header location: " + headerLocation, e );
 1055  9
                 }
 1056  
             }
 1057  
 
 1058  9
             if ( cacheFile != null )
 1059  
             {
 1060  9
                 p.setProperty( "checkstyle.cache.file", cacheFile );
 1061  
             }
 1062  
         }
 1063  0
         catch ( IOException e )
 1064  
         {
 1065  0
             throw new MavenReportException( "Failed to get overriding properties", e );
 1066  9
         }
 1067  
 
 1068  9
         if ( suppressionsFileExpression != null )
 1069  
         {
 1070  0
             String suppresionFile = getSuppressionLocation();
 1071  
 
 1072  0
             if ( suppresionFile != null )
 1073  
             {
 1074  0
                 p.setProperty( suppressionsFileExpression, suppresionFile );
 1075  
             }
 1076  
         }
 1077  
 
 1078  9
         return p;
 1079  
     }
 1080  
 
 1081  
     private String getConfigFile()
 1082  
         throws MavenReportException
 1083  
     {
 1084  
         try
 1085  
         {
 1086  9
             File configFile = locator.getResourceAsFile( configLocation, "checkstyle-checker.xml" );
 1087  
 
 1088  9
             if ( configFile == null )
 1089  
             {
 1090  0
                 throw new MavenReportException( "Unable to process config location: " + configLocation );
 1091  
             }
 1092  9
             return configFile.getAbsolutePath();
 1093  
         }
 1094  0
         catch ( org.codehaus.plexus.resource.loader.ResourceNotFoundException e )
 1095  
         {
 1096  0
             throw new MavenReportException( "Unable to find configuration file at location "
 1097  
                                             + configLocation, e );
 1098  
         }
 1099  0
         catch ( FileResourceCreationException e )
 1100  
         {
 1101  0
             throw new MavenReportException( "Unable to process configuration file location "
 1102  
                                             + configLocation, e );
 1103  
         }
 1104  
 
 1105  
     }
 1106  
 
 1107  
     private String getSuppressionLocation()
 1108  
         throws MavenReportException
 1109  
     {
 1110  
         try
 1111  
         {
 1112  0
             File suppressionsFile = locator.resolveLocation( suppressionsLocation, "checkstyle-suppressions.xml" );
 1113  
 
 1114  0
             if ( suppressionsFile == null )
 1115  
             {
 1116  0
                 return null;
 1117  
             }
 1118  
 
 1119  0
             return suppressionsFile.getAbsolutePath();
 1120  
         }
 1121  0
         catch ( IOException e )
 1122  
         {
 1123  0
             throw new MavenReportException( "Failed to process supressions location: " + suppressionsLocation, e );
 1124  
         }
 1125  
     }
 1126  
 
 1127  
     private FilterSet getSuppressions()
 1128  
         throws MavenReportException
 1129  
     {
 1130  
         try
 1131  
         {
 1132  9
             File suppressionsFile = locator.resolveLocation( suppressionsLocation, "checkstyle-suppressions.xml" );
 1133  
 
 1134  9
             if ( suppressionsFile == null )
 1135  
             {
 1136  9
                 return null;
 1137  
             }
 1138  
 
 1139  0
             return SuppressionsLoader.loadSuppressions( suppressionsFile.getAbsolutePath() );
 1140  
         }
 1141  0
         catch ( CheckstyleException ce )
 1142  
         {
 1143  0
             throw new MavenReportException( "failed to load suppressions location: " + suppressionsLocation, ce );
 1144  
         }
 1145  0
         catch ( IOException e )
 1146  
         {
 1147  0
             throw new MavenReportException( "Failed to process supressions location: " + suppressionsLocation, e );
 1148  
         }
 1149  
     }
 1150  
 
 1151  
     private DefaultLogger getConsoleListener()
 1152  
         throws MavenReportException
 1153  
     {
 1154  
         DefaultLogger consoleListener;
 1155  
 
 1156  2
         if ( useFile == null )
 1157  
         {
 1158  1
             stringOutputStream = new ByteArrayOutputStream();
 1159  1
             consoleListener = new DefaultLogger( stringOutputStream, false );
 1160  
         }
 1161  
         else
 1162  
         {
 1163  1
             OutputStream out = getOutputStream( useFile );
 1164  
 
 1165  1
             consoleListener = new DefaultLogger( out, true );
 1166  
         }
 1167  
 
 1168  2
         return consoleListener;
 1169  
     }
 1170  
 
 1171  
     private static ResourceBundle getBundle( Locale locale )
 1172  
     {
 1173  9
         return ResourceBundle.getBundle( "checkstyle-report", locale, CheckstyleReport.class.getClassLoader() );
 1174  
     }
 1175  
 
 1176  
     /** {@inheritDoc} */
 1177  
     public boolean canGenerateReport()
 1178  
     {
 1179  
         // TODO: would be good to scan the files here
 1180  10
         return sourceDirectory.exists();
 1181  
     }
 1182  
 
 1183  
     /** {@inheritDoc} */
 1184  
     public void setReportOutputDirectory( File reportOutputDirectory )
 1185  
     {
 1186  0
         super.setReportOutputDirectory( reportOutputDirectory );
 1187  0
         this.outputDirectory = reportOutputDirectory;
 1188  0
     }
 1189  
 }