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 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.LinkedHashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.TreeMap;
32
33 import net.sourceforge.pmd.PMD;
34
35 import org.apache.maven.doxia.siterenderer.Renderer;
36 import org.apache.maven.model.ReportPlugin;
37 import org.apache.maven.plugins.annotations.Component;
38 import org.apache.maven.plugins.annotations.Parameter;
39 import org.apache.maven.project.MavenProject;
40 import org.apache.maven.reporting.AbstractMavenReport;
41 import org.codehaus.plexus.util.FileUtils;
42 import org.codehaus.plexus.util.PathTool;
43 import org.codehaus.plexus.util.ReaderFactory;
44 import org.codehaus.plexus.util.StringUtils;
45
46
47
48
49
50
51
52 public abstract class AbstractPmdReport
53 extends AbstractMavenReport
54 {
55
56
57
58 @Parameter( property = "project.build.directory", required = true )
59 protected File targetDirectory;
60
61
62
63
64
65
66 @Parameter( property = "project.reporting.outputDirectory", required = true )
67 protected File outputDirectory;
68
69
70
71
72 @Component
73 private Renderer siteRenderer;
74
75
76
77
78 @Parameter( defaultValue = "${project}", readonly = true, required = true )
79 protected MavenProject project;
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 @Parameter( defaultValue = "false" )
192 protected boolean includeXmlInSite;
193
194
195
196
197
198
199
200 @Parameter( defaultValue = "true" )
201 protected boolean skipEmptyReport;
202
203
204 protected Map<File, PmdFileInfo> filesToProcess;
205
206
207
208
209 @Override
210 protected MavenProject getProject()
211 {
212 return project;
213 }
214
215
216
217
218 @Override
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" )
247 List<ReportPlugin> reportPlugins = project.getReportPlugins();
248 for ( ReportPlugin plugin : reportPlugins )
249 {
250 String artifactId = plugin.getArtifactId();
251 if ( "maven-jxr-plugin".equals( artifactId ) || "jxr-maven-plugin".equals( artifactId ) )
252 {
253 location = relativePath;
254 }
255 }
256 }
257
258 if ( location == null )
259 {
260 getLog().warn( "Unable to locate Source XRef to link to - DISABLED" );
261 }
262 }
263 return location;
264 }
265
266
267
268
269
270
271
272 protected Map<File, PmdFileInfo> getFilesToProcess()
273 throws IOException
274 {
275 if ( aggregate && !project.isExecutionRoot() )
276 {
277 return Collections.emptyMap();
278 }
279
280 if ( excludeRoots == null )
281 {
282 excludeRoots = new File[0];
283 }
284
285 Collection<File> excludeRootFiles = new HashSet<File>( excludeRoots.length );
286
287 for ( File file : excludeRoots )
288 {
289 if ( file.isDirectory() )
290 {
291 excludeRootFiles.add( file );
292 }
293 }
294
295 List<PmdFileInfo> directories = new ArrayList<PmdFileInfo>();
296
297 if ( compileSourceRoots != null )
298 {
299 for ( String root : compileSourceRoots )
300 {
301 File sroot = new File( root );
302 if ( sroot.exists() )
303 {
304 String sourceXref = constructXRefLocation( false );
305 directories.add( new PmdFileInfo( project, sroot, sourceXref ) );
306 }
307 }
308
309 }
310 if ( includeTests )
311 {
312 if ( testSourceRoots != null )
313 {
314 for ( String root : testSourceRoots )
315 {
316 File sroot = new File( root );
317 if ( sroot.exists() )
318 {
319 String testXref = constructXRefLocation( true );
320 directories.add( new PmdFileInfo( project, sroot, testXref ) );
321 }
322 }
323 }
324 }
325 if ( aggregate )
326 {
327 for ( MavenProject localProject : reactorProjects )
328 {
329 @SuppressWarnings( "unchecked" )
330 List<String> localCompileSourceRoots = localProject.getCompileSourceRoots();
331 for ( String root : localCompileSourceRoots )
332 {
333 File sroot = new File( root );
334 if ( sroot.exists() )
335 {
336 String sourceXref = constructXRefLocation( false );
337 directories.add( new PmdFileInfo( localProject, sroot, sourceXref ) );
338 }
339 }
340 if ( includeTests )
341 {
342 @SuppressWarnings( "unchecked" )
343 List<String> localTestCompileSourceRoots = localProject.getTestCompileSourceRoots();
344 for ( String root : localTestCompileSourceRoots )
345 {
346 File sroot = new File( root );
347 if ( sroot.exists() )
348 {
349 String testXref = constructXRefLocation( true );
350 directories.add( new PmdFileInfo( localProject, sroot, testXref ) );
351 }
352 }
353 }
354 }
355
356 }
357
358 String excluding = getExcludes();
359 getLog().debug( "Exclusions: " + excluding );
360 String including = getIncludes();
361 getLog().debug( "Inclusions: " + including );
362
363 Map<File, PmdFileInfo> files = new TreeMap<File, PmdFileInfo>();
364
365 for ( PmdFileInfo finfo : directories )
366 {
367 getLog().debug( "Searching for files in directory " + finfo.getSourceDirectory().toString() );
368 File sourceDirectory = finfo.getSourceDirectory();
369 if ( sourceDirectory.isDirectory() && !excludeRootFiles.contains( sourceDirectory ) )
370 {
371 List<File> newfiles = 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 Collection<String> patterns = new LinkedHashSet<String>( FileUtils.getDefaultExcludesAsList() );
409 if ( excludes != null )
410 {
411 patterns.addAll( excludes );
412 }
413 return StringUtils.join( patterns.iterator(), "," );
414 }
415
416 protected boolean isHtml()
417 {
418 return "html".equals( format );
419 }
420
421 protected boolean isXml()
422 {
423 return "xml".equals( format );
424 }
425
426
427
428
429 @Override
430 public boolean canGenerateReport()
431 {
432 if ( aggregate && !project.isExecutionRoot() )
433 {
434 return false;
435 }
436
437 if ( "pom".equals( project.getPackaging() ) && !aggregate )
438 {
439 return false;
440 }
441
442
443
444 if ( isXml() )
445 {
446 return true;
447 }
448 try
449 {
450 filesToProcess = getFilesToProcess();
451 if ( filesToProcess.isEmpty() )
452 {
453 return false;
454 }
455 }
456 catch ( IOException e )
457 {
458 getLog().error( e );
459 }
460 return true;
461 }
462
463
464
465
466 @Override
467 protected String getOutputDirectory()
468 {
469 return outputDirectory.getAbsolutePath();
470 }
471
472 protected String getSourceEncoding()
473 {
474 return sourceEncoding;
475 }
476
477
478
479
480
481
482
483 protected String getOutputEncoding()
484 {
485 return ( outputEncoding != null ) ? outputEncoding : ReaderFactory.UTF_8;
486 }
487
488 static String getPmdVersion()
489 {
490 try
491 {
492 return (String) PMD.class.getField( "VERSION" ).get( null );
493 }
494 catch ( IllegalAccessException e )
495 {
496 throw new RuntimeException( "PMD VERSION field not accessible", e );
497 }
498 catch ( NoSuchFieldException e )
499 {
500 throw new RuntimeException( "PMD VERSION field not found", e );
501 }
502 }
503 }