1   package org.apache.maven.plugins.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.xml.pull.XmlPullParserException;
33  
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  
55  
56      @Parameter( property = "pmd.failOnViolation", defaultValue = "true", required = true )
57      protected boolean failOnViolation;
58  
59      
60  
61  
62  
63  
64  
65  
66      @Parameter( property = "aggregate", defaultValue = "false" )
67      @Deprecated
68      protected boolean aggregate;
69  
70      
71  
72  
73      @Parameter( property = "pmd.verbose", defaultValue = "false" )
74      private boolean verbose;
75  
76      
77  
78  
79  
80  
81      @Parameter( property = "pmd.printFailingErrors", defaultValue = "false" )
82      private boolean printFailingErrors;
83  
84      
85  
86  
87  
88  
89  
90  
91  
92      @Parameter( property = "pmd.excludeFromFailureFile", defaultValue = "" )
93      private String excludeFromFailureFile;
94  
95      
96  
97  
98  
99  
100 
101 
102 
103 
104 
105     @Parameter( property = "pmd.maxAllowedViolations", defaultValue = "0" )
106     private int maxAllowedViolations;
107 
108     
109     private final ExcludeFromFile<D> excludeFromFile;
110 
111     
112 
113 
114 
115     protected AbstractPmdViolationCheckMojo( ExcludeFromFile<D> excludeFromFile )
116     {
117         this.excludeFromFile = excludeFromFile;
118     }
119 
120     
121 
122 
123     @Parameter( defaultValue = "${project}", readonly = true, required = true )
124     protected MavenProject project;
125 
126     protected void executeCheck( final String filename, final String tagName, final String key,
127                                  final int failurePriority )
128         throws MojoFailureException, MojoExecutionException
129     {
130         if ( aggregate && !project.isExecutionRoot() )
131         {
132             return;
133         }
134 
135         if ( !isAggregator() && "pom".equalsIgnoreCase( project.getPackaging() ) )
136         {
137             return;
138         }
139 
140         excludeFromFile.loadExcludeFromFailuresData( excludeFromFailureFile );
141         final File outputFile = new File( targetDirectory, filename );
142 
143         if ( outputFile.exists() )
144         {
145             getLog().info( "PMD version: " + AbstractPmdReport.getPmdVersion() );
146 
147             try
148             {
149                 final ViolationDetails<D> violations = getViolations( outputFile, failurePriority );
150 
151                 final List<D> failures = violations.getFailureDetails();
152                 final List<D> warnings = violations.getWarningDetails();
153 
154                 if ( verbose )
155                 {
156                     printErrors( failures, warnings );
157                 }
158 
159                 final int failureCount = failures.size();
160                 final int warningCount = warnings.size();
161 
162                 final String message = getMessage( failureCount, warningCount, key, outputFile );
163 
164                 getLog().debug( "PMD failureCount: " + failureCount + ", warningCount: " + warningCount );
165 
166                 if ( failureCount > getMaxAllowedViolations() && isFailOnViolation() )
167                 {
168                     throw new MojoFailureException( message );
169                 }
170 
171                 this.getLog().info( message );
172 
173                 if ( failureCount > 0 && isFailOnViolation() && failureCount <= getMaxAllowedViolations() )
174                 {
175                     this.getLog().info( "The build is not failed, since " + getMaxAllowedViolations()
176                         + " violations are allowed (maxAllowedViolations)." );
177                 }
178             }
179             catch ( final IOException | XmlPullParserException e )
180             {
181                 throw new MojoExecutionException(
182                                                   "Unable to read PMD results xml: " + outputFile.getAbsolutePath(),
183                                                   e );
184             }
185         }
186         else
187         {
188             throw new MojoFailureException( "Unable to perform check, " + "unable to find " + outputFile );
189         }
190     }
191 
192     
193 
194 
195 
196 
197 
198 
199 
200 
201     private ViolationDetails<D> getViolations( final File analysisFile, final int failurePriority )
202         throws XmlPullParserException, IOException
203     {
204         final List<D> failures = new ArrayList<>();
205         final List<D> warnings = new ArrayList<>();
206 
207         final List<D> violations = getErrorDetails( analysisFile );
208 
209         for ( final D violation : violations )
210         {
211             final int priority = getPriority( violation );
212             if ( priority <= failurePriority && !excludeFromFile.isExcludedFromFailure( violation ) )
213             {
214                 failures.add( violation );
215                 if ( printFailingErrors )
216                 {
217                     printError( violation, "Failure" );
218                 }
219             }
220             else
221             {
222                 warnings.add( violation );
223             }
224         }
225 
226         final ViolationDetails<D> details = newViolationDetailsInstance();
227         details.setFailureDetails( failures );
228         details.setWarningDetails( warnings );
229         return details;
230     }
231 
232     protected abstract int getPriority( D errorDetail );
233 
234     protected abstract ViolationDetails<D> newViolationDetailsInstance();
235 
236     
237 
238 
239 
240 
241 
242     protected void printErrors( final List<D> failures, final List<D> warnings )
243     {
244         for ( final D warning : warnings )
245         {
246             printError( warning, "Warning" );
247         }
248 
249         for ( final D failure : failures )
250         {
251             printError( failure, "Failure" );
252         }
253     }
254 
255     
256 
257 
258 
259 
260 
261 
262 
263 
264     private String getMessage( final int failureCount, final int warningCount, final String key, final File outputFile )
265     {
266         final StringBuilder message = new StringBuilder( 256 );
267         if ( failureCount > 0 || warningCount > 0 )
268         {
269             if ( failureCount > 0 )
270             {
271                 message.append( "You have " ).append( failureCount ).append( " " ).append( key ).
272                   append( failureCount > 1 ? "s" : "" );
273             }
274 
275             if ( warningCount > 0 )
276             {
277                 if ( failureCount > 0 )
278                 {
279                     message.append( " and " );
280                 }
281                 else
282                 {
283                     message.append( "You have " );
284                 }
285                 message.append( warningCount ).append( " warning" ).append( warningCount > 1 ? "s" : "" );
286             }
287 
288             message.append( ". For more details see: " ).append( outputFile.getAbsolutePath() );
289         }
290         return message.toString();
291     }
292 
293     
294 
295 
296 
297 
298 
299 
300     protected abstract void printError( D item, String severity );
301 
302     
303 
304 
305 
306 
307 
308 
309 
310 
311     protected abstract List<D> getErrorDetails( File analysisFile )
312         throws XmlPullParserException, IOException;
313 
314     public boolean isFailOnViolation()
315     {
316         return failOnViolation;
317     }
318 
319     public Integer getMaxAllowedViolations()
320     {
321         return maxAllowedViolations;
322     }
323 
324     protected boolean isAggregator()
325     {
326         
327         return aggregate;
328     }
329 }