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