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 }