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