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