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.util.ArrayList;
24  import java.util.Collections;
25  import java.util.Comparator;
26  import java.util.List;
27  import java.util.ResourceBundle;
28  
29  import net.sourceforge.pmd.IRuleViolation;
30  import net.sourceforge.pmd.ReportListener;
31  import net.sourceforge.pmd.stat.Metric;
32  
33  import org.apache.maven.doxia.sink.Sink;
34  import org.codehaus.plexus.util.StringUtils;
35  
36  /**
37   * Handle events from PMD, converting them into Doxia events.
38   *
39   * @author Brett Porter
40   * @version $Id: PmdReportListener.html 816696 2012-05-08 15:19:20Z hboutemy $
41   */
42  public class PmdReportListener
43      implements ReportListener
44  {
45      private Sink sink;
46  
47      private String currentFilename;
48  
49      private boolean fileInitialized;
50  
51      private ResourceBundle bundle;
52  
53      private PmdFileInfo fileInfo;
54  
55      private List<IRuleViolation> violations = new ArrayList<IRuleViolation>();
56  
57      private boolean aggregate;
58  
59      // The number of erroneous files
60      private int fileCount = 0;
61  
62      //private List metrics = new ArrayList();
63  
64      public PmdReportListener( Sink sink, ResourceBundle bundle, boolean aggregate )
65      {
66          this.sink = sink;
67          this.bundle = bundle;
68          this.aggregate = aggregate;
69      }
70  
71      private String getTitle()
72      {
73          return bundle.getString( "report.pmd.title" );
74      }
75  
76      /** {@inheritDoc} */
77      public void ruleViolationAdded( IRuleViolation ruleViolation )
78      {
79          if ( !fileInitialized )
80          {
81              sink.section2();
82              sink.sectionTitle2();
83              String title = currentFilename;
84              if ( aggregate )
85              {
86                  title = fileInfo.getProject().getName() + " - " + currentFilename;
87              }
88              sink.text( title );
89              sink.sectionTitle2_();
90  
91              sink.table();
92              sink.tableRow();
93              sink.tableHeaderCell();
94              sink.text( bundle.getString( "report.pmd.column.violation" ) );
95              sink.tableHeaderCell_();
96              sink.tableHeaderCell();
97              sink.text( bundle.getString( "report.pmd.column.line" ) );
98              sink.tableHeaderCell_();
99              sink.tableRow_();
100 
101             fileInitialized = true;
102         }
103         violations.add( ruleViolation );
104     }
105 
106     // When dealing with multiple rulesets, the violations will get out of order
107     // wrt their source line number.  We re-sort them before writing them to the report.
108     private void processViolations()
109     {
110         fileCount++;
111         Collections.sort( violations, new Comparator<IRuleViolation>()
112         {
113             /** {@inheritDoc} */
114             public int compare( IRuleViolation o1, IRuleViolation o2 )
115             {
116                 return o1.getBeginLine() - o2.getBeginLine();
117             }
118         } );
119 
120         for ( IRuleViolation ruleViolation : violations )
121         {
122             sink.tableRow();
123             sink.tableCell();
124             sink.text( ruleViolation.getDescription() );
125             sink.tableCell_();
126             sink.tableCell();
127 
128             int beginLine = ruleViolation.getBeginLine();
129             outputLineLink( beginLine );
130             int endLine = ruleViolation.getEndLine();
131             if ( endLine != beginLine )
132             {
133                 sink.text( " - " );
134                 outputLineLink( endLine );
135             }
136 
137             sink.tableCell_();
138             sink.tableRow_();
139         }
140         violations.clear();
141     }
142 
143     private void outputLineLink( int line )
144     {
145         String xrefLocation = fileInfo.getXrefLocation();
146         if ( xrefLocation != null )
147         {
148             sink.link( xrefLocation + "/" + currentFilename.replaceAll( "\\.java$", ".html" ) + "#" + line );
149         }
150         sink.text( String.valueOf( line ) );
151         if ( xrefLocation != null )
152         {
153             sink.link_();
154         }
155     }
156 
157     /** {@inheritDoc} */
158     public void metricAdded( Metric metric )
159     {
160 //        if ( metric.getCount() != 0 )
161 //        {
162 //            // Skip metrics which have no data
163 //            metrics.add( metric );
164 //        }
165     }
166 
167     public void beginDocument()
168     {
169         sink.head();
170         sink.title();
171         sink.text( getTitle() );
172         sink.title_();
173         sink.head_();
174 
175         sink.body();
176 
177         sink.section1();
178         sink.sectionTitle1();
179         sink.text( getTitle() );
180         sink.sectionTitle1_();
181 
182         sink.paragraph();
183         sink.text( bundle.getString( "report.pmd.pmdlink" ) + " " );
184         sink.link( "http://pmd.sourceforge.net/" );
185         sink.text( "PMD" );
186         sink.link_();
187         sink.text( " " + AbstractPmdReport.getPmdVersion() + "." );
188         sink.paragraph_();
189 
190         sink.section1_();
191 
192         // TODO overall summary
193 
194         sink.section1();
195         sink.sectionTitle1();
196         sink.text( bundle.getString( "report.pmd.files" ) );
197         sink.sectionTitle1_();
198 
199         // TODO files summary
200     }
201 
202     public void beginFile( File file, PmdFileInfo finfo )
203     {
204         fileInfo = finfo;
205         currentFilename = StringUtils.substring( file.getAbsolutePath(),
206                                                  finfo.getSourceDirectory().getAbsolutePath().length() + 1 );
207         currentFilename = StringUtils.replace( currentFilename, "\\", "/" );
208         fileInitialized = false;
209     }
210 
211     public void endFile( File file )
212     {
213         if ( fileInitialized )
214         {
215             processViolations();
216             sink.table_();
217             sink.section2_();
218         }
219     }
220 
221     /*
222     private void processMetrics()
223     {
224         if ( metrics.size() == 0 )
225         {
226             return;
227         }
228 
229         sink.section1();
230         sink.sectionTitle1();
231         sink.text( "Metrics" );
232         sink.sectionTitle1_();
233 
234         sink.table();
235         sink.tableRow();
236         sink.tableHeaderCell();
237         sink.text( "Name" );
238         sink.tableHeaderCell_();
239         sink.tableHeaderCell();
240         sink.text( "Count" );
241         sink.tableHeaderCell_();
242         sink.tableHeaderCell();
243         sink.text( "High" );
244         sink.tableHeaderCell_();
245         sink.tableHeaderCell();
246         sink.text( "Low" );
247         sink.tableHeaderCell_();
248         sink.tableHeaderCell();
249         sink.text( "Average" );
250         sink.tableHeaderCell_();
251         sink.tableRow_();
252 
253         for ( Iterator iter = metrics.iterator(); iter.hasNext(); )
254         {
255             Metric met = (Metric) iter.next();
256             sink.tableRow();
257             sink.tableCell();
258             sink.text( met.getMetricName() );
259             sink.tableCell_();
260             sink.tableCell();
261             sink.text( String.valueOf( met.getCount() ) );
262             sink.tableCell_();
263             sink.tableCell();
264             sink.text( String.valueOf( met.getHighValue() ) );
265             sink.tableCell_();
266             sink.tableCell();
267             sink.text( String.valueOf( met.getLowValue() ) );
268             sink.tableCell_();
269             sink.tableCell();
270             sink.text( String.valueOf( met.getAverage() ) );
271             sink.tableCell_();
272             sink.tableRow_();
273         }
274         sink.table_();
275         sink.section1_();
276     }
277     */
278 
279     public void endDocument()
280     {
281         if ( fileCount == 0 )
282         {
283             sink.paragraph();
284             sink.text( bundle.getString( "report.pmd.noProblems" ) );
285             sink.paragraph_();
286         }
287 
288         sink.section1_();
289 
290         // The Metrics report useless with the current PMD metrics impl.
291         // For instance, run the coupling ruleset and you will get a boatload
292         // of excessive imports metrics, none of which is really any use.
293         // TODO Determine if we are going to just ignore metrics.
294 
295         // processMetrics();
296 
297         sink.body_();
298 
299         sink.flush();
300 
301         sink.close();
302     }
303 }