Index: src/main/java/org/apache/maven/plugin/checkstyle/CheckstyleReport.java =================================================================== --- src/main/java/org/apache/maven/plugin/checkstyle/CheckstyleReport.java (revision 307222) +++ src/main/java/org/apache/maven/plugin/checkstyle/CheckstyleReport.java (working copy) @@ -27,6 +27,7 @@ import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.api.FilterSet; +import com.puppycrawl.tools.checkstyle.api.SeverityLevel; import com.puppycrawl.tools.checkstyle.filters.SuppressionsLoader; import org.apache.maven.project.MavenProject; import org.apache.maven.reporting.AbstractMavenReport; @@ -41,6 +42,7 @@ import java.io.IOException; import java.io.OutputStream; import java.net.URL; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Properties; @@ -118,8 +120,7 @@ /** * If null, the checkstyle task will display violations on stdout. Otherwise, the text file will be - * created with the violations. Note: This is in addition to the XML result file (containing - * the violations in XML format which is always created. + * created with the violations. * * @parameter */ @@ -187,6 +188,8 @@ */ private SiteRenderer siteRenderer; + private CheckstyleReportListener reportListener; + /** * @see org.apache.maven.reporting.MavenReport#getName(java.util.Locale) */ @@ -226,13 +229,23 @@ { return siteRenderer; } - + /** * @see org.apache.maven.reporting.AbstractMavenReport#executeReport(java.util.Locale) */ public void executeReport( Locale locale ) throws MavenReportException { + executeCheckstyle(); + + CheckstyleReportGenerator generator = new CheckstyleReportGenerator( getSink(), getBundle( locale ) ); + + generator.generateReport( reportListener.getFiles() ); + } + + private void executeCheckstyle() + throws MavenReportException + { File[] files = getFilesToProcess( includes, excludes ); String configFile = getConfigFile(); @@ -268,25 +281,9 @@ { throw new MavenReportException( "Failed during checkstyle configuration", ce ); } + + setupListeners( checker ); - AuditListener listener = getListener(); - - if ( listener != null ) - { - checker.addListener( listener ); - } - - if ( useFile != null ) - { - OutputStream out = getOutputStream( useFile ); - - checker.addListener( new DefaultLogger( out, true ) ); - } - - AuditListener sinkListener = new CheckstyleReportListener( getSink(), sourceDirectory, getBundle( locale ) ); - - checker.addListener( sinkListener ); - int nbErrors = checker.process( files ); checker.destroy(); @@ -304,7 +301,29 @@ { return "checkstyle"; } + + private void setupListeners( Checker checker ) + throws MavenReportException + { + AuditListener listener = getListener(); + if ( listener != null ) + { + checker.addListener( listener ); + } + + if ( useFile != null ) + { + OutputStream out = getOutputStream( useFile ); + + checker.addListener( new DefaultLogger( out, true ) ); + } + + reportListener = new CheckstyleReportListener( sourceDirectory ); + + checker.addListener( reportListener ); + } + private AuditListener getListener() throws MavenReportException { @@ -353,6 +372,14 @@ throw new MavenReportException( "Can't open file for output: " + file.getAbsolutePath(), ioe ); } } + + private OutputStream getOutputStream( String file ) + throws MavenReportException + { + String basedir = System.getProperty( "basedir", System.getProperty( "user.dir" ) ); + + return getOutputStream( new File( basedir, file ) ); + } private File[] getFilesToProcess( String includes, String excludes ) throws MavenReportException @@ -483,7 +510,7 @@ throw new MavenReportException( "failed to load suppressions XML: " + suppressionsFile, ce ); } } - + private static ResourceBundle getBundle( Locale locale ) { return ResourceBundle.getBundle( "checkstyle-report", locale, CheckstyleReport.class.getClassLoader() ); Index: src/main/java/org/apache/maven/plugin/checkstyle/CheckstyleReportGenerator.java =================================================================== --- src/main/java/org/apache/maven/plugin/checkstyle/CheckstyleReportGenerator.java (revision 0) +++ src/main/java/org/apache/maven/plugin/checkstyle/CheckstyleReportGenerator.java (revision 0) @@ -0,0 +1,313 @@ +package org.apache.maven.plugin.checkstyle; + +/* + * Copyright 2004-2005 The Apache Software Foundation. + * + * Licensed 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 com.puppycrawl.tools.checkstyle.api.AuditEvent; +import com.puppycrawl.tools.checkstyle.api.SeverityLevel; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ResourceBundle; +import java.util.Map; + +import org.codehaus.doxia.sink.Sink; + +public class CheckstyleReportGenerator +{ + private ResourceBundle bundle; + + private Sink sink; + + private SeverityLevel severityLevel; + + public CheckstyleReportGenerator( Sink sink, ResourceBundle bundle ) + { + this.bundle = bundle; + + this.sink = sink; + } + + private String getTitle() + { + String title; + + if ( getSeverityLevel() == null ) + title = bundle.getString( "report.checkstyle.title" ); + else + title = bundle.getString( "report.checkstyle.severity_title" ) + severityLevel.getName(); + + return title; + } + + public void generateReport( Map files ) + { + doHeading(); + + if ( getSeverityLevel() == null ) + { + doSeveritySummary( files ); + + doFilesSummary( files ); + } + + doDetails( files ); + } + + private void doHeading() + { + 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.checkstyle.checkstylelink" ) + " " ); + sink.link( "http://checkstyle.sourceforge.net/" ); + sink.text( "Checkstyle" ); + sink.link_(); + sink.paragraph_(); + } + + private void doSeveritySummary( Map files ) + { + sink.section1(); + sink.sectionTitle1(); + sink.text( bundle.getString( "report.checkstyle.summary" ) ); + sink.sectionTitle1_(); + + sink.table(); + + sink.tableRow(); + sink.tableHeaderCell(); + sink.text( bundle.getString( "report.checkstyle.files" ) ); + sink.tableHeaderCell_(); + sink.tableHeaderCell(); + sink.text( "Infos" ); + sink.tableHeaderCell_(); + sink.tableHeaderCell(); + sink.text( "Warnings" ); + sink.tableHeaderCell_(); + sink.tableHeaderCell(); + sink.text( "Errors" ); + sink.tableHeaderCell_(); + sink.tableRow_(); + + sink.tableRow(); + sink.tableCell(); + sink.text( String.valueOf( files.size() ) ); + sink.tableCell_(); + sink.tableCell(); + sink.text( countSeverity( files.values().iterator(), SeverityLevel.INFO ) ); + sink.tableCell_(); + sink.tableCell(); + sink.text( countSeverity( files.values().iterator(), SeverityLevel.WARNING ) ); + sink.tableCell_(); + sink.tableCell(); + sink.text( countSeverity( files.values().iterator(), SeverityLevel.ERROR ) ); + sink.tableCell_(); + sink.tableRow_(); + + sink.table_(); + + sink.section1_(); + } + + private String countSeverity( Iterator files, SeverityLevel level ) + { + long count = 0; + + while ( files.hasNext() ) + { + List errors = (List) files.next(); + + for( Iterator error = errors.iterator(); error.hasNext(); ) + { + AuditEvent event = (AuditEvent) error.next(); + + if ( event.getSeverityLevel().equals( level ) ) count++; + } + } + + return String.valueOf( count ); + } + + private void doFilesSummary( Map filesMap ) + { + sink.section1(); + sink.sectionTitle1(); + sink.text( bundle.getString( "report.checkstyle.files" ) ); + sink.sectionTitle1_(); + + sink.table(); + + sink.tableRow(); + sink.tableHeaderCell(); + sink.text( bundle.getString( "report.checkstyle.files" ) ); + sink.tableHeaderCell_(); + sink.tableHeaderCell(); + sink.text( "I" ); + sink.tableHeaderCell_(); + sink.tableHeaderCell(); + sink.text( "W" ); + sink.tableHeaderCell_(); + sink.tableHeaderCell(); + sink.text( "E" ); + sink.tableHeaderCell_(); + sink.tableRow_(); + + for( Iterator files = filesMap.keySet().iterator(); files.hasNext(); ) + { + String filename = (String) files.next(); + List errors = (List) filesMap.get( filename ); + + sink.tableRow(); + + sink.tableCell(); + sink.link( "#" + filename ); + sink.text( filename ); + sink.link_(); + sink.tableCell_(); + + sink.tableCell(); + sink.text( countSeverity( Collections.singletonList( errors ).iterator(), SeverityLevel.INFO ) ); + sink.tableCell_(); + + sink.tableCell(); + sink.text( countSeverity( Collections.singletonList( errors ).iterator(), SeverityLevel.WARNING ) ); + sink.tableCell_(); + + sink.tableCell(); + sink.text( countSeverity( Collections.singletonList( errors ).iterator(), SeverityLevel.ERROR ) ); + sink.tableCell_(); + + sink.tableRow_(); + } + + sink.table_(); + sink.section1_(); + } + + private void doDetails( Map filesMap ) + { + Iterator files = filesMap.keySet().iterator(); + + while ( files.hasNext() ) + { + String file = (String) files.next(); + List eventList = (List) filesMap.get( file ); + + sink.section1(); + sink.sectionTitle1(); + sink.anchor( file ); + sink.text( file ); + sink.anchor_(); + sink.sectionTitle1_(); + + sink.table(); + sink.tableRow(); + sink.tableHeaderCell(); + sink.text( bundle.getString( "report.checkstyle.column.violation" ) ); + sink.tableHeaderCell_(); + sink.tableHeaderCell(); + sink.text( "Message" ); + sink.tableHeaderCell_(); + sink.tableHeaderCell(); + sink.text( "Line" ); + sink.tableHeaderCell_(); + sink.tableRow_(); + + doFileEvents( eventList); + + sink.table_(); + sink.section1_(); + } + } + + private void doFileEvents( List eventList ) + { + Iterator events = eventList.iterator(); + while ( events.hasNext() ) + { + AuditEvent event = (AuditEvent) events.next(); + SeverityLevel level = event.getSeverityLevel(); + + if ( getSeverityLevel() != null ) + if ( !getSeverityLevel().equals( level ) ) continue; + + sink.tableRow(); + + sink.tableCell(); + sink.figure(); + sink.figureCaption(); + sink.text( level.getName() ); + sink.figureCaption_(); + + if ( SeverityLevel.INFO.equals( level ) ) + sink.figureGraphics( "images/icon_info_sml.gif" ); + else if ( SeverityLevel.WARNING.equals( level ) ) + sink.figureGraphics( "images/icon_warning_sml.gif" ); + else if ( SeverityLevel.ERROR.equals( level ) ) + sink.figureGraphics( "images/icon_error_sml.gif" ); + + sink.figure_(); + sink.tableCell_(); + + sink.tableCell(); + sink.text( event.getMessage() ); + sink.tableCell_(); + + sink.tableCell(); + sink.text( String.valueOf( event.getLine() ) ); + sink.tableCell_(); + + sink.tableRow_(); + } + } + + private Iterator getCheckstyleEvents( Iterator events, SeverityLevel level ) + { + LinkedList filtered = new LinkedList(); + + while( events.hasNext() ) + { + AuditEvent event = (AuditEvent) events.next(); + + if ( event.getSeverityLevel().equals( level ) ) filtered.add( event ); + } + + return filtered.iterator(); + } + + public SeverityLevel getSeverityLevel() + { + return severityLevel; + } + + public void setSeverityLevel(SeverityLevel severityLevel) + { + this.severityLevel = severityLevel; + } +} Index: src/main/java/org/apache/maven/plugin/checkstyle/CheckstyleReportListener.java =================================================================== --- src/main/java/org/apache/maven/plugin/checkstyle/CheckstyleReportListener.java (revision 307222) +++ src/main/java/org/apache/maven/plugin/checkstyle/CheckstyleReportListener.java (working copy) @@ -16,15 +16,13 @@ * limitations under the License. */ -import org.codehaus.doxia.sink.Sink; -import org.codehaus.plexus.util.StringUtils; - -import java.util.ResourceBundle; - import com.puppycrawl.tools.checkstyle.api.AuditEvent; import com.puppycrawl.tools.checkstyle.api.AuditListener; import com.puppycrawl.tools.checkstyle.api.AutomaticBean; import com.puppycrawl.tools.checkstyle.api.SeverityLevel; +import java.util.LinkedList; +import java.util.TreeMap; +import org.codehaus.plexus.util.StringUtils; /** * @author Emmanuel Venisse @@ -34,122 +32,81 @@ extends AutomaticBean implements AuditListener { - private Sink sink; - private String sourceDirectory; - - private String currentFilename; - - private boolean fileInitialized; - - private ResourceBundle bundle; - - public CheckstyleReportListener( Sink sink, String sourceDirectory, ResourceBundle bundle ) + + private TreeMap files; + + private String currentFile; + + private LinkedList events; + + private SeverityLevel severityLevel; + + public CheckstyleReportListener( String sourceDirectory ) { - this.sink = sink; this.sourceDirectory = sourceDirectory; - this.bundle = bundle; } - - private String getTitle() + + public void setSeverityLevelFilter( SeverityLevel severityLevel ) { - return bundle.getString( "report.checkstyle.title" ); + this.severityLevel = severityLevel; } - + + public SeverityLevel getSeverityLevelFilter() + { + return severityLevel; + } + public void auditStarted( AuditEvent event ) { - 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.checkstyle.checkstylelink" ) + " " ); - sink.link( "http://checkstyle.sourceforge.net/" ); - sink.text( "Checkstyle" ); - sink.link_(); - sink.paragraph_(); - - // TODO overall summary - - sink.section1_(); - sink.sectionTitle1(); - sink.text( bundle.getString( "report.checkstyle.files" ) ); - sink.sectionTitle1_(); - - // TODO files summary + setFiles( new TreeMap() ); } public void auditFinished( AuditEvent event ) { - sink.section1_(); - sink.body_(); - sink.flush(); - sink.close(); + //do nothing } public void fileStarted( AuditEvent event ) { - currentFilename = StringUtils.substring( event.getFileName(), sourceDirectory.length() + 1 ); - currentFilename = StringUtils.replace( currentFilename, "\\", "/" ); - fileInitialized = false; + currentFile = StringUtils.substring( event.getFileName(), sourceDirectory.length() + 1 ); + currentFile = StringUtils.replace( currentFile, "\\", "/" ); + + if ( !getFiles().containsKey( currentFile ) ) + getFiles().put( currentFile, new LinkedList() ); + + events = (LinkedList) getFiles().get( currentFile ); } public void fileFinished( AuditEvent event ) { - if ( fileInitialized ) - { - sink.table_(); - sink.section2_(); - } + getFiles().put( currentFile, events ); + currentFile = null; } public void addError( AuditEvent event ) { - if ( !SeverityLevel.IGNORE.equals( event.getSeverityLevel() ) ) + if ( SeverityLevel.IGNORE.equals( event.getSeverityLevel() ) ) return; + + if ( severityLevel == null || severityLevel.equals( event.getSeverityLevel() ) ) { - if ( !fileInitialized ) - { - sink.section2(); - sink.sectionTitle2(); - sink.text( currentFilename ); - sink.sectionTitle2_(); - - sink.table(); - sink.tableRow(); - sink.tableHeaderCell(); - sink.text( bundle.getString( "report.checkstyle.column.violation" ) ); - sink.tableHeaderCell_(); - sink.tableHeaderCell(); - sink.text( bundle.getString( "report.checkstyle.column.line" ) ); - sink.tableHeaderCell_(); - sink.tableRow_(); - - fileInitialized = true; - } - - sink.tableRow(); - sink.tableCell(); - sink.text( event.getMessage() ); - sink.tableCell_(); - sink.tableCell(); - sink.text( String.valueOf( event.getLine() ) ); - sink.tableCell_(); - sink.tableRow_(); + events.add( event ); } } - + public void addException( AuditEvent event, Throwable throwable ) { //Do Nothing } + + public TreeMap getFiles() + { + return files; + } + + public void setFiles( TreeMap files ) + { + this.files = files; + } } Index: src/main/resources/checkstyle-report_en.properties =================================================================== --- src/main/resources/checkstyle-report_en.properties (revision 307222) +++ src/main/resources/checkstyle-report_en.properties (working copy) @@ -5,3 +5,5 @@ report.checkstyle.column.line=Line report.checkstyle.checkstylelink=The following document contains the results of report.checkstyle.files=Files +report.checkstyle.summary=Summary +report.checkstyle.severity_title=Checkstyle errors in severity \ No newline at end of file