blob: 5c0fa1d271ef3a6d568531dcd967338b2b46512f [file] [log] [blame]
package org.apache.maven.plugin.pmd;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;
import net.sourceforge.pmd.IRuleViolation;
import net.sourceforge.pmd.ReportListener;
import net.sourceforge.pmd.stat.Metric;
import org.apache.maven.doxia.sink.Sink;
import org.codehaus.plexus.util.StringUtils;
/**
* Handle events from PMD, converting them into Doxia events.
*
* @author Brett Porter
* @version $Id$
*/
public class PmdReportListener
implements ReportListener
{
private Sink sink;
private String currentFilename;
private boolean fileInitialized;
private ResourceBundle bundle;
private PmdFileInfo fileInfo;
private List violations = new ArrayList();
private boolean aggregate;
// The number of erroneous files
private int fileCount = 0;
//private List metrics = new ArrayList();
public PmdReportListener( Sink sink, ResourceBundle bundle, boolean aggregate )
{
this.sink = sink;
this.bundle = bundle;
this.aggregate = aggregate;
}
private String getTitle()
{
return bundle.getString( "report.pmd.title" );
}
/** {@inheritDoc} */
public void ruleViolationAdded( IRuleViolation ruleViolation )
{
if ( !fileInitialized )
{
sink.section2();
sink.sectionTitle2();
String title = currentFilename;
if ( aggregate )
{
title = fileInfo.getProject().getName() + " - " + currentFilename;
}
sink.text( title );
sink.sectionTitle2_();
sink.table();
sink.tableRow();
sink.tableHeaderCell();
sink.text( bundle.getString( "report.pmd.column.violation" ) );
sink.tableHeaderCell_();
sink.tableHeaderCell();
sink.text( bundle.getString( "report.pmd.column.line" ) );
sink.tableHeaderCell_();
sink.tableRow_();
fileInitialized = true;
}
violations.add( ruleViolation );
}
// When dealing with multiple rulesets, the violations will get out of order
// wrt their source line number. We re-sort them before writing them to the report.
private void processViolations()
{
fileCount++;
Collections.sort( violations, new Comparator()
{
/** {@inheritDoc} */
public int compare( Object o1, Object o2 )
{
return ( (IRuleViolation) o1 ).getBeginLine()
- ( (IRuleViolation) o2 ).getBeginLine();
}
} );
for ( Iterator it = violations.iterator(); it.hasNext(); )
{
IRuleViolation ruleViolation = (IRuleViolation) it.next();
sink.tableRow();
sink.tableCell();
sink.text( ruleViolation.getDescription() );
sink.tableCell_();
sink.tableCell();
int beginLine = ruleViolation.getBeginLine();
outputLineLink( beginLine );
int endLine = ruleViolation.getEndLine();
if ( endLine != beginLine )
{
sink.text( " - " );
outputLineLink( endLine );
}
sink.tableCell_();
sink.tableRow_();
}
violations.clear();
}
private void outputLineLink( int line )
{
String xrefLocation = fileInfo.getXrefLocation();
if ( xrefLocation != null )
{
sink.link( xrefLocation + "/" + currentFilename.replaceAll( "\\.java$", ".html" ) + "#" + line );
}
sink.text( String.valueOf( line ) );
if ( xrefLocation != null )
{
sink.link_();
}
}
/** {@inheritDoc} */
public void metricAdded( Metric metric )
{
// if ( metric.getCount() != 0 )
// {
// // Skip metrics which have no data
// metrics.add( metric );
// }
}
public void beginDocument()
{
sink.head();
sink.title();
sink.text( getTitle() );
sink.title_();
sink.head_();
sink.body();
sink.section1();
sink.sectionTitle1();
sink.text( getTitle() );
sink.sectionTitle1_();
sink.paragraph();
sink.text( bundle.getString( "report.pmd.pmdlink" ) + " " );
sink.link( "http://pmd.sourceforge.net/" );
sink.text( "PMD" );
sink.link_();
sink.text( " " + AbstractPmdReport.getPmdVersion() + "." );
sink.paragraph_();
sink.section1_();
// TODO overall summary
sink.section1();
sink.sectionTitle1();
sink.text( bundle.getString( "report.pmd.files" ) );
sink.sectionTitle1_();
// TODO files summary
}
public void beginFile( File file, PmdFileInfo finfo )
{
fileInfo = finfo;
currentFilename = StringUtils.substring( file.getAbsolutePath(),
finfo.getSourceDirectory().getAbsolutePath().length() + 1 );
currentFilename = StringUtils.replace( currentFilename, "\\", "/" );
fileInitialized = false;
}
public void endFile( File file )
{
if ( fileInitialized )
{
processViolations();
sink.table_();
sink.section2_();
}
}
/*
private void processMetrics()
{
if ( metrics.size() == 0 )
{
return;
}
sink.section1();
sink.sectionTitle1();
sink.text( "Metrics" );
sink.sectionTitle1_();
sink.table();
sink.tableRow();
sink.tableHeaderCell();
sink.text( "Name" );
sink.tableHeaderCell_();
sink.tableHeaderCell();
sink.text( "Count" );
sink.tableHeaderCell_();
sink.tableHeaderCell();
sink.text( "High" );
sink.tableHeaderCell_();
sink.tableHeaderCell();
sink.text( "Low" );
sink.tableHeaderCell_();
sink.tableHeaderCell();
sink.text( "Average" );
sink.tableHeaderCell_();
sink.tableRow_();
for ( Iterator iter = metrics.iterator(); iter.hasNext(); )
{
Metric met = (Metric) iter.next();
sink.tableRow();
sink.tableCell();
sink.text( met.getMetricName() );
sink.tableCell_();
sink.tableCell();
sink.text( String.valueOf( met.getCount() ) );
sink.tableCell_();
sink.tableCell();
sink.text( String.valueOf( met.getHighValue() ) );
sink.tableCell_();
sink.tableCell();
sink.text( String.valueOf( met.getLowValue() ) );
sink.tableCell_();
sink.tableCell();
sink.text( String.valueOf( met.getAverage() ) );
sink.tableCell_();
sink.tableRow_();
}
sink.table_();
sink.section1_();
}
*/
public void endDocument()
{
if ( fileCount == 0 )
{
sink.paragraph();
sink.text( bundle.getString( "report.pmd.noProblems" ) );
sink.paragraph_();
}
sink.section1_();
// The Metrics report useless with the current PMD metrics impl.
// For instance, run the coupling ruleset and you will get a boatload
// of excessive imports metrics, none of which is really any use.
// TODO Determine if we are going to just ignore metrics.
// processMetrics();
sink.body_();
sink.flush();
sink.close();
}
}