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