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