View Javadoc

1   package org.apache.maven.plugin.pmd;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.io.Reader;
25  import java.util.ArrayList;
26  import java.util.List;
27  
28  import org.apache.maven.plugin.AbstractMojo;
29  import org.apache.maven.plugin.MojoExecutionException;
30  import org.apache.maven.plugin.MojoFailureException;
31  import org.apache.maven.project.MavenProject;
32  import org.codehaus.plexus.util.IOUtil;
33  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
34  
35  /**
36   * Base class for mojos that check if there were any PMD violations.
37   *
38   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
39   * @version $Id: AbstractPmdViolationCheckMojo.html 816696 2012-05-08 15:19:20Z hboutemy $
40   */
41  public abstract class AbstractPmdViolationCheckMojo<D>
42      extends AbstractMojo
43  {
44      /**
45       * The location of the XML report to check, as generated by the PMD report.
46       *
47       * @parameter expression="${project.build.directory}"
48       * @required
49       */
50      private File targetDirectory;
51  
52      /**
53       * Whether to fail the build if the validation check fails.
54       *
55       * @parameter expression="${pmd.failOnViolation}" default-value="true"
56       * @required
57       */
58      private boolean failOnViolation;
59  
60      /**
61       * The project language, for determining whether to run the report.
62       *
63       * @parameter expression="${project.artifact.artifactHandler.language}"
64       * @required
65       * @readonly
66       */
67      private String language;
68  
69      /**
70       * Whether to build an aggregated report at the root, or build individual reports.
71       *
72       * @parameter expression="${aggregate}" default-value="false"
73       * @since 2.2
74       */
75      protected boolean aggregate;
76  
77      /**
78       * Print details of check failures to build output.
79       *
80       * @parameter expression="${pmd.verbose}" default-value="false"
81       */
82      private boolean verbose;
83  
84      /**
85       * The project to analyze.
86       *
87       * @parameter expression="${project}"
88       * @required
89       * @readonly
90       */
91      protected MavenProject project;
92  
93      protected void executeCheck( String filename, String tagName, String key, int failurePriority )
94          throws MojoFailureException, MojoExecutionException
95      {
96          if ( aggregate && !project.isExecutionRoot() )
97          {
98              return;
99          }
100 
101         if ( "java".equals( language ) || aggregate )
102         {
103             File outputFile = new File( targetDirectory, filename );
104 
105             if ( outputFile.exists() )
106             {
107                 Reader reader = null;
108                 try
109                 {
110                     ViolationDetails<D> violations = getViolations( outputFile, failurePriority );
111 
112                     List<D> failures = violations.getFailureDetails();
113                     List<D> warnings = violations.getWarningDetails();
114 
115                     if ( verbose )
116                     {
117                         printErrors( failures, warnings );
118                     }
119 
120                     int failureCount = failures.size();
121                     int warningCount = warnings.size();
122 
123                     String message = getMessage( failureCount, warningCount, key, outputFile );
124 
125                     if ( failureCount > 0 && failOnViolation )
126                     {
127                         throw new MojoFailureException( message );
128                     }
129 
130                     this.getLog().info( message );
131                 }
132                 catch ( IOException e )
133                 {
134                     throw new MojoExecutionException(
135                                                       "Unable to read PMD results xml: " + outputFile.getAbsolutePath(),
136                                                       e );
137                 }
138                 catch ( XmlPullParserException e )
139                 {
140                     throw new MojoExecutionException(
141                                                       "Unable to read PMD results xml: " + outputFile.getAbsolutePath(),
142                                                       e );
143                 }
144                 finally
145                 {
146                     IOUtil.close( reader );
147                 }
148             }
149             else
150             {
151                 throw new MojoFailureException( "Unable to perform check, " + "unable to find " + outputFile );
152             }
153         }
154     }
155 
156     /**
157      * Method for collecting the violations found by the PMD tool
158      *
159      * @param xpp
160      *            the xml parser object
161      * @param tagName
162      *            the element that will be checked
163      * @return an int that specifies the number of violations found
164      * @throws XmlPullParserException
165      * @throws IOException
166      */
167     private ViolationDetails<D> getViolations( File analysisFile, int failurePriority )
168         throws XmlPullParserException, IOException
169     {
170         List<D> failures = new ArrayList<D>();
171         List<D> warnings = new ArrayList<D>();
172 
173         List<D> violations = getErrorDetails( analysisFile );
174         
175         for( D violation : violations )
176         {
177             int priority = getPriority( violation );
178             if ( priority <= failurePriority )
179             {
180                 failures.add( violation );
181             }
182             else
183             {
184                 warnings.add( violation );
185             }
186         }
187         
188         ViolationDetails<D> details = newViolationDetailsInstance();
189         details.setFailureDetails( failures );
190         details.setWarningDetails( warnings );
191         return details;
192     }
193     
194     protected abstract int getPriority( D errorDetail );
195     
196     protected abstract ViolationDetails<D> newViolationDetailsInstance();
197 
198     /**
199      * Prints the warnings and failures
200      *
201      * @param failures
202      *            list of failures
203      * @param warnings
204      *            list of warnings
205      */
206     protected void printErrors( List<D> failures, List<D> warnings )
207     {
208         for ( D warning :  warnings )
209         {
210             printError( warning, "Warning" );
211         }
212 
213         for ( D failure : failures )
214         {
215             printError( failure, "Failure" );
216         }
217     }
218 
219     /**
220      * Gets the output message
221      *
222      * @param failureCount
223      * @param warningCount
224      * @param key
225      * @param outputFile
226      * @return
227      */
228     private String getMessage( int failureCount, int warningCount, String key, File outputFile )
229     {
230         StringBuffer message = new StringBuffer();
231         if ( failureCount > 0 || warningCount > 0 )
232         {
233             if ( failureCount > 0 )
234             {
235                 message.append( "You have " + failureCount + " " + key + ( failureCount > 1 ? "s" : "" ) );
236             }
237 
238             if ( warningCount > 0 )
239             {
240                 if ( failureCount > 0 )
241                 {
242                     message.append( " and " );
243                 }
244                 else
245                 {
246                     message.append( "You have " );
247                 }
248                 message.append( warningCount + " warning" + ( warningCount > 1 ? "s" : "" ) );
249             }
250 
251             message.append( ". For more details see:" ).append( outputFile.getAbsolutePath() );
252         }
253         return message.toString();
254     }
255 
256     /**
257      * Formats the failure details and prints them as an INFO message
258      *
259      * @param item
260      */
261     protected abstract void printError( D item, String severity );
262 
263     /**
264      * Gets the attributes and text for the violation tag and puts them in a
265      * HashMap
266      *
267      * @param xpp
268      * @throws XmlPullParserException
269      * @throws IOException
270      */
271     protected abstract List<D> getErrorDetails( File analisysFile )
272         throws XmlPullParserException, IOException;
273 }