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