View Javadoc
1   package org.apache.maven.plugins.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.FileNotFoundException;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.io.OutputStreamWriter;
27  import java.io.PrintStream;
28  import java.io.Writer;
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.Locale;
34  import java.util.Properties;
35  import java.util.ResourceBundle;
36  
37  import org.apache.maven.doxia.sink.Sink;
38  import org.apache.maven.execution.MavenSession;
39  import org.apache.maven.plugin.MojoExecutionException;
40  import org.apache.maven.plugins.annotations.Component;
41  import org.apache.maven.plugins.annotations.Mojo;
42  import org.apache.maven.plugins.annotations.Parameter;
43  import org.apache.maven.plugins.annotations.ResolutionScope;
44  import org.apache.maven.project.DefaultProjectBuildingRequest;
45  import org.apache.maven.project.MavenProject;
46  import org.apache.maven.project.ProjectBuildingRequest;
47  import org.apache.maven.reporting.MavenReportException;
48  import org.apache.maven.shared.artifact.filter.resolve.ScopeFilter;
49  import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResult;
50  import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolver;
51  import org.codehaus.plexus.resource.ResourceManager;
52  import org.codehaus.plexus.resource.loader.FileResourceCreationException;
53  import org.codehaus.plexus.resource.loader.FileResourceLoader;
54  import org.codehaus.plexus.resource.loader.ResourceNotFoundException;
55  import org.codehaus.plexus.util.FileUtils;
56  import org.codehaus.plexus.util.ReaderFactory;
57  import org.codehaus.plexus.util.StringUtils;
58  
59  import net.sourceforge.pmd.PMD;
60  import net.sourceforge.pmd.PMDConfiguration;
61  import net.sourceforge.pmd.Report;
62  import net.sourceforge.pmd.RuleContext;
63  import net.sourceforge.pmd.RulePriority;
64  import net.sourceforge.pmd.RuleSetFactory;
65  import net.sourceforge.pmd.RuleSetNotFoundException;
66  import net.sourceforge.pmd.RuleSetReferenceId;
67  import net.sourceforge.pmd.RuleViolation;
68  import net.sourceforge.pmd.benchmark.Benchmarker;
69  import net.sourceforge.pmd.benchmark.TextReport;
70  import net.sourceforge.pmd.lang.LanguageRegistry;
71  import net.sourceforge.pmd.lang.LanguageVersion;
72  import net.sourceforge.pmd.renderers.CSVRenderer;
73  import net.sourceforge.pmd.renderers.HTMLRenderer;
74  import net.sourceforge.pmd.renderers.Renderer;
75  import net.sourceforge.pmd.renderers.TextRenderer;
76  import net.sourceforge.pmd.renderers.XMLRenderer;
77  import net.sourceforge.pmd.util.ResourceLoader;
78  import net.sourceforge.pmd.util.datasource.DataSource;
79  import net.sourceforge.pmd.util.datasource.FileDataSource;
80  
81  /**
82   * Creates a PMD report.
83   *
84   * @author Brett Porter
85   * @version $Id$
86   * @since 2.0
87   */
88  @Mojo( name = "pmd", threadSafe = true, requiresDependencyResolution = ResolutionScope.TEST )
89  public class PmdReport
90      extends AbstractPmdReport
91  {
92      /**
93       * The target JDK to analyze based on. Should match the source used in the compiler plugin. Valid values are
94       * currently <code>1.3</code>, <code>1.4</code>, <code>1.5</code>, <code>1.6</code>, <code>1.7</code>,
95       * <code>1.8</code>, <code>9</code>, and <code>10</code>.
96       * <p>
97       *   <b>Note:</b> this parameter is only used if the language parameter is set to <code>java</code>.
98       * </p>
99       */
100     @Parameter( property = "targetJdk", defaultValue = "${maven.compiler.source}" )
101     private String targetJdk;
102 
103     /**
104      * The programming language to be analyzed by PMD. Valid values are currently <code>java</code>,
105      * <code>javascript</code> and <code>jsp</code>.
106      *
107      * @since 3.0
108      */
109     @Parameter( defaultValue = "java" )
110     private String language;
111 
112     /**
113      * The rule priority threshold; rules with lower priority than this will not be evaluated.
114      *
115      * @since 2.1
116      */
117     @Parameter( property = "minimumPriority", defaultValue = "5" )
118     private int minimumPriority = 5;
119 
120     /**
121      * Skip the PMD report generation. Most useful on the command line via "-Dpmd.skip=true".
122      *
123      * @since 2.1
124      */
125     @Parameter( property = "pmd.skip", defaultValue = "false" )
126     private boolean skip;
127 
128     /**
129      * The PMD rulesets to use. See the
130      * <a href="https://pmd.github.io/latest/pmd_rules_java.html">Stock Java Rulesets</a> for a
131      * list of available rules.
132      * Defaults to a custom ruleset provided by this maven plugin
133      * (<code>/rulesets/java/maven-pmd-plugin-default.xml</code>).
134      */
135     @Parameter
136     private String[] rulesets = new String[] { "/rulesets/java/maven-pmd-plugin-default.xml" };
137 
138     /**
139      * Controls whether the project's compile/test classpath should be passed to PMD to enable its type resolution
140      * feature.
141      *
142      * @since 3.0
143      */
144     @Parameter( property = "pmd.typeResolution", defaultValue = "true" )
145     private boolean typeResolution;
146 
147     /**
148      * Controls whether PMD will track benchmark information.
149      *
150      * @since 3.1
151      */
152     @Parameter( property = "pmd.benchmark", defaultValue = "false" )
153     private boolean benchmark;
154 
155     /**
156      * Benchmark output filename.
157      *
158      * @since 3.1
159      */
160     @Parameter( property = "pmd.benchmarkOutputFilename",
161                     defaultValue = "${project.build.directory}/pmd-benchmark.txt" )
162     private String benchmarkOutputFilename;
163 
164     /**
165      * Source level marker used to indicate whether a RuleViolation should be suppressed. If it is not set, PMD's
166      * default will be used, which is <code>NOPMD</code>. See also <a
167      * href="https://pmd.github.io/latest/pmd_userdocs_suppressing_warnings.html">PMD &#x2013; Suppressing warnings</a>.
168      *
169      * @since 3.4
170      */
171     @Parameter( property = "pmd.suppressMarker" )
172     private String suppressMarker;
173 
174     /**
175      */
176     @Component
177     private ResourceManager locator;
178 
179     /** The PMD renderer for collecting violations. */
180     private PmdCollectingRenderer renderer;
181 
182     /** Helper to exclude violations given as a properties file. */
183     private final ExcludeViolationsFromFile excludeFromFile = new ExcludeViolationsFromFile();
184 
185     /**
186      * per default pmd executions error are ignored to not break the whole
187      *
188      * @since 3.1
189      */
190     @Parameter( property = "pmd.skipPmdError", defaultValue = "true" )
191     private boolean skipPmdError;
192 
193     /**
194      * Enables the analysis cache, which speeds up PMD. This
195      * requires a cache file, that contains the results of the last
196      * PMD run. Thus the cache is only effective, if this file is
197      * not cleaned between runs.
198      *
199      * @since 3.8
200      */
201     @Parameter( property = "pmd.analysisCache", defaultValue = "false" )
202     private boolean analysisCache;
203 
204     /**
205      * The location of the analysis cache, if it is enabled.
206      * This file contains the results of the last PMD run and must not be cleaned
207      * between consecutive PMD runs. Otherwise the cache is not in use.
208      * If the file doesn't exist, PMD executes as if there is no cache enabled and
209      * all files are analyzed. Otherwise only changed files will be analyzed again.
210      *
211      * @since 3.8
212      */
213     @Parameter( property = "pmd.analysisCacheLocation", defaultValue = "${project.build.directory}/pmd/pmd.cache" )
214     private String analysisCacheLocation;
215 
216     /**
217      * Also render processing errors into the HTML report.
218      * Processing errors are problems, that PMD encountered while executing the rules.
219      * It can be parsing errors or exceptions during rule execution.
220      * Processing errors indicate a bug in PMD and the information provided help in
221      * reporting and fixing bugs in PMD.
222      *
223      * @since 3.9.0
224      */
225     @Parameter( property = "pmd.renderProcessingErrors", defaultValue = "true" )
226     private boolean renderProcessingErrors = true;
227 
228     /**
229      * Also render the rule priority into the HTML report.
230      *
231      * @since 3.10.0
232      */
233     @Parameter( property = "pmd.renderRuleViolationPriority", defaultValue = "true" )
234     private boolean renderRuleViolationPriority = true;
235 
236     @Component
237     private DependencyResolver dependencyResolver;
238 
239     @Parameter( defaultValue = "${session}", required = true, readonly = true )
240     private MavenSession session;
241 
242     /**
243      * {@inheritDoc}
244      */
245     @Override
246     public String getName( Locale locale )
247     {
248         return getBundle( locale ).getString( "report.pmd.name" );
249     }
250 
251     /**
252      * {@inheritDoc}
253      */
254     @Override
255     public String getDescription( Locale locale )
256     {
257         return getBundle( locale ).getString( "report.pmd.description" );
258     }
259 
260     /**
261      * Configures the PMD rulesets to be used directly.
262      * Note: Usually the rulesets are configured via the property.
263      *
264      * @param rulesets the PMD rulesets to be used.
265      * @see #rulesets
266      */
267     public void setRulesets( String[] rulesets )
268     {
269         this.rulesets = Arrays.copyOf( rulesets, rulesets.length );
270     }
271 
272     /**
273      * {@inheritDoc}
274      */
275     @Override
276     public void executeReport( Locale locale )
277         throws MavenReportException
278     {
279         try
280         {
281             execute( locale );
282         }
283         finally
284         {
285             if ( getSink() != null )
286             {
287                 getSink().close();
288             }
289         }
290     }
291 
292     private void execute( Locale locale )
293         throws MavenReportException
294     {
295         if ( !skip && canGenerateReport() )
296         {
297             ClassLoader origLoader = Thread.currentThread().getContextClassLoader();
298             try
299             {
300                 Thread.currentThread().setContextClassLoader( this.getClass().getClassLoader() );
301 
302                 Report report = generateReport( locale );
303 
304                 if ( !isHtml() && !isXml() )
305                 {
306                     writeNonHtml( report );
307                 }
308             }
309             finally
310             {
311                 Thread.currentThread().setContextClassLoader( origLoader );
312             }
313         }
314     }
315 
316     @Override
317     public boolean canGenerateReport()
318     {
319         if ( skip )
320         {
321             return false;
322         }
323 
324         boolean result = super.canGenerateReport();
325         if ( result )
326         {
327             try
328             {
329                 executePmdWithClassloader();
330                 if ( skipEmptyReport )
331                 {
332                     result = renderer.hasViolations();
333                     if ( result )
334                     {
335                         getLog().debug( "Skipping report since skipEmptyReport is true and"
336                                             + "there are no PMD violations." );
337                     }
338                 }
339             }
340             catch ( MavenReportException e )
341             {
342                 throw new RuntimeException( e );
343             }
344         }
345         return result;
346     }
347 
348     private void executePmdWithClassloader()
349         throws MavenReportException
350     {
351         ClassLoader origLoader = Thread.currentThread().getContextClassLoader();
352         try
353         {
354             Thread.currentThread().setContextClassLoader( this.getClass().getClassLoader() );
355             executePmd();
356         }
357         finally
358         {
359             Thread.currentThread().setContextClassLoader( origLoader );
360         }
361     }
362 
363     private void executePmd()
364         throws MavenReportException
365     {
366         setupPmdLogging();
367 
368         if ( renderer != null )
369         {
370             // PMD has already been run
371             getLog().debug( "PMD has already been run - skipping redundant execution." );
372             return;
373         }
374 
375         try
376         {
377             excludeFromFile.loadExcludeFromFailuresData( excludeFromFailureFile );
378         }
379         catch ( MojoExecutionException e )
380         {
381             throw new MavenReportException( "Unable to load exclusions", e );
382         }
383 
384         // configure ResourceManager
385         locator.addSearchPath( FileResourceLoader.ID, project.getFile().getParentFile().getAbsolutePath() );
386         locator.addSearchPath( "url", "" );
387         locator.setOutputDirectory( targetDirectory );
388 
389         renderer = new PmdCollectingRenderer();
390         PMDConfiguration pmdConfiguration = getPMDConfiguration();
391 
392         String[] sets = new String[rulesets.length];
393         try
394         {
395             for ( int idx = 0; idx < rulesets.length; idx++ )
396             {
397                 String set = rulesets[idx];
398                 getLog().debug( "Preparing ruleset: " + set );
399                 RuleSetReferenceId id = new RuleSetReferenceId( set );
400                 File ruleset = locator.getResourceAsFile( id.getRuleSetFileName(), getLocationTemp( set ) );
401                 if ( null == ruleset )
402                 {
403                     throw new MavenReportException( "Could not resolve " + set );
404                 }
405                 sets[idx] = ruleset.getAbsolutePath();
406             }
407         }
408         catch ( ResourceNotFoundException e )
409         {
410             throw new MavenReportException( e.getMessage(), e );
411         }
412         catch ( FileResourceCreationException e )
413         {
414             throw new MavenReportException( e.getMessage(), e );
415         }
416         pmdConfiguration.setRuleSets( StringUtils.join( sets, "," ) );
417 
418         try
419         {
420             if ( filesToProcess == null )
421             {
422                 filesToProcess = getFilesToProcess();
423             }
424 
425             if ( filesToProcess.isEmpty() && !"java".equals( language ) )
426             {
427                 getLog().warn( "No files found to process. Did you add your additional source folders like javascript?"
428                                    + " (see also build-helper-maven-plugin)" );
429             }
430         }
431         catch ( IOException e )
432         {
433             throw new MavenReportException( "Can't get file list", e );
434         }
435 
436         String encoding = getSourceEncoding();
437         if ( StringUtils.isEmpty( encoding ) )
438         {
439             encoding = ReaderFactory.FILE_ENCODING;
440             if ( !filesToProcess.isEmpty() )
441             {
442                 getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
443                                + ", i.e. build is platform dependent!" );
444             }
445         }
446         pmdConfiguration.setSourceEncoding( encoding );
447 
448         List<DataSource> dataSources = new ArrayList<>( filesToProcess.size() );
449         for ( File f : filesToProcess.keySet() )
450         {
451             dataSources.add( new FileDataSource( f ) );
452         }
453 
454         if ( sets.length > 0 )
455         {
456             processFilesWithPMD( pmdConfiguration, dataSources );
457         }
458         else
459         {
460             getLog().debug( "Skipping PMD execution as no rulesets are defined." );
461         }
462 
463         if ( renderer.hasErrors() )
464         {
465             if ( !skipPmdError )
466             {
467                 getLog().error( "PMD processing errors:" );
468                 getLog().error( renderer.getErrorsAsString( getLog().isDebugEnabled() ) );
469                 throw new MavenReportException( "Found " + renderer.getErrors().size() + " PMD processing errors" );
470             }
471             getLog().warn( "There are " + renderer.getErrors().size() + " PMD processing errors:" );
472             getLog().warn( renderer.getErrorsAsString( getLog().isDebugEnabled() ) );
473         }
474 
475         removeExcludedViolations( renderer.getViolations() );
476 
477         // if format is XML, we need to output it even if the file list is empty or we have no violations
478         // so the "check" goals can check for violations
479         if ( isXml() && renderer != null )
480         {
481             writeNonHtml( renderer.asReport() );
482         }
483 
484         if ( benchmark )
485         {
486             try ( PrintStream benchmarkFileStream = new PrintStream( benchmarkOutputFilename ) )
487             {
488                 ( new TextReport() ).generate( Benchmarker.values(), benchmarkFileStream );
489             }
490             catch ( FileNotFoundException fnfe )
491             {
492                 getLog().error( "Unable to generate benchmark file: " + benchmarkOutputFilename, fnfe );
493             }
494         }
495     }
496 
497     private void removeExcludedViolations( List<RuleViolation> violations )
498     {
499         getLog().debug( "Removing excluded violations. Using " + excludeFromFile.countExclusions()
500             + " configured exclusions." );
501         int violationsBefore = violations.size();
502 
503         Iterator<RuleViolation> iterator = violations.iterator();
504         while ( iterator.hasNext() )
505         {
506             RuleViolation rv = iterator.next();
507             if ( excludeFromFile.isExcludedFromFailure( rv ) )
508             {
509                 iterator.remove();
510             }
511         }
512 
513         int numberOfExcludedViolations = violationsBefore - violations.size();
514         getLog().debug( "Excluded " + numberOfExcludedViolations + " violations." );
515     }
516 
517     private void processFilesWithPMD( PMDConfiguration pmdConfiguration, List<DataSource> dataSources )
518             throws MavenReportException
519     {
520         RuleSetFactory ruleSetFactory = new RuleSetFactory( new ResourceLoader(),
521                 RulePriority.valueOf( this.minimumPriority ), true, true );
522         try
523         {
524             // load the ruleset once to log out any deprecated rules as warnings
525             ruleSetFactory.createRuleSets( pmdConfiguration.getRuleSets() );
526         }
527         catch ( RuleSetNotFoundException e1 )
528         {
529             throw new MavenReportException( "The ruleset could not be loaded", e1 );
530         }
531 
532         try
533         {
534             getLog().debug( "Executing PMD..." );
535             RuleContext ruleContext = new RuleContext();
536             PMD.processFiles( pmdConfiguration, ruleSetFactory, dataSources, ruleContext,
537                               Arrays.<Renderer>asList( renderer ) );
538 
539             if ( getLog().isDebugEnabled() )
540             {
541                 getLog().debug( "PMD finished. Found " + renderer.getViolations().size() + " violations." );
542             }
543         }
544         catch ( Exception e )
545         {
546             String message = "Failure executing PMD: " + e.getLocalizedMessage();
547             if ( !skipPmdError )
548             {
549                 throw new MavenReportException( message, e );
550             }
551             getLog().warn( message, e );
552         }
553     }
554 
555     private Report generateReport( Locale locale )
556         throws MavenReportException
557     {
558         Sink sink = getSink();
559         PmdReportGenerator doxiaRenderer = new PmdReportGenerator( getLog(), sink, getBundle( locale ), aggregate );
560         doxiaRenderer.setRenderRuleViolationPriority( renderRuleViolationPriority );
561         doxiaRenderer.setFiles( filesToProcess );
562         doxiaRenderer.setViolations( renderer.getViolations() );
563         if ( renderProcessingErrors )
564         {
565             doxiaRenderer.setProcessingErrors( renderer.getErrors() );
566         }
567 
568         try
569         {
570             doxiaRenderer.beginDocument();
571             doxiaRenderer.render();
572             doxiaRenderer.endDocument();
573         }
574         catch ( IOException e )
575         {
576             getLog().warn( "Failure creating the report: " + e.getLocalizedMessage(), e );
577         }
578 
579         return renderer.asReport();
580     }
581 
582     /**
583      * Convenience method to get the location of the specified file name.
584      *
585      * @param name the name of the file whose location is to be resolved
586      * @return a String that contains the absolute file name of the file
587      */
588     protected String getLocationTemp( String name )
589     {
590         String loc = name;
591         if ( loc.indexOf( '/' ) != -1 )
592         {
593             loc = loc.substring( loc.lastIndexOf( '/' ) + 1 );
594         }
595         if ( loc.indexOf( '\\' ) != -1 )
596         {
597             loc = loc.substring( loc.lastIndexOf( '\\' ) + 1 );
598         }
599 
600         // MPMD-127 in the case that the rules are defined externally on a url
601         // we need to replace some special url characters that cannot be
602         // used in filenames on disk or produce ackward filenames.
603         // replace all occurrences of the following characters: ? : & = %
604         loc = loc.replaceAll( "[\\?\\:\\&\\=\\%]", "_" );
605 
606         if ( !loc.endsWith( ".xml" ) )
607         {
608             loc = loc + ".xml";
609         }
610 
611         getLog().debug( "Before: " + name + " After: " + loc );
612         return loc;
613     }
614 
615     /**
616      * Use the PMD renderers to render in any format aside from HTML.
617      *
618      * @param report
619      * @throws MavenReportException
620      */
621     private void writeNonHtml( Report report )
622         throws MavenReportException
623     {
624         Renderer r = createRenderer();
625 
626         if ( r == null )
627         {
628             return;
629         }
630 
631         File targetFile = new File( targetDirectory, "pmd." + format );
632         try ( Writer writer = new OutputStreamWriter( new FileOutputStream( targetFile ), getOutputEncoding() ) )
633         {
634             targetDirectory.mkdirs();
635 
636             r.setWriter( writer );
637             r.start();
638             r.renderFileReport( report );
639             r.end();
640             r.flush();
641 
642             if ( includeXmlInSite )
643             {
644                 File siteDir = getReportOutputDirectory();
645                 siteDir.mkdirs();
646                 FileUtils.copyFile( targetFile, new File( siteDir, "pmd." + format ) );
647             }
648         }
649         catch ( IOException ioe )
650         {
651             throw new MavenReportException( ioe.getMessage(), ioe );
652         }
653     }
654 
655     /**
656      * Constructs the PMD configuration class, passing it an argument that configures the target JDK.
657      *
658      * @return the resulting PMD
659      * @throws org.apache.maven.reporting.MavenReportException if targetJdk is not supported
660      */
661     public PMDConfiguration getPMDConfiguration()
662         throws MavenReportException
663     {
664         PMDConfiguration configuration = new PMDConfiguration();
665         LanguageVersion languageVersion = null;
666 
667         if ( ( "java".equals( language ) || null == language ) && null != targetJdk )
668         {
669             languageVersion = LanguageRegistry.findLanguageVersionByTerseName( "java " + targetJdk );
670             if ( languageVersion == null )
671             {
672                 throw new MavenReportException( "Unsupported targetJdk value '" + targetJdk + "'." );
673             }
674         }
675         else if ( "javascript".equals( language ) || "ecmascript".equals( language ) )
676         {
677             languageVersion = LanguageRegistry.findLanguageVersionByTerseName( "ecmascript" );
678         }
679         else if ( "jsp".equals( language ) )
680         {
681             languageVersion = LanguageRegistry.findLanguageVersionByTerseName( "jsp" );
682         }
683 
684         if ( languageVersion != null )
685         {
686             getLog().debug( "Using language " + languageVersion );
687             configuration.setDefaultLanguageVersion( languageVersion );
688         }
689 
690         if ( typeResolution )
691         {
692             configureTypeResolution( configuration );
693         }
694 
695         if ( null != suppressMarker )
696         {
697             configuration.setSuppressMarker( suppressMarker );
698         }
699 
700         configuration.setBenchmark( benchmark );
701 
702         if ( analysisCache )
703         {
704             configuration.setAnalysisCacheLocation( analysisCacheLocation );
705             getLog().debug( "Using analysis cache location: " + analysisCacheLocation );
706         }
707         else
708         {
709             configuration.setIgnoreIncrementalAnalysis( true );
710         }
711 
712         return configuration;
713     }
714 
715     private void configureTypeResolution( PMDConfiguration configuration ) throws MavenReportException
716     {
717         try
718         {
719             List<String> classpath = new ArrayList<>();
720             if ( aggregate )
721             {
722                 List<String> dependencies = new ArrayList<>();
723 
724                 for ( MavenProject localProject : reactorProjects )
725                 {
726                     // Add the project's target folder first
727                     classpath.addAll( includeTests ? localProject.getTestClasspathElements()
728                             : localProject.getCompileClasspathElements() );
729 
730                     ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest(
731                             session.getProjectBuildingRequest() );
732 
733                     Iterable<ArtifactResult> resolvedDependencies = dependencyResolver.resolveDependencies(
734                             buildingRequest, localProject.getModel(),
735                             includeTests ? ScopeFilter.including( "test" ) : ScopeFilter.including( "compile" ) );
736 
737                     for ( ArtifactResult resolvedArtifact : resolvedDependencies )
738                     {
739                         dependencies.add( resolvedArtifact.getArtifact().getFile().toString() );
740                     }
741 
742                 }
743 
744                 // Add the dependencies as last entries
745                 classpath.addAll( dependencies );
746 
747                 getLog().debug( "Using aggregated aux classpath: " + classpath );
748             }
749             else
750             {
751                 classpath.addAll( includeTests ? project.getTestClasspathElements()
752                         : project.getCompileClasspathElements() );
753                 getLog().debug( "Using aux classpath: " + classpath );
754             }
755             String path = StringUtils.join( classpath.iterator(), File.pathSeparator );
756             configuration.prependClasspath( path );
757         }
758         catch ( Exception e )
759         {
760             throw new MavenReportException( e.getMessage(), e );
761         }
762     }
763 
764     /**
765      * {@inheritDoc}
766      */
767     @Override
768     public String getOutputName()
769     {
770         return "pmd";
771     }
772 
773     private static ResourceBundle getBundle( Locale locale )
774     {
775         return ResourceBundle.getBundle( "pmd-report", locale, PmdReport.class.getClassLoader() );
776     }
777 
778     /**
779      * Create and return the correct renderer for the output type.
780      *
781      * @return the renderer based on the configured output
782      * @throws org.apache.maven.reporting.MavenReportException if no renderer found for the output type
783      */
784     public final Renderer createRenderer()
785         throws MavenReportException
786     {
787         Renderer result = null;
788         if ( "xml".equals( format ) )
789         {
790             result = new XMLRenderer( getOutputEncoding() );
791         }
792         else if ( "txt".equals( format ) )
793         {
794             result = new TextRenderer();
795         }
796         else if ( "csv".equals( format ) )
797         {
798             result = new CSVRenderer();
799         }
800         else if ( "html".equals( format ) )
801         {
802             result = new HTMLRenderer();
803         }
804         else if ( !"".equals( format ) && !"none".equals( format ) )
805         {
806             try
807             {
808                 result = (Renderer) Class.forName( format ).getConstructor( Properties.class ).
809                                 newInstance( new Properties() );
810             }
811             catch ( Exception e )
812             {
813                 throw new MavenReportException( "Can't find PMD custom format " + format + ": "
814                     + e.getClass().getName(), e );
815             }
816         }
817 
818         return result;
819     }
820 }