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