Coverage Report - org.apache.maven.plugin.pmd.AbstractPmdReport
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractPmdReport
67%
70/104
50%
38/76
5,083
 
 1  
 package org.apache.maven.plugin.pmd;
 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.File;
 23  
 import java.io.IOException;
 24  
 import java.util.ArrayList;
 25  
 import java.util.Collection;
 26  
 import java.util.Collections;
 27  
 import java.util.HashSet;
 28  
 import java.util.Iterator;
 29  
 import java.util.LinkedHashSet;
 30  
 import java.util.List;
 31  
 import java.util.Map;
 32  
 import java.util.TreeMap;
 33  
 
 34  
 import net.sourceforge.pmd.PMD;
 35  
 
 36  
 import org.apache.maven.doxia.siterenderer.Renderer;
 37  
 import org.apache.maven.model.ReportPlugin;
 38  
 import org.apache.maven.project.MavenProject;
 39  
 import org.apache.maven.reporting.AbstractMavenReport;
 40  
 import org.codehaus.plexus.util.FileUtils;
 41  
 import org.codehaus.plexus.util.PathTool;
 42  
 import org.codehaus.plexus.util.ReaderFactory;
 43  
 import org.codehaus.plexus.util.StringUtils;
 44  
 
 45  
 /**
 46  
  * Base class for the PMD reports.
 47  
  *
 48  
  * @author <a href="mailto:brett@apache.org">Brett Porter</a>
 49  
  * @version $Id: org.apache.maven.plugin.pmd.AbstractPmdReport.html 816698 2012-05-08 15:21:08Z hboutemy $
 50  
  */
 51  13
 public abstract class AbstractPmdReport
 52  
     extends AbstractMavenReport
 53  
 {
 54  
     /**
 55  
      * The output directory for the intermediate XML report.
 56  
      *
 57  
      * @parameter expression="${project.build.directory}"
 58  
      * @required
 59  
      */
 60  
     protected File targetDirectory;
 61  
 
 62  
     /**
 63  
      * The output directory for the final HTML report. Note that this parameter is only evaluated if the goal is run
 64  
      * directly from the command line or during the default lifecycle. If the goal is run indirectly as part of a site
 65  
      * generation, the output directory configured in the Maven Site Plugin is used instead.
 66  
      *
 67  
      * @parameter expression="${project.reporting.outputDirectory}"
 68  
      * @required
 69  
      */
 70  
     protected File outputDirectory;
 71  
 
 72  
     /**
 73  
      * Site rendering component for generating the HTML report.
 74  
      *
 75  
      * @component
 76  
      */
 77  
     private Renderer siteRenderer;
 78  
 
 79  
     /**
 80  
      * The project to analyse.
 81  
      *
 82  
      * @parameter expression="${project}"
 83  
      * @required
 84  
      * @readonly
 85  
      */
 86  
     protected MavenProject project;
 87  
 
 88  
     /**
 89  
      * Set the output format type, in addition to the HTML report.  Must be one of: "none",
 90  
      * "csv", "xml", "txt" or the full class name of the PMD renderer to use.
 91  
      * See the net.sourceforge.pmd.renderers package javadoc for available renderers.
 92  
      * XML is required if the pmd:check goal is being used.
 93  
      *
 94  
      * @parameter expression="${format}" default-value="xml"
 95  
      */
 96  13
     protected String format = "xml";
 97  
 
 98  
     /**
 99  
      * Link the violation line numbers to the source xref. Links will be created
 100  
      * automatically if the jxr plugin is being used.
 101  
      *
 102  
      * @parameter expression="${linkXRef}" default-value="true"
 103  
      */
 104  
     private boolean linkXRef;
 105  
 
 106  
     /**
 107  
      * Location of the Xrefs to link to.
 108  
      *
 109  
      * @parameter default-value="${project.reporting.outputDirectory}/xref"
 110  
      */
 111  
     private File xrefLocation;
 112  
 
 113  
     /**
 114  
      * Location of the Test Xrefs to link to.
 115  
      *
 116  
      * @parameter default-value="${project.reporting.outputDirectory}/xref-test"
 117  
      */
 118  
     private File xrefTestLocation;
 119  
 
 120  
     /**
 121  
      * A list of files to exclude from checking. Can contain Ant-style wildcards and double wildcards. Note that these
 122  
      * exclusion patterns only operate on the path of a source file relative to its source root directory. In other
 123  
      * words, files are excluded based on their package and/or class name. If you want to exclude entire source root
 124  
      * directories, use the parameter <code>excludeRoots</code> instead.
 125  
      *
 126  
      * @parameter
 127  
      * @since 2.2
 128  
      */
 129  
     private List<String> excludes;
 130  
 
 131  
     /**
 132  
      * A list of files to include from checking. Can contain Ant-style wildcards and double wildcards.
 133  
      * Defaults to **\/*.java.
 134  
      *
 135  
      * @parameter
 136  
      * @since 2.2
 137  
      */
 138  
     private List<String> includes;
 139  
 
 140  
     /**
 141  
      * The directories containing the sources to be compiled.
 142  
      *
 143  
      * @parameter expression="${project.compileSourceRoots}"
 144  
      * @required
 145  
      * @readonly
 146  
      */
 147  
     private List<String> compileSourceRoots;
 148  
 
 149  
     /**
 150  
      * The directories containing the test-sources to be compiled.
 151  
      *
 152  
      * @parameter expression="${project.testCompileSourceRoots}"
 153  
      * @required
 154  
      * @readonly
 155  
      */
 156  
     private List<String> testSourceRoots;
 157  
 
 158  
     /**
 159  
      * The project source directories that should be excluded.
 160  
      *
 161  
      * @parameter
 162  
      * @since 2.2
 163  
      */
 164  
     private File[] excludeRoots;
 165  
 
 166  
     /**
 167  
      * Run PMD on the tests.
 168  
      *
 169  
      * @parameter default-value="false"
 170  
      * @since 2.2
 171  
      */
 172  
     protected boolean includeTests;
 173  
 
 174  
     /**
 175  
      * Whether to build an aggregated report at the root, or build individual reports.
 176  
      *
 177  
      * @parameter expression="${aggregate}" default-value="false"
 178  
      * @since 2.2
 179  
      */
 180  
     protected boolean aggregate;
 181  
 
 182  
     /**
 183  
      * The file encoding to use when reading the Java sources.
 184  
      *
 185  
      * @parameter expression="${encoding}" default-value="${project.build.sourceEncoding}"
 186  
      * @since 2.3
 187  
      */
 188  
     private String sourceEncoding;
 189  
 
 190  
     /**
 191  
      * The file encoding when writing non-HTML reports.
 192  
      *
 193  
      * @parameter expression="${outputEncoding}" default-value="${project.reporting.outputEncoding}"
 194  
      * @since 2.5
 195  
      */
 196  
     private String outputEncoding;
 197  
 
 198  
     /**
 199  
      * The projects in the reactor for aggregation report.
 200  
      *
 201  
      * @parameter expression="${reactorProjects}"
 202  
      * @readonly
 203  
      */
 204  
     protected List<MavenProject> reactorProjects;
 205  
 
 206  
     /** {@inheritDoc} */
 207  
     protected MavenProject getProject()
 208  
     {
 209  0
         return project;
 210  
     }
 211  
 
 212  
     /** {@inheritDoc} */
 213  
     protected Renderer getSiteRenderer()
 214  
     {
 215  13
         return siteRenderer;
 216  
     }
 217  
 
 218  
     protected String constructXRefLocation( boolean test )
 219  
     {
 220  19
         String location = null;
 221  19
         if ( linkXRef )
 222  
         {
 223  8
             File xrefLoc = test ? xrefTestLocation : xrefLocation;
 224  
 
 225  8
             String relativePath = PathTool.getRelativePath( outputDirectory.getAbsolutePath(),
 226  
                                                             xrefLoc.getAbsolutePath() );
 227  8
             if ( StringUtils.isEmpty( relativePath ) )
 228  
             {
 229  0
                 relativePath = ".";
 230  
             }
 231  8
             relativePath = relativePath + "/" + xrefLoc.getName();
 232  8
             if ( xrefLoc.exists() )
 233  
             {
 234  
                 // XRef was already generated by manual execution of a lifecycle binding
 235  2
                 location = relativePath;
 236  
             }
 237  
             else
 238  
             {
 239  
                 // Not yet generated - check if the report is on its way
 240  
                 @SuppressWarnings( "unchecked" )
 241  6
                 List<ReportPlugin> reportPlugins = project.getReportPlugins();
 242  6
                 for ( ReportPlugin plugin  : reportPlugins )
 243  
                 {
 244  6
                     String artifactId = plugin.getArtifactId();
 245  6
                     if ( "maven-jxr-plugin".equals( artifactId ) || "jxr-maven-plugin".equals( artifactId ) )
 246  
                     {
 247  6
                         location = relativePath;
 248  
                     }
 249  6
                 }
 250  
             }
 251  
 
 252  8
             if ( location == null )
 253  
             {
 254  0
                 getLog().warn( "Unable to locate Source XRef to link to - DISABLED" );
 255  
             }
 256  
         }
 257  19
         return location;
 258  
     }
 259  
 
 260  
     /**
 261  
      * Convenience method to get the list of files where the PMD tool will be executed
 262  
      *
 263  
      * @return a List of the files where the PMD tool will be executed
 264  
      * @throws java.io.IOException
 265  
      */
 266  
     protected Map<File, PmdFileInfo> getFilesToProcess()
 267  
         throws IOException
 268  
     {
 269  19
         String sourceXref = constructXRefLocation( false );
 270  19
         String testXref = includeTests ? constructXRefLocation( true ) : "";
 271  
 
 272  19
         if ( aggregate && !project.isExecutionRoot() )
 273  
         {
 274  0
             return Collections.emptyMap();
 275  
         }
 276  
 
 277  19
         if ( excludeRoots == null )
 278  
         {
 279  10
             excludeRoots = new File[0];
 280  
         }
 281  
         
 282  19
         Collection<File> excludeRootFiles = new HashSet<File>( excludeRoots.length );
 283  
 
 284  19
         for ( int i = 0; i < excludeRoots.length; i++ )
 285  
         {
 286  0
             File file = excludeRoots[i];
 287  0
             if ( file.isDirectory() )
 288  
             {
 289  0
                 excludeRootFiles.add( file );
 290  
             }
 291  
         }
 292  
 
 293  19
         List<PmdFileInfo> directories = new ArrayList<PmdFileInfo>();
 294  
 
 295  19
         if ( compileSourceRoots != null )
 296  
         {
 297  
 
 298  18
             for ( String root : compileSourceRoots )
 299  
             {
 300  18
                 File sroot = new File( root );
 301  18
                 directories.add( new PmdFileInfo( project, sroot, sourceXref ) );
 302  18
             }
 303  
 
 304  
         }
 305  19
         if ( includeTests )
 306  
         {
 307  0
             if ( testSourceRoots != null )
 308  
             {
 309  0
                 for ( String root : testSourceRoots )
 310  
                 {
 311  0
                     File sroot = new File( root );
 312  0
                     directories.add( new PmdFileInfo( project, sroot, testXref ) );
 313  0
                 }
 314  
             }
 315  
         }
 316  19
         if ( aggregate )
 317  
         {
 318  0
             for ( MavenProject localProject : reactorProjects )
 319  
             {
 320  
                 @SuppressWarnings( "unchecked" )
 321  0
                 List<String> localCompileSourceRoots = localProject.getCompileSourceRoots(); 
 322  0
                 for ( String root : localCompileSourceRoots )
 323  
                 {
 324  0
                     File sroot = new File( root );
 325  0
                     directories.add( new PmdFileInfo( localProject, sroot, sourceXref ) );
 326  0
                 }
 327  0
                 if ( includeTests )
 328  
                 {
 329  
                     @SuppressWarnings( "unchecked" )
 330  0
                     List<String> localTestCompileSourceRoots = localProject.getTestCompileSourceRoots(); 
 331  0
                     for ( String root : localTestCompileSourceRoots )
 332  
                     {
 333  0
                         File sroot = new File( root );
 334  0
                         directories.add( new PmdFileInfo( localProject, sroot, testXref ) );
 335  0
                     }
 336  
                 }
 337  0
             }
 338  
 
 339  
         }
 340  
 
 341  19
         String excluding = getExcludes();
 342  19
         getLog().debug( "Exclusions: " + excluding );
 343  19
         String including = getIncludes();
 344  19
         getLog().debug( "Inclusions: " + including );
 345  
 
 346  19
         Map<File, PmdFileInfo> files = new TreeMap<File, PmdFileInfo>();
 347  
 
 348  19
         for ( PmdFileInfo finfo : directories )
 349  
         {
 350  18
             File sourceDirectory = finfo.getSourceDirectory();
 351  18
             if ( sourceDirectory.isDirectory() && !excludeRootFiles.contains( sourceDirectory ) )
 352  
             {
 353  
                 @SuppressWarnings( "unchecked" )
 354  18
                 List<File> newfiles = FileUtils.getFiles( sourceDirectory, including, excluding );
 355  18
                 for ( Iterator<File> it2 = newfiles.iterator(); it2.hasNext(); )
 356  
                 {
 357  45
                     files.put( it2.next(), finfo );
 358  
                 }
 359  
             }
 360  18
         }
 361  
 
 362  19
         return files;
 363  
     }
 364  
 
 365  
     /**
 366  
      * Gets the comma separated list of effective include patterns.
 367  
      *
 368  
      * @return The comma separated list of effective include patterns, never <code>null</code>.
 369  
      */
 370  
     private String getIncludes()
 371  
     {
 372  19
         Collection<String> patterns = new LinkedHashSet<String>();
 373  19
         if ( includes != null )
 374  
         {
 375  0
             patterns.addAll( includes );
 376  
         }
 377  19
         if ( patterns.isEmpty() )
 378  
         {
 379  19
             patterns.add( "**/*.java" );
 380  
         }
 381  19
         return StringUtils.join( patterns.iterator(), "," );
 382  
     }
 383  
 
 384  
     /**
 385  
      * Gets the comma separated list of effective exclude patterns.
 386  
      *
 387  
      * @return The comma separated list of effective exclude patterns, never <code>null</code>.
 388  
      */
 389  
     private String getExcludes()
 390  
     {
 391  
         @SuppressWarnings( "unchecked" )
 392  19
         Collection<String> patterns = new LinkedHashSet<String>( FileUtils.getDefaultExcludesAsList() );
 393  19
         if ( excludes != null )
 394  
         {
 395  8
             patterns.addAll( excludes );
 396  
         }
 397  19
         return StringUtils.join( patterns.iterator(), "," );
 398  
     }
 399  
 
 400  
     protected boolean isHtml()
 401  
     {
 402  8
         return "html".equals( format );
 403  
     }
 404  
 
 405  
     /** {@inheritDoc} */
 406  
     public boolean canGenerateReport()
 407  
     {
 408  29
         if ( aggregate && !project.isExecutionRoot() )
 409  
         {
 410  0
             return false;
 411  
         }
 412  
 
 413  29
         if ( "pom".equals( project.getPackaging() ) && !aggregate )
 414  
         {
 415  0
             return false;
 416  
         }
 417  
 
 418  
         // if format is XML, we need to output it even if the file list is empty
 419  
         // so the "check" goals can check for failures
 420  29
         if ( "xml".equals( format ) )
 421  
         {
 422  18
             return true;
 423  
         }
 424  
         try
 425  
         {
 426  11
             Map<File, PmdFileInfo> filesToProcess = getFilesToProcess();
 427  11
             if ( filesToProcess.isEmpty() )
 428  
             {
 429  1
                 return false;
 430  
             }
 431  
         }
 432  0
         catch ( IOException e )
 433  
         {
 434  0
             getLog().error( e );
 435  10
         }
 436  10
         return true;
 437  
     }
 438  
 
 439  
     /** {@inheritDoc} */
 440  
     protected String getOutputDirectory()
 441  
     {
 442  17
         return outputDirectory.getAbsolutePath();
 443  
     }
 444  
 
 445  
     protected String getSourceEncoding()
 446  
     {
 447  84
         return sourceEncoding;
 448  
     }
 449  
 
 450  
     /**
 451  
      * Gets the effective reporting output files encoding.
 452  
      *
 453  
      * @return The effective reporting output file encoding, never <code>null</code>.
 454  
      * @since 2.5
 455  
      */
 456  
     protected String getOutputEncoding()
 457  
     {
 458  14
         return ( outputEncoding != null ) ? outputEncoding : ReaderFactory.UTF_8;
 459  
     }
 460  
 
 461  
     static String getPmdVersion()
 462  
     {
 463  
         try
 464  
         {
 465  8
             return (String) PMD.class.getField( "VERSION" ).get( null );
 466  
         }
 467  0
         catch ( IllegalAccessException e )
 468  
         {
 469  0
             throw new RuntimeException( "PMD VERSION field not accessible", e );
 470  
         }
 471  0
         catch ( NoSuchFieldException e )
 472  
         {
 473  0
             throw new RuntimeException( "PMD VERSION field not found", e );
 474  
         }
 475  
     }
 476  
 }