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 tagName, final String key, 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 getLog().info("PMD version: " + AbstractPmdReport.getPmdVersion());
138
139 try {
140 final ViolationDetails<D> violations = getViolations(outputFile, failurePriority);
141
142 final List<D> failures = violations.getFailureDetails();
143 final List<D> warnings = violations.getWarningDetails();
144
145 if (verbose) {
146 printErrors(failures, warnings);
147 }
148
149 final int failureCount = failures.size();
150 final int warningCount = warnings.size();
151
152 final String message = getMessage(failureCount, warningCount, key, outputFile);
153
154 getLog().debug("PMD failureCount: " + failureCount + ", warningCount: " + warningCount);
155
156 if (failureCount > getMaxAllowedViolations() && isFailOnViolation()) {
157 throw new MojoFailureException(message);
158 }
159
160 this.getLog().info(message);
161
162 if (failureCount > 0 && isFailOnViolation() && failureCount <= getMaxAllowedViolations()) {
163 this.getLog()
164 .info("The build is not failed, since " + getMaxAllowedViolations()
165 + " violations are allowed (maxAllowedViolations).");
166 }
167 } catch (final IOException | XmlPullParserException e) {
168 throw new MojoExecutionException("Unable to read PMD results xml: " + outputFile.getAbsolutePath(), e);
169 }
170 } else {
171 throw new MojoFailureException("Unable to perform check, " + "unable to find " + outputFile);
172 }
173 }
174
175
176
177
178
179
180
181
182
183
184 private ViolationDetails<D> getViolations(final File analysisFile, final int failurePriority)
185 throws XmlPullParserException, IOException {
186 final List<D> failures = new ArrayList<>();
187 final List<D> warnings = new ArrayList<>();
188
189 final List<D> violations = getErrorDetails(analysisFile);
190
191 for (final D violation : violations) {
192 final int priority = getPriority(violation);
193 if (priority <= failurePriority && !excludeFromFile.isExcludedFromFailure(violation)) {
194 failures.add(violation);
195 if (printFailingErrors) {
196 printError(violation, "Failure");
197 }
198 } else {
199 warnings.add(violation);
200 }
201 }
202
203 final ViolationDetails<D> details = newViolationDetailsInstance();
204 details.setFailureDetails(failures);
205 details.setWarningDetails(warnings);
206 return details;
207 }
208
209 protected abstract int getPriority(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 for (final D warning : warnings) {
221 printError(warning, "Warning");
222 }
223
224 for (final D failure : failures) {
225 printError(failure, "Failure");
226 }
227 }
228
229
230
231
232
233
234
235
236
237
238 private String getMessage(final int failureCount, final int warningCount, final String key, final File outputFile) {
239 final StringBuilder message = new StringBuilder(256);
240 if (failureCount > 0 || warningCount > 0) {
241 if (failureCount > 0) {
242 message.append("You have ")
243 .append(failureCount)
244 .append(" ")
245 .append(key)
246 .append(failureCount > 1 ? "s" : "");
247 }
248
249 if (warningCount > 0) {
250 if (failureCount > 0) {
251 message.append(" and ");
252 } else {
253 message.append("You have ");
254 }
255 message.append(warningCount).append(" warning").append(warningCount > 1 ? "s" : "");
256 }
257
258 message.append(". For more details see: ").append(outputFile.getAbsolutePath());
259 }
260 return message.toString();
261 }
262
263
264
265
266
267
268
269
270 protected abstract void printError(D item, String severity);
271
272
273
274
275
276
277
278
279
280
281 protected abstract List<D> getErrorDetails(File analysisFile) throws XmlPullParserException, IOException;
282
283 public boolean isFailOnViolation() {
284 return failOnViolation;
285 }
286
287 public Integer getMaxAllowedViolations() {
288 return maxAllowedViolations;
289 }
290
291 protected boolean isAggregator() {
292
293 return aggregate;
294 }
295 }