You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ol...@apache.org on 2012/05/21 21:58:42 UTC

svn commit: r1341175 - in /maven/plugins/trunk/maven-pmd-plugin: ./ src/main/java/org/apache/maven/plugin/pmd/ src/main/resources/rulesets/ src/test/java/org/apache/maven/plugin/pmd/ src/test/resources/unit/custom-configuration/ src/test/resources/unit...

Author: olamy
Date: Mon May 21 19:58:41 2012
New Revision: 1341175

URL: http://svn.apache.org/viewvc?rev=1341175&view=rev
Log:
[MPMD-147] Migrate to PMD 5.0.0
Submitted by Andreas Dangel.

Modified:
    maven/plugins/trunk/maven-pmd-plugin/pom.xml
    maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReport.java
    maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/PmdReport.java
    maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/PmdReportListener.java
    maven/plugins/trunk/maven-pmd-plugin/src/main/resources/rulesets/maven.xml
    maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/CpdReportTest.java
    maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/PmdReportTest.java
    maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/PmdViolationCheckMojoTest.java
    maven/plugins/trunk/maven-pmd-plugin/src/test/resources/unit/custom-configuration/custom-configuration-plugin-config.xml
    maven/plugins/trunk/maven-pmd-plugin/src/test/resources/unit/custom-configuration/resources/rulesets/custom.xml

Modified: maven/plugins/trunk/maven-pmd-plugin/pom.xml
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-pmd-plugin/pom.xml?rev=1341175&r1=1341174&r2=1341175&view=diff
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/pom.xml (original)
+++ maven/plugins/trunk/maven-pmd-plugin/pom.xml Mon May 21 19:58:41 2012
@@ -64,7 +64,7 @@ under the License.
   <properties>
     <mavenVersion>2.2.1</mavenVersion>
     <doxiaVersion>1.1.3</doxiaVersion>
-    <pmdVersion>4.3</pmdVersion>
+    <pmdVersion>5.0.0</pmdVersion>
     <sitePluginVersion>3.0</sitePluginVersion>
   </properties>
 
@@ -156,7 +156,7 @@ under the License.
 
     <!-- pmd -->
     <dependency>
-      <groupId>pmd</groupId>
+      <groupId>net.sourceforge.pmd</groupId>
       <artifactId>pmd</artifactId>
       <version>${pmdVersion}</version>
     </dependency>

Modified: maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReport.java
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReport.java?rev=1341175&r1=1341174&r2=1341175&view=diff
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReport.java (original)
+++ maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReport.java Mon May 21 19:58:41 2012
@@ -32,6 +32,7 @@ import java.util.Properties;
 import java.util.ResourceBundle;
 
 import net.sourceforge.pmd.cpd.CPD;
+import net.sourceforge.pmd.cpd.CPDConfiguration;
 import net.sourceforge.pmd.cpd.CSVRenderer;
 import net.sourceforge.pmd.cpd.JavaLanguage;
 import net.sourceforge.pmd.cpd.JavaTokenizer;
@@ -158,26 +159,17 @@ public class CpdReport
         {
             p.setProperty( JavaTokenizer.IGNORE_IDENTIFIERS, "true" );
         }
-        CPD cpd = new CPD( minimumTokens, new JavaLanguage( p ) );
 
+        CPD cpd;
         Map<File, PmdFileInfo> files = null;
+
         try
         {
             files = getFilesToProcess();
+            String encoding = determineEncoding( !files.isEmpty() );
 
-            if ( StringUtils.isNotEmpty( getSourceEncoding() ) )
-            {
-                cpd.setEncoding( getSourceEncoding() );
-
-                // test encoding as CPD will convert exception into a RuntimeException
-                WriterFactory.newWriter( new ByteArrayOutputStream(), getSourceEncoding() );
-            }
-            else if ( !files.isEmpty() )
-            {
-                getLog().warn(
-                               "File encoding has not been set, using platform encoding "
-                                   + WriterFactory.FILE_ENCODING + ", i.e. build is platform dependent!" );
-            }
+            CPDConfiguration cpdConfiguration = new CPDConfiguration( minimumTokens, new JavaLanguage( p ), encoding );
+            cpd = new CPD( cpdConfiguration );
 
             for ( File file : files.keySet() )
             {
@@ -201,6 +193,23 @@ public class CpdReport
         return cpd;
     }
 
+    private String determineEncoding(boolean showWarn) throws UnsupportedEncodingException {
+        String encoding = WriterFactory.FILE_ENCODING;
+        if ( StringUtils.isNotEmpty( getSourceEncoding() ) ) {
+
+            encoding = getSourceEncoding();
+            // test encoding as CPD will convert exception into a RuntimeException
+            WriterFactory.newWriter( new ByteArrayOutputStream(), encoding );
+
+        } else if ( showWarn ) {
+            getLog().warn(
+                    "File encoding has not been set, using platform encoding "
+                        + WriterFactory.FILE_ENCODING + ", i.e. build is platform dependent!" );
+            encoding = WriterFactory.FILE_ENCODING;
+        }
+        return encoding;
+    }
+
     void writeNonHtml( CPD cpd )
         throws MavenReportException
     {
@@ -262,7 +271,9 @@ public class CpdReport
         Renderer renderer = null;
         if ( "xml".equals( format ) )
         {
-            renderer = new XMLRenderer( getOutputEncoding() );
+            //TODO: pmd should provide a better way to specify the output encoding (getOutputEncoding());
+            System.setProperty("file.encoding", getOutputEncoding());
+            renderer = new XMLRenderer();
         }
         else if ( "csv".equals( format ) )
         {

Modified: maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/PmdReport.java
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/PmdReport.java?rev=1341175&r1=1341174&r2=1341175&view=diff
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/PmdReport.java (original)
+++ maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/PmdReport.java Mon May 21 19:58:41 2012
@@ -20,33 +20,34 @@ package org.apache.maven.plugin.pmd;
  */
 
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.UnsupportedEncodingException;
 import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Properties;
 import java.util.ResourceBundle;
 
-import net.sourceforge.pmd.IRuleViolation;
 import net.sourceforge.pmd.PMD;
-import net.sourceforge.pmd.PMDException;
+import net.sourceforge.pmd.PMDConfiguration;
 import net.sourceforge.pmd.Report;
-import net.sourceforge.pmd.Rule;
 import net.sourceforge.pmd.RuleContext;
-import net.sourceforge.pmd.RuleSet;
+import net.sourceforge.pmd.RulePriority;
 import net.sourceforge.pmd.RuleSetFactory;
-import net.sourceforge.pmd.SourceType;
+import net.sourceforge.pmd.RuleSetReferenceId;
+import net.sourceforge.pmd.RuleViolation;
+import net.sourceforge.pmd.lang.LanguageVersion;
 import net.sourceforge.pmd.renderers.CSVRenderer;
 import net.sourceforge.pmd.renderers.HTMLRenderer;
 import net.sourceforge.pmd.renderers.Renderer;
 import net.sourceforge.pmd.renderers.TextRenderer;
 import net.sourceforge.pmd.renderers.XMLRenderer;
+import net.sourceforge.pmd.util.datasource.DataSource;
+import net.sourceforge.pmd.util.datasource.FileDataSource;
 
 import org.apache.maven.doxia.sink.Sink;
 import org.apache.maven.reporting.MavenReportException;
@@ -73,9 +74,10 @@ public class PmdReport
 {
     /**
      * The target JDK to analyze based on. Should match the target used in the compiler plugin. Valid values are
-     * currently <code>1.3</code>, <code>1.4</code>, <code>1.5</code> and <code>1.6</code>.
+     * currently <code>1.3</code>, <code>1.4</code>, <code>1.5</code>, <code>1.6</code> and <code>1.7</code>.
      * <p>
-     * <b>Note:</b> support for <code>1.6</code> was added in version 2.3 of this plugin.
+     * <b>Note:</b> support for <code>1.6</code> was added in version 2.3 of this plugin,
+     * support for <code>1.7</code> was added in version 2.7 of this plugin.
      * </p>
      *
      * @parameter expression="${targetJdk}"
@@ -103,12 +105,11 @@ public class PmdReport
     /**
      * The PMD rulesets to use. See the <a href="http://pmd.sourceforge.net/rules/index.html">Stock Rulesets</a> for a
      * list of some included. Since version 2.5, the ruleset "rulesets/maven.xml" is also available. Defaults to the
-     * basic, imports and unusedcode rulesets.
+     * java-basic, java-imports and java-unusedcode rulesets.
      *
      * @parameter
      */
-    private String[] rulesets =
-        new String[]{ "rulesets/basic.xml", "rulesets/unusedcode.xml", "rulesets/imports.xml", };
+    private String[] rulesets = new String[]{ "java-basic", "java-unusedcode", "java-imports" };
 
     /**
      * @component
@@ -191,49 +192,36 @@ public class PmdReport
     {
         Sink sink = getSink();
 
-        PMD pmd = getPMD();
-        RuleContext ruleContext = new RuleContext();
-        Report report = new Report();
-        PmdReportListener reportSink = new PmdReportListener( sink, getBundle( locale ), aggregate );
-
-        report.addListener( reportSink );
-        ruleContext.setReport( report );
+        PMDConfiguration pmdConfiguration = getPMDConfiguration();
+        final PmdReportListener reportSink = new PmdReportListener( sink, getBundle( locale ), aggregate );
+        RuleContext ruleContext = new RuleContext() {
+            @Override
+            public void setReport(Report report) {
+                super.setReport( report );
+                // make sure our listener is added - the Report is created by PMD internally now
+                report.addListener( reportSink );
+            }
+        };
         reportSink.beginDocument();
 
         RuleSetFactory ruleSetFactory = new RuleSetFactory();
-        ruleSetFactory.setMinimumPriority( this.minimumPriority );
-        RuleSet[] sets = new RuleSet[rulesets.length];
+        ruleSetFactory.setMinimumPriority( RulePriority.valueOf( this.minimumPriority ) );
+        String[] sets = new String[rulesets.length];
         try
         {
             for ( int idx = 0; idx < rulesets.length; idx++ )
             {
                 String set = rulesets[idx];
                 getLog().debug( "Preparing ruleset: " + set );
-                File ruleset = locator.getResourceAsFile( set, getLocationTemp( set ) );
-
+                RuleSetReferenceId id = new RuleSetReferenceId( set );
+                File ruleset = locator.getResourceAsFile( id.getRuleSetFileName(), getLocationTemp( set ) );
                 if ( null == ruleset )
                 {
                     throw new MavenReportException( "Could not resolve " + set );
                 }
-
-                InputStream rulesInput = new FileInputStream( ruleset );
-                try
-                {
-                    RuleSet ruleSet = ruleSetFactory.createRuleSet( rulesInput );
-                    sets[idx] = ruleSet;
-
-                    ruleSet.start( ruleContext );
-                }
-                finally
-                {
-                    rulesInput.close();
-                }
+                sets[idx] = ruleset.getAbsolutePath();
             }
         }
-        catch ( IOException e )
-        {
-            throw new MavenReportException( e.getMessage(), e );
-        }
         catch ( ResourceNotFoundException e )
         {
             throw new MavenReportException( e.getMessage(), e );
@@ -242,6 +230,7 @@ public class PmdReport
         {
             throw new MavenReportException( e.getMessage(), e );
         }
+        pmdConfiguration.setRuleSets( StringUtils.join( sets, "," ));
 
         Map<File, PmdFileInfo> files;
         try
@@ -253,86 +242,84 @@ public class PmdReport
             throw new MavenReportException( "Can't get file list", e );
         }
 
-        if ( StringUtils.isEmpty( getSourceEncoding() ) && !files.isEmpty() )
+        String encoding = getSourceEncoding();
+        if ( StringUtils.isEmpty( encoding ) && !files.isEmpty() )
         {
             getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
                                + ", i.e. build is platform dependent!" );
+            encoding = ReaderFactory.FILE_ENCODING;
         }
+        pmdConfiguration.setSourceEncoding( encoding );
 
-        for ( Map.Entry<File, PmdFileInfo> entry : files.entrySet() )
+        reportSink.setFiles(files);
+        List<DataSource> dataSources = new ArrayList<DataSource>( files.size() );
+        for ( File f : files.keySet() )
         {
-            File file = entry.getKey();
-            PmdFileInfo fileInfo = entry.getValue();
+            dataSources.add( new FileDataSource( f ) );
+        }
 
-            // TODO: lazily call beginFile in case there are no rules
+        try
+        {
+            List<Renderer> renderers = Collections.emptyList();
 
-            reportSink.beginFile( file, fileInfo );
-            ruleContext.setSourceCodeFilename( file.getAbsolutePath() );
-            for ( int idx = 0; idx < rulesets.length; idx++ )
-            {
-                try
-                {
-                    // PMD closes this Reader even though it did not open it so we have
-                    // to open a new one with every call to processFile().
-                    Reader reader;
-                    if ( StringUtils.isNotEmpty( getSourceEncoding() ) )
-                    {
-                        reader = ReaderFactory.newReader( file, getSourceEncoding() );
-                    }
-                    else
-                    {
-                        reader = ReaderFactory.newPlatformReader( file );
-                    }
-
-                    try
-                    {
-                        pmd.processFile( reader, sets[idx], ruleContext );
-                    }
-                    finally
-                    {
-                        reader.close();
-                    }
-                }
-                catch ( UnsupportedEncodingException e1 )
-                {
-                    throw new MavenReportException( "Encoding '" + getSourceEncoding() + "' is not supported.", e1 );
-                }
-                catch ( PMDException pe )
-                {
-                    String msg = pe.getLocalizedMessage();
-                    Throwable r = pe.getCause();
-                    if ( r != null )
-                    {
-                        msg = msg + ": " + r.getLocalizedMessage();
-                    }
-                    getLog().warn( msg );
-                    reportSink.ruleViolationAdded( new ProcessingErrorRuleViolation( file, msg ) );
-                }
-                catch ( FileNotFoundException e2 )
-                {
-                    getLog().warn( "Error opening source file: " + file );
-                    reportSink.ruleViolationAdded( new ProcessingErrorRuleViolation( file, e2.getLocalizedMessage() ) );
-                }
-                catch ( Exception e3 )
-                {
-                    getLog().warn( "Failure executing PMD for: " + file, e3 );
-                    reportSink.ruleViolationAdded( new ProcessingErrorRuleViolation( file, e3.getLocalizedMessage() ) );
-                }
-            }
-            reportSink.endFile( file );
-        }
+            // Unfortunately we need to disable multi-threading for now - as otherwise our PmdReportListener
+            // will be ignored.
+            // Longer term solution could be to use a custom renderer instead. And collect with this renderer
+            // all the violations.
+            pmdConfiguration.setThreads( 0 );
 
-        for ( int idx = 0; idx < rulesets.length; idx++ )
+            PMD.processFiles(pmdConfiguration, ruleSetFactory, dataSources, ruleContext, renderers );
+        }
+        catch ( Exception e )
         {
-            sets[idx].end( ruleContext );
+            getLog().warn( "Failure executing PMD: " + e.getLocalizedMessage(), e );
         }
 
         reportSink.endDocument();
 
+        // copy over the violations into a single report - PMD now creates one report per file
+        Report report = new Report();
+        for ( RuleViolation v : reportSink.getViolations() )
+        {
+            report.addRuleViolation( v );
+        }
         return report;
     }
 
     /**
+     * Convenience method to get the location of the specified file name.
+     *
+     * @param name the name of the file whose location is to be resolved
+     * @return a String that contains the absolute file name of the file
+     */
+    protected String getLocationTemp( String name )
+    {
+        String loc = name;
+        if ( loc.indexOf( '/' ) != -1 )
+        {
+            loc = loc.substring( loc.lastIndexOf( '/' ) + 1 );
+        }
+        if ( loc.indexOf( '\\' ) != -1 )
+        {
+            loc = loc.substring( loc.lastIndexOf( '\\' ) + 1 );
+        }
+
+        // MPMD-127 in the case that the rules are defined externally on a url
+        // we need to replace some special url characters that cannot be
+        // used in filenames on disk or produce ackward filenames.
+        // replace all occurrences of the following characters:  ? : & = %
+        loc = loc.replaceAll( "[\\?\\:\\&\\=\\%]", "_" );
+
+        if (!loc.endsWith( ".xml" ))
+        {
+            loc = loc + ".xml";
+        }
+
+        getLog().debug( "Before: " + name + " After: " + loc );
+        return loc;
+    }
+
+    /**
      * Use the PMD renderers to render in any format aside from HTML.
      *
      * @param report
@@ -379,57 +366,29 @@ public class PmdReport
     }
 
     /**
-     * Convenience method to get the location of the specified file name.
-     *
-     * @param name the name of the file whose location is to be resolved
-     * @return a String that contains the absolute file name of the file
-     */
-    protected String getLocationTemp( String name )
-    {
-        String loc = name;
-        if ( loc.indexOf( '/' ) != -1 )
-        {
-            loc = loc.substring( loc.lastIndexOf( '/' ) + 1 );
-        }
-        if ( loc.indexOf( '\\' ) != -1 )
-        {
-            loc = loc.substring( loc.lastIndexOf( '\\' ) + 1 );
-        }
-
-        // MPMD-127 in the case that the rules are defined externally on a url
-        // we need to replace some special url characters that cannot be
-        // used in filenames on disk or produce ackward filenames.
-        // replace all occurrences of the following characters:  ? : & = %
-        loc = loc.replaceAll( "[\\?\\:\\&\\=\\%]", "_" );
-
-        getLog().debug( "Before: " + name + " After: " + loc );
-        return loc;
-    }
-
-    /**
-     * Constructs the PMD class, passing it an argument
+     * Constructs the PMD configuration class, passing it an argument
      * that configures the target JDK.
      *
      * @return the resulting PMD
      * @throws org.apache.maven.reporting.MavenReportException
      *          if targetJdk is not supported
      */
-    public PMD getPMD()
+    public PMDConfiguration getPMDConfiguration()
         throws MavenReportException
     {
-        PMD pmd = new PMD();
+        PMDConfiguration configuration = new PMDConfiguration();
 
         if ( null != targetJdk )
         {
-            SourceType sourceType = SourceType.getSourceTypeForId( "java " + targetJdk );
-            if ( sourceType == null )
+            LanguageVersion languageVersion = LanguageVersion.findByTerseName( "java " + targetJdk );
+            if ( languageVersion == null )
             {
                 throw new MavenReportException( "Unsupported targetJdk value '" + targetJdk + "'." );
             }
-            pmd.setJavaVersion( sourceType );
+            configuration.setDefaultLanguageVersion( languageVersion );
         }
 
-        return pmd;
+        return configuration;
     }
 
     /**
@@ -462,21 +421,23 @@ public class PmdReport
         }
         else if ( "txt".equals( format ) )
         {
-            renderer = new TextRenderer();
+            renderer = new TextRenderer( new Properties() );
         }
         else if ( "csv".equals( format ) )
         {
-            renderer = new CSVRenderer();
+            renderer = new CSVRenderer( new Properties() );
         }
         else if ( "html".equals( format ) )
         {
-            renderer = new HTMLRenderer();
+            renderer = new HTMLRenderer( new Properties() );
         }
         else if ( !"".equals( format ) && !"none".equals( format ) )
         {
             try
             {
-                renderer = (Renderer) Class.forName( format ).newInstance();
+                renderer = (Renderer) Class.forName( format )
+                        .getConstructor( Properties.class )
+                            .newInstance( new Properties() );
             }
             catch ( Exception e )
             {
@@ -493,122 +454,8 @@ public class PmdReport
     {
         public PmdXMLRenderer( String encoding )
         {
-            super();
+            super( new Properties() );
             this.encoding = encoding;
         }
     }
-
-    /**
-     * @author <a href="mailto:douglass.doug@gmail.com">Doug Douglass</a>
-     */
-    private static class ProcessingErrorRuleViolation
-        implements IRuleViolation
-    {
-
-        private String filename;
-
-        private String description;
-
-        public ProcessingErrorRuleViolation( File file, String description )
-        {
-            filename = file.getPath();
-            this.description = description;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public String getFilename()
-        {
-            return this.filename;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public int getBeginLine()
-        {
-            return 0;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public int getBeginColumn()
-        {
-            return 0;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public int getEndLine()
-        {
-            return 0;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public int getEndColumn()
-        {
-            return 0;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public Rule getRule()
-        {
-            return null;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public String getDescription()
-        {
-            return this.description;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public String getPackageName()
-        {
-            return null;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public String getMethodName()
-        {
-            return null;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public String getClassName()
-        {
-            return null;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public boolean isSuppressed()
-        {
-            return false;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public String getVariableName()
-        {
-            return null;
-        }
-    }
 }
\ No newline at end of file

Modified: maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/PmdReportListener.java
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/PmdReportListener.java?rev=1341175&r1=1341174&r2=1341175&view=diff
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/PmdReportListener.java (original)
+++ maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/PmdReportListener.java Mon May 21 19:58:41 2012
@@ -23,11 +23,13 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.ResourceBundle;
 
-import net.sourceforge.pmd.IRuleViolation;
 import net.sourceforge.pmd.ReportListener;
+import net.sourceforge.pmd.RuleViolation;
 import net.sourceforge.pmd.stat.Metric;
 
 import org.apache.maven.doxia.sink.Sink;
@@ -46,20 +48,20 @@ public class PmdReportListener
 
     private String currentFilename;
 
-    private boolean fileInitialized;
-
     private ResourceBundle bundle;
 
     private PmdFileInfo fileInfo;
 
-    private List<IRuleViolation> violations = new ArrayList<IRuleViolation>();
+    private List<RuleViolation> violations = new ArrayList<RuleViolation>();
 
     private boolean aggregate;
 
     // The number of erroneous files
     private int fileCount = 0;
 
-    //private List metrics = new ArrayList();
+    private Map<File, PmdFileInfo> files;
+
+//    private List<Metric> metrics = new ArrayList<Metric>();
 
     public PmdReportListener( Sink sink, ResourceBundle bundle, boolean aggregate )
     {
@@ -74,70 +76,118 @@ public class PmdReportListener
     }
 
     /** {@inheritDoc} */
-    public void ruleViolationAdded( IRuleViolation ruleViolation )
+    public void ruleViolationAdded( RuleViolation ruleViolation )
     {
-        if ( !fileInitialized )
+        violations.add( ruleViolation );
+    }
+
+    public List<RuleViolation> getViolations() {
+        return violations;
+    }
+
+    private void startFileSection(String currentFilename, PmdFileInfo fileInfo) {
+        sink.section2();
+        sink.sectionTitle2();
+
+        // prepare the filename
+        this.currentFilename = StringUtils.substring( currentFilename,
+                                          fileInfo.getSourceDirectory().getAbsolutePath().length() + 1 );
+        this.currentFilename = StringUtils.replace( this.currentFilename, "\\", "/" );
+
+        String title = this.currentFilename;
+        if (aggregate)
         {
-            sink.section2();
-            sink.sectionTitle2();
-            String title = currentFilename;
-            if ( aggregate )
-            {
-                title = fileInfo.getProject().getName() + " - " + currentFilename;
-            }
-            sink.text( title );
-            sink.sectionTitle2_();
+            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_();
+        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_();
+    }
+
+    private void endFileSection() {
+        sink.table_();
+        sink.section2_();
+    }
 
-            fileInitialized = true;
+    private void processSingleRuleViolation(RuleViolation ruleViolation) {
+        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 );
         }
-        violations.add( ruleViolation );
+
+        sink.tableCell_();
+        sink.tableRow_();
     }
 
-    // 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.
+    // PMD might run the analysis multi-threaded, so the violations might be reported
+    // out of order. We sort them here by filename and line number before writing them to
+    // the report.
     private void processViolations()
     {
-        fileCount++;
-        Collections.sort( violations, new Comparator<IRuleViolation>()
-        {
+        fileCount = files.size();
+        Collections.sort( violations, new Comparator<RuleViolation>() {
             /** {@inheritDoc} */
-            public int compare( IRuleViolation o1, IRuleViolation o2 )
-            {
-                return o1.getBeginLine() - o2.getBeginLine();
+            public int compare(RuleViolation o1, RuleViolation o2) {
+                int filenames = o1.getFilename().compareTo( o2.getFilename() );
+                if (filenames == 0) {
+                    return o1.getBeginLine() - o2.getBeginLine();
+                }
+                else {
+                    return filenames;
+                }
             }
         } );
 
-        for ( IRuleViolation ruleViolation : violations )
+        Map<String, PmdFileInfo> fileLookup = new HashMap<String, PmdFileInfo>( fileCount );
+        for ( Map.Entry<File, PmdFileInfo> entry : files.entrySet() )
         {
-            sink.tableRow();
-            sink.tableCell();
-            sink.text( ruleViolation.getDescription() );
-            sink.tableCell_();
-            sink.tableCell();
+            fileLookup.put( entry.getKey().getAbsolutePath(), entry.getValue() );
+        }
 
-            int beginLine = ruleViolation.getBeginLine();
-            outputLineLink( beginLine );
-            int endLine = ruleViolation.getEndLine();
-            if ( endLine != beginLine )
+        boolean fileSectionStarted = false;
+        String previousFilename = null;
+        for ( RuleViolation ruleViolation : violations )
+        {
+            String currentFn = ruleViolation.getFilename();
+            if ( !currentFn.equalsIgnoreCase( previousFilename ) && fileSectionStarted )
+            {
+                endFileSection();
+                fileSectionStarted = false;
+            }
+            if ( !fileSectionStarted )
             {
-                sink.text( " - " );
-                outputLineLink( endLine );
+                fileInfo = fileLookup.get( currentFn );
+                startFileSection( currentFn, fileInfo );
+                fileSectionStarted = true;
             }
 
-            sink.tableCell_();
-            sink.tableRow_();
+            processSingleRuleViolation( ruleViolation );
+
+            previousFilename = currentFn;
+        }
+
+        if ( fileSectionStarted )
+        {
+            endFileSection();
         }
-        violations.clear();
     }
 
     private void outputLineLink( int line )
@@ -199,26 +249,7 @@ public class PmdReportListener
         // 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 )
@@ -250,9 +281,8 @@ public class PmdReportListener
         sink.tableHeaderCell_();
         sink.tableRow_();
 
-        for ( Iterator iter = metrics.iterator(); iter.hasNext(); )
+        for ( Metric met : metrics )
         {
-            Metric met = (Metric) iter.next();
             sink.tableRow();
             sink.tableCell();
             sink.text( met.getMetricName() );
@@ -274,10 +304,12 @@ public class PmdReportListener
         sink.table_();
         sink.section1_();
     }
-    */
+*/
 
     public void endDocument()
     {
+        processViolations();
+
         if ( fileCount == 0 )
         {
             sink.paragraph();
@@ -292,7 +324,7 @@ public class PmdReportListener
         // of excessive imports metrics, none of which is really any use.
         // TODO Determine if we are going to just ignore metrics.
 
-        // processMetrics();
+//        processMetrics();
 
         sink.body_();
 
@@ -300,4 +332,8 @@ public class PmdReportListener
 
         sink.close();
     }
+
+    public void setFiles(Map<File, PmdFileInfo> files) {
+        this.files = files;
+    }
 }
\ No newline at end of file

Modified: maven/plugins/trunk/maven-pmd-plugin/src/main/resources/rulesets/maven.xml
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-pmd-plugin/src/main/resources/rulesets/maven.xml?rev=1341175&r1=1341174&r2=1341175&view=diff
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/src/main/resources/rulesets/maven.xml (original)
+++ maven/plugins/trunk/maven-pmd-plugin/src/main/resources/rulesets/maven.xml Mon May 21 19:58:41 2012
@@ -32,16 +32,16 @@ under the License.
     This ruleset checks the code for discouraged programming constructs.
   </description>
   
-  <rule ref="rulesets/basic.xml">
+  <rule ref="rulesets/java/basic.xml">
     <exclude name="EmptyCatchBlock"/>
   </rule>
-  <rule ref="rulesets/basic.xml/EmptyCatchBlock">
+  <rule ref="rulesets/java/basic.xml/EmptyCatchBlock">
     <properties>
       <property name="allowCommentedBlocks" value="true"/>
     </properties>
   </rule>
 
-  <rule ref="rulesets/unusedcode.xml"/>
+  <rule ref="rulesets/java/unusedcode.xml"/>
 
-  <rule ref="rulesets/imports.xml"/>
+  <rule ref="rulesets/java/imports.xml"/>
 </ruleset>

Modified: maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/CpdReportTest.java
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/CpdReportTest.java?rev=1341175&r1=1341174&r2=1341175&view=diff
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/CpdReportTest.java (original)
+++ maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/CpdReportTest.java Mon May 21 19:58:41 2012
@@ -31,8 +31,8 @@ import javax.xml.parsers.DocumentBuilder
 import javax.xml.parsers.DocumentBuilderFactory;
 
 import net.sourceforge.pmd.cpd.CPD;
+import net.sourceforge.pmd.cpd.CPDConfiguration;
 import net.sourceforge.pmd.cpd.JavaLanguage;
-import net.sourceforge.pmd.cpd.Language;
 import net.sourceforge.pmd.cpd.Match;
 import net.sourceforge.pmd.cpd.TokenEntry;
 
@@ -201,7 +201,8 @@ public class CpdReportTest
         tMatch.setSourceCodeSlice( "// ----- ACCESSEURS  avec �l�ments -----" );
         tList.add( tMatch );
 
-        CPD tCpd = new MockCpd( 100, new JavaLanguage(), tList.iterator() );
+        CPDConfiguration cpdConfiguration = new CPDConfiguration( 100, new JavaLanguage(), "UTF-8" );
+        CPD tCpd = new MockCpd( cpdConfiguration, tList.iterator() );
 
         tCpd.go();
         mojo.writeNonHtml( tCpd );
@@ -220,9 +221,9 @@ public class CpdReportTest
 
         private Iterator<Match> matches;
 
-        public MockCpd( int minimumTileSize, Language language, Iterator<Match> tMatch )
+        public MockCpd( CPDConfiguration configuration, Iterator<Match> tMatch )
         {
-            super( minimumTileSize, language );
+            super( configuration );
             matches = tMatch;
         }
 

Modified: maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/PmdReportTest.java
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/PmdReportTest.java?rev=1341175&r1=1341174&r2=1341175&view=diff
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/PmdReportTest.java (original)
+++ maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/PmdReportTest.java Mon May 21 19:58:41 2012
@@ -62,13 +62,14 @@ public class PmdReportTest
         File generatedFile = new File( getBasedir(), "target/test/unit/default-configuration/target/pmd.xml" );
         assertTrue( FileUtils.fileExists( generatedFile.getAbsolutePath() ) );
 
-        generatedFile = new File( getBasedir(), "target/test/unit/default-configuration/target/basic.xml" );
+        // check if the rulesets, that have been applied, have been copied
+        generatedFile = new File( getBasedir(), "target/test/unit/default-configuration/target/java-basic.xml" );
         assertTrue( FileUtils.fileExists( generatedFile.getAbsolutePath() ) );
 
-        generatedFile = new File( getBasedir(), "target/test/unit/default-configuration/target/imports.xml" );
+        generatedFile = new File( getBasedir(), "target/test/unit/default-configuration/target/java-imports.xml" );
         assertTrue( FileUtils.fileExists( generatedFile.getAbsolutePath() ) );
 
-        generatedFile = new File( getBasedir(), "target/test/unit/default-configuration/target/unusedcode.xml" );
+        generatedFile = new File( getBasedir(), "target/test/unit/default-configuration/target/java-unusedcode.xml" );
         assertTrue( FileUtils.fileExists( generatedFile.getAbsolutePath() ) );
 
         generatedFile = new File( getBasedir(), "target/test/unit/default-configuration/target/site/pmd.html" );
@@ -96,9 +97,9 @@ public class PmdReportTest
                                  "src/test/resources/unit/default-configuration/default-configuration-plugin-config.xml" );
         PmdReport mojo = (PmdReport) lookupMojo( "pmd", testPom );
 
-        URL url = getClass().getClassLoader().getResource( "rulesets/basic.xml" );
-        URL url2 = getClass().getClassLoader().getResource( "rulesets/unusedcode.xml" );
-        URL url3 = getClass().getClassLoader().getResource( "rulesets/imports.xml" );
+        URL url = getClass().getClassLoader().getResource( "rulesets/java/basic.xml" );
+        URL url2 = getClass().getClassLoader().getResource( "rulesets/java/unusedcode.xml" );
+        URL url3 = getClass().getClassLoader().getResource( "rulesets/java/imports.xml" );
         mojo.setRulesets( new String[]{ url.toString(), url2.toString(), url3.toString() } );
 
         mojo.execute();
@@ -181,8 +182,6 @@ public class PmdReportTest
         PmdReport mojo = (PmdReport) lookupMojo( "pmd", testPom );
         mojo.execute();
 
-        File basedir = new File( getBasedir(), "target/test/unit/skip-configuration" );
-
         // verify the generated files do not exist because PMD was skipped
         File generatedFile = new File( getBasedir(), "target/test/unit/skip-configuration/target/pmd.csv" );
         assertFalse( FileUtils.fileExists( generatedFile.getAbsolutePath() ) );
@@ -281,7 +280,7 @@ public class PmdReportTest
         PmdReport mojo = (PmdReport) lookupMojo( "pmd", testPom );
 
         assertEquals( "locationTemp is not correctly encoding filename",
-                      "export_format_pmd_language_java_name_some_2520name", mojo.getLocationTemp(
+                      "export_format_pmd_language_java_name_some_2520name.xml", mojo.getLocationTemp(
             "http://nemo.sonarsource.org/sonar/profiles/export?format=pmd&language=java&name=some%2520name" ) );
 
     }

Modified: maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/PmdViolationCheckMojoTest.java
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/PmdViolationCheckMojoTest.java?rev=1341175&r1=1341174&r2=1341175&view=diff
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/PmdViolationCheckMojoTest.java (original)
+++ maven/plugins/trunk/maven-pmd-plugin/src/test/java/org/apache/maven/plugin/pmd/PmdViolationCheckMojoTest.java Mon May 21 19:58:41 2012
@@ -76,6 +76,11 @@ public class PmdViolationCheckMojoTest
         throws Exception
     {
         File testPom = new File( getBasedir(),
+                "src/test/resources/unit/default-configuration/default-configuration-plugin-config.xml" );
+        PmdReport mojo = (PmdReport) lookupMojo( "pmd", testPom );
+        mojo.execute();
+
+        testPom = new File( getBasedir(),
                                  "src/test/resources/unit/default-configuration/pmd-check-failonpriority-plugin-config.xml" );
         PmdViolationCheckMojo pmdViolationMojo = (PmdViolationCheckMojo) lookupMojo( "check", testPom );
         pmdViolationMojo.execute();

Modified: maven/plugins/trunk/maven-pmd-plugin/src/test/resources/unit/custom-configuration/custom-configuration-plugin-config.xml
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-pmd-plugin/src/test/resources/unit/custom-configuration/custom-configuration-plugin-config.xml?rev=1341175&r1=1341174&r2=1341175&view=diff
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/src/test/resources/unit/custom-configuration/custom-configuration-plugin-config.xml (original)
+++ maven/plugins/trunk/maven-pmd-plugin/src/test/resources/unit/custom-configuration/custom-configuration-plugin-config.xml Mon May 21 19:58:41 2012
@@ -42,9 +42,9 @@ under the License.
           <sourceEncoding>ISO-8859-1</sourceEncoding>
           <rulesets>
             <ruleset>${basedir}/src/test/resources/unit/custom-configuration/resources/rulesets/custom.xml</ruleset>
-            <ruleset>rulesets/basic.xml</ruleset>
-            <ruleset>rulesets/unusedcode.xml</ruleset>
-            <ruleset>rulesets/imports.xml</ruleset>
+            <ruleset>java-basic</ruleset>
+            <ruleset>rulesets/java/unusedcode.xml</ruleset>
+            <ruleset>java-imports</ruleset>
           </rulesets>
           <targetJdk>1.4</targetJdk>
           <minimumPriority>4</minimumPriority>          

Modified: maven/plugins/trunk/maven-pmd-plugin/src/test/resources/unit/custom-configuration/resources/rulesets/custom.xml
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-pmd-plugin/src/test/resources/unit/custom-configuration/resources/rulesets/custom.xml?rev=1341175&r1=1341174&r2=1341175&view=diff
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/src/test/resources/unit/custom-configuration/resources/rulesets/custom.xml (original)
+++ maven/plugins/trunk/maven-pmd-plugin/src/test/resources/unit/custom-configuration/resources/rulesets/custom.xml Mon May 21 19:58:41 2012
@@ -22,13 +22,13 @@ under the License.
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
   <description>Just the braces rules I like</description>
-  <rule ref="rulesets/braces.xml">
+  <rule ref="rulesets/java/braces.xml">
     <exclude name="WhileLoopsMustUseBracesRule"/>
     <exclude name="IfElseStmtsMustUseBracesRule"/>
   </rule>   
   
   <description>Lowest priority for unnecessary constructor</description>
-  <rule ref="rulesets/controversial.xml/UnnecessaryConstructor" >
+  <rule ref="rulesets/java/controversial.xml/UnnecessaryConstructor" >
 	<priority>5</priority>
   </rule>