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