1 package org.apache.maven.plugins.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.List;
26
27 import org.apache.maven.plugin.AbstractMojo;
28 import org.apache.maven.plugin.MojoExecutionException;
29 import org.apache.maven.plugin.MojoFailureException;
30 import org.apache.maven.plugins.annotations.Parameter;
31 import org.apache.maven.project.MavenProject;
32 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
33
34
35
36
37
38
39
40
41
42 public abstract class AbstractPmdViolationCheckMojo<D>
43 extends AbstractMojo
44 {
45
46
47
48 @Parameter( property = "project.build.directory", required = true )
49 private File targetDirectory;
50
51
52
53
54
55
56 @Parameter( property = "pmd.failOnViolation", defaultValue = "true", required = true )
57 protected boolean failOnViolation;
58
59
60
61
62
63
64
65
66 @Parameter( property = "aggregate", defaultValue = "false" )
67 @Deprecated
68 protected boolean aggregate;
69
70
71
72
73 @Parameter( property = "pmd.verbose", defaultValue = "false" )
74 private boolean verbose;
75
76
77
78
79
80
81 @Parameter( property = "pmd.printFailingErrors", defaultValue = "false" )
82 private boolean printFailingErrors;
83
84
85
86
87
88
89
90
91
92 @Parameter( property = "pmd.excludeFromFailureFile", defaultValue = "" )
93 private String excludeFromFailureFile;
94
95
96
97
98
99
100
101
102
103
104
105 @Parameter( property = "pmd.maxAllowedViolations", defaultValue = "0" )
106 private int maxAllowedViolations;
107
108
109 private final ExcludeFromFile<D> excludeFromFile;
110
111
112
113
114
115 protected AbstractPmdViolationCheckMojo( ExcludeFromFile<D> excludeFromFile )
116 {
117 this.excludeFromFile = excludeFromFile;
118 }
119
120
121
122
123 @Parameter( defaultValue = "${project}", readonly = true, required = true )
124 protected MavenProject project;
125
126 protected void executeCheck( final String filename, final String tagName, final String key,
127 final int failurePriority )
128 throws MojoFailureException, MojoExecutionException
129 {
130 if ( aggregate && !project.isExecutionRoot() )
131 {
132 return;
133 }
134
135 if ( !isAggregator() && "pom".equalsIgnoreCase( project.getPackaging() ) )
136 {
137 return;
138 }
139
140 excludeFromFile.loadExcludeFromFailuresData( excludeFromFailureFile );
141 final File outputFile = new File( targetDirectory, filename );
142
143 if ( outputFile.exists() )
144 {
145 getLog().info( "PMD version: " + AbstractPmdReport.getPmdVersion() );
146
147 try
148 {
149 final ViolationDetails<D> violations = getViolations( outputFile, failurePriority );
150
151 final List<D> failures = violations.getFailureDetails();
152 final List<D> warnings = violations.getWarningDetails();
153
154 if ( verbose )
155 {
156 printErrors( failures, warnings );
157 }
158
159 final int failureCount = failures.size();
160 final int warningCount = warnings.size();
161
162 final String message = getMessage( failureCount, warningCount, key, outputFile );
163
164 getLog().debug( "PMD failureCount: " + failureCount + ", warningCount: " + warningCount );
165
166 if ( failureCount > getMaxAllowedViolations() && isFailOnViolation() )
167 {
168 throw new MojoFailureException( message );
169 }
170
171 this.getLog().info( message );
172
173 if ( failureCount > 0 && isFailOnViolation() && failureCount <= getMaxAllowedViolations() )
174 {
175 this.getLog().info( "The build is not failed, since " + getMaxAllowedViolations()
176 + " violations are allowed (maxAllowedViolations)." );
177 }
178 }
179 catch ( final IOException | XmlPullParserException e )
180 {
181 throw new MojoExecutionException(
182 "Unable to read PMD results xml: " + outputFile.getAbsolutePath(),
183 e );
184 }
185 }
186 else
187 {
188 throw new MojoFailureException( "Unable to perform check, " + "unable to find " + outputFile );
189 }
190 }
191
192
193
194
195
196
197
198
199
200
201 private ViolationDetails<D> getViolations( final File analysisFile, final int failurePriority )
202 throws XmlPullParserException, IOException
203 {
204 final List<D> failures = new ArrayList<>();
205 final List<D> warnings = new ArrayList<>();
206
207 final List<D> violations = getErrorDetails( analysisFile );
208
209 for ( final D violation : violations )
210 {
211 final int priority = getPriority( violation );
212 if ( priority <= failurePriority && !excludeFromFile.isExcludedFromFailure( violation ) )
213 {
214 failures.add( violation );
215 if ( printFailingErrors )
216 {
217 printError( violation, "Failure" );
218 }
219 }
220 else
221 {
222 warnings.add( violation );
223 }
224 }
225
226 final ViolationDetails<D> details = newViolationDetailsInstance();
227 details.setFailureDetails( failures );
228 details.setWarningDetails( warnings );
229 return details;
230 }
231
232 protected abstract int getPriority( D errorDetail );
233
234 protected abstract ViolationDetails<D> newViolationDetailsInstance();
235
236
237
238
239
240
241
242 protected void printErrors( final List<D> failures, final List<D> warnings )
243 {
244 for ( final D warning : warnings )
245 {
246 printError( warning, "Warning" );
247 }
248
249 for ( final D failure : failures )
250 {
251 printError( failure, "Failure" );
252 }
253 }
254
255
256
257
258
259
260
261
262
263
264 private String getMessage( final int failureCount, final int warningCount, final String key, final File outputFile )
265 {
266 final StringBuilder message = new StringBuilder( 256 );
267 if ( failureCount > 0 || warningCount > 0 )
268 {
269 if ( failureCount > 0 )
270 {
271 message.append( "You have " ).append( failureCount ).append( " " ).append( key ).
272 append( failureCount > 1 ? "s" : "" );
273 }
274
275 if ( warningCount > 0 )
276 {
277 if ( failureCount > 0 )
278 {
279 message.append( " and " );
280 }
281 else
282 {
283 message.append( "You have " );
284 }
285 message.append( warningCount ).append( " warning" ).append( warningCount > 1 ? "s" : "" );
286 }
287
288 message.append( ". For more details see: " ).append( outputFile.getAbsolutePath() );
289 }
290 return message.toString();
291 }
292
293
294
295
296
297
298
299
300 protected abstract void printError( D item, String severity );
301
302
303
304
305
306
307
308
309
310
311 protected abstract List<D> getErrorDetails( File analysisFile )
312 throws XmlPullParserException, IOException;
313
314 public boolean isFailOnViolation()
315 {
316 return failOnViolation;
317 }
318
319 public Integer getMaxAllowedViolations()
320 {
321 return maxAllowedViolations;
322 }
323
324 protected boolean isAggregator()
325 {
326
327 return aggregate;
328 }
329 }