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