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