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