1 package org.apache.maven.plugin.pmd;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import net.sourceforge.pmd.PMD;
23 import org.apache.maven.doxia.siterenderer.Renderer;
24 import org.apache.maven.model.ReportPlugin;
25 import org.apache.maven.plugins.annotations.Component;
26 import org.apache.maven.plugins.annotations.Parameter;
27 import org.apache.maven.project.MavenProject;
28 import org.apache.maven.reporting.AbstractMavenReport;
29 import org.codehaus.plexus.util.FileUtils;
30 import org.codehaus.plexus.util.PathTool;
31 import org.codehaus.plexus.util.ReaderFactory;
32 import org.codehaus.plexus.util.StringUtils;
33
34 import java.io.File;
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.Collection;
38 import java.util.Collections;
39 import java.util.HashSet;
40 import java.util.LinkedHashSet;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.TreeMap;
44
45
46
47
48
49
50
51 public abstract class AbstractPmdReport
52 extends AbstractMavenReport
53 {
54
55
56
57 @Parameter( property = "project.build.directory", required = true )
58 protected File targetDirectory;
59
60
61
62
63
64
65 @Parameter( property = "project.reporting.outputDirectory", required = true )
66 protected File outputDirectory;
67
68
69
70
71 @Component
72 private Renderer siteRenderer;
73
74
75
76
77 @Component
78 protected MavenProject project;
79
80
81
82
83
84
85
86 @Parameter( property = "format", defaultValue = "xml" )
87 protected String format = "xml";
88
89
90
91
92
93 @Parameter( property = "linkXRef", defaultValue = "true" )
94 private boolean linkXRef;
95
96
97
98
99 @Parameter( defaultValue = "${project.reporting.outputDirectory}/xref" )
100 private File xrefLocation;
101
102
103
104
105 @Parameter( defaultValue = "${project.reporting.outputDirectory}/xref-test" )
106 private File xrefTestLocation;
107
108
109
110
111
112
113
114
115
116 @Parameter
117 private List<String> excludes;
118
119
120
121
122
123
124
125 @Parameter
126 private List<String> includes;
127
128
129
130
131 @Parameter( property = "project.compileSourceRoots", required = true, readonly = true )
132 private List<String> compileSourceRoots;
133
134
135
136
137 @Parameter( property = "project.testCompileSourceRoots", required = true, readonly = true )
138 private List<String> testSourceRoots;
139
140
141
142
143
144
145 @Parameter
146 private File[] excludeRoots;
147
148
149
150
151
152
153 @Parameter( defaultValue = "false" )
154 protected boolean includeTests;
155
156
157
158
159
160
161 @Parameter( property = "aggregate", defaultValue = "false" )
162 protected boolean aggregate;
163
164
165
166
167
168
169 @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
170 private String sourceEncoding;
171
172
173
174
175
176
177 @Parameter( property = "outputEncoding", defaultValue = "${project.reporting.outputEncoding}" )
178 private String outputEncoding;
179
180
181
182
183 @Parameter( property = "reactorProjects", readonly = true )
184 protected List<MavenProject> reactorProjects;
185
186
187
188
189
190
191
192
193 @Parameter( defaultValue = "false" )
194 protected boolean includeXmlInSite;
195
196
197
198
199
200
201
202 @Parameter( defaultValue = "true" )
203 protected boolean skipEmptyReport;
204
205
206 protected Map<File, PmdFileInfo> filesToProcess;
207
208
209
210
211 protected MavenProject getProject()
212 {
213 return project;
214 }
215
216
217
218
219 protected Renderer getSiteRenderer()
220 {
221 return siteRenderer;
222 }
223
224 protected String constructXRefLocation( boolean test )
225 {
226 String location = null;
227 if ( linkXRef )
228 {
229 File xrefLoc = test ? xrefTestLocation : xrefLocation;
230
231 String relativePath =
232 PathTool.getRelativePath( outputDirectory.getAbsolutePath(), xrefLoc.getAbsolutePath() );
233 if ( StringUtils.isEmpty( relativePath ) )
234 {
235 relativePath = ".";
236 }
237 relativePath = relativePath + "/" + xrefLoc.getName();
238 if ( xrefLoc.exists() )
239 {
240
241 location = relativePath;
242 }
243 else
244 {
245
246 @SuppressWarnings( "unchecked" ) List<ReportPlugin> reportPlugins = project.getReportPlugins();
247 for ( ReportPlugin plugin : reportPlugins )
248 {
249 String artifactId = plugin.getArtifactId();
250 if ( "maven-jxr-plugin".equals( artifactId ) || "jxr-maven-plugin".equals( artifactId ) )
251 {
252 location = relativePath;
253 }
254 }
255 }
256
257 if ( location == null )
258 {
259 getLog().warn( "Unable to locate Source XRef to link to - DISABLED" );
260 }
261 }
262 return location;
263 }
264
265
266
267
268
269
270
271 protected Map<File, PmdFileInfo> getFilesToProcess()
272 throws IOException
273 {
274 if ( aggregate && !project.isExecutionRoot() )
275 {
276 return Collections.emptyMap();
277 }
278
279 if ( excludeRoots == null )
280 {
281 excludeRoots = new File[0];
282 }
283
284 Collection<File> excludeRootFiles = new HashSet<File>( excludeRoots.length );
285
286 for ( File file : excludeRoots )
287 {
288 if ( file.isDirectory() )
289 {
290 excludeRootFiles.add( file );
291 }
292 }
293
294 List<PmdFileInfo> directories = new ArrayList<PmdFileInfo>();
295
296 if ( compileSourceRoots != null )
297 {
298 for ( String root : compileSourceRoots )
299 {
300 File sroot = new File( root );
301 if ( sroot.exists() )
302 {
303 String sourceXref = constructXRefLocation( false );
304 directories.add( new PmdFileInfo( project, sroot, sourceXref ) );
305 }
306 }
307
308 }
309 if ( includeTests )
310 {
311 if ( testSourceRoots != null )
312 {
313 for ( String root : testSourceRoots )
314 {
315 File sroot = new File( root );
316 if ( sroot.exists() )
317 {
318 String testXref = constructXRefLocation( true );
319 directories.add( new PmdFileInfo( project, sroot, testXref ) );
320 }
321 }
322 }
323 }
324 if ( aggregate )
325 {
326 for ( MavenProject localProject : reactorProjects )
327 {
328 @SuppressWarnings( "unchecked" ) List<String> localCompileSourceRoots =
329 localProject.getCompileSourceRoots();
330 for ( String root : localCompileSourceRoots )
331 {
332 File sroot = new File( root );
333 if ( sroot.exists() )
334 {
335 String sourceXref = constructXRefLocation( false );
336 directories.add( new PmdFileInfo( localProject, sroot, sourceXref ) );
337 }
338 }
339 if ( includeTests )
340 {
341 @SuppressWarnings( "unchecked" ) List<String> localTestCompileSourceRoots =
342 localProject.getTestCompileSourceRoots();
343 for ( String root : localTestCompileSourceRoots )
344 {
345 File sroot = new File( root );
346 if ( sroot.exists() )
347 {
348 String testXref = constructXRefLocation( true );
349 directories.add( new PmdFileInfo( localProject, sroot, testXref ) );
350 }
351 }
352 }
353 }
354
355 }
356
357 String excluding = getExcludes();
358 getLog().debug( "Exclusions: " + excluding );
359 String including = getIncludes();
360 getLog().debug( "Inclusions: " + including );
361
362 Map<File, PmdFileInfo> files = new TreeMap<File, PmdFileInfo>();
363
364 for ( PmdFileInfo finfo : directories )
365 {
366 getLog().debug( "Searching for files in directory " + finfo.getSourceDirectory().toString() );
367 File sourceDirectory = finfo.getSourceDirectory();
368 if ( sourceDirectory.isDirectory() && !excludeRootFiles.contains( sourceDirectory ) )
369 {
370 @SuppressWarnings( "unchecked" ) List<File> newfiles =
371 FileUtils.getFiles( sourceDirectory, including, excluding );
372 for ( File newfile : newfiles )
373 {
374 files.put( newfile.getCanonicalFile(), finfo );
375 }
376 }
377 }
378
379 return files;
380 }
381
382
383
384
385
386
387 private String getIncludes()
388 {
389 Collection<String> patterns = new LinkedHashSet<String>();
390 if ( includes != null )
391 {
392 patterns.addAll( includes );
393 }
394 if ( patterns.isEmpty() )
395 {
396 patterns.add( "**/*.java" );
397 }
398 return StringUtils.join( patterns.iterator(), "," );
399 }
400
401
402
403
404
405
406 private String getExcludes()
407 {
408 @SuppressWarnings( "unchecked" ) Collection<String> patterns =
409 new LinkedHashSet<String>( FileUtils.getDefaultExcludesAsList() );
410 if ( excludes != null )
411 {
412 patterns.addAll( excludes );
413 }
414 return StringUtils.join( patterns.iterator(), "," );
415 }
416
417 protected boolean isHtml()
418 {
419 return "html".equals( format );
420 }
421 protected boolean isXml()
422 {
423 return "xml".equals( format );
424 }
425
426
427
428
429 public boolean canGenerateReport()
430 {
431 if ( aggregate && !project.isExecutionRoot() )
432 {
433 return false;
434 }
435
436 if ( "pom".equals( project.getPackaging() ) && !aggregate )
437 {
438 return false;
439 }
440
441
442
443 if ( isXml() )
444 {
445 return true;
446 }
447 try
448 {
449 filesToProcess = getFilesToProcess();
450 if ( filesToProcess.isEmpty() )
451 {
452 return false;
453 }
454 }
455 catch ( IOException e )
456 {
457 getLog().error( e );
458 }
459 return true;
460 }
461
462
463
464
465 protected String getOutputDirectory()
466 {
467 return outputDirectory.getAbsolutePath();
468 }
469
470 protected String getSourceEncoding()
471 {
472 return sourceEncoding;
473 }
474
475
476
477
478
479
480
481 protected String getOutputEncoding()
482 {
483 return ( outputEncoding != null ) ? outputEncoding : ReaderFactory.UTF_8;
484 }
485
486 static String getPmdVersion()
487 {
488 try
489 {
490 return (String) PMD.class.getField( "VERSION" ).get( null );
491 }
492 catch ( IllegalAccessException e )
493 {
494 throw new RuntimeException( "PMD VERSION field not accessible", e );
495 }
496 catch ( NoSuchFieldException e )
497 {
498 throw new RuntimeException( "PMD VERSION field not found", e );
499 }
500 }
501 }