Coverage Report - org.apache.maven.plugin.pmd.CpdReport
 
Classes in this File Line Coverage Branch Coverage Complexity
CpdReport
75 %
54/72
50 %
15/30
3,333
 
 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.ByteArrayOutputStream;
 23  
 import java.io.File;
 24  
 import java.io.FileOutputStream;
 25  
 import java.io.IOException;
 26  
 import java.io.OutputStreamWriter;
 27  
 import java.io.UnsupportedEncodingException;
 28  
 import java.io.Writer;
 29  
 import java.util.Iterator;
 30  
 import java.util.Locale;
 31  
 import java.util.Map;
 32  
 import java.util.Properties;
 33  
 import java.util.ResourceBundle;
 34  
 
 35  
 import net.sourceforge.pmd.cpd.CPD;
 36  
 import net.sourceforge.pmd.cpd.CSVRenderer;
 37  
 import net.sourceforge.pmd.cpd.JavaLanguage;
 38  
 import net.sourceforge.pmd.cpd.JavaTokenizer;
 39  
 import net.sourceforge.pmd.cpd.Renderer;
 40  
 import net.sourceforge.pmd.cpd.XMLRenderer;
 41  
 
 42  
 import org.apache.maven.reporting.MavenReportException;
 43  
 import org.codehaus.plexus.util.FileUtils;
 44  
 import org.codehaus.plexus.util.IOUtil;
 45  
 import org.codehaus.plexus.util.WriterFactory;
 46  
 import org.codehaus.plexus.util.StringUtils;
 47  
 
 48  
 /**
 49  
  * Creates a report for PMD's CPD tool.  See
 50  
  * <a href="http://pmd.sourceforge.net/cpd.html">http://pmd.sourceforge.net/cpd.html</a>
 51  
  * for more detail.
 52  
  *
 53  
  * @author Mike Perham
 54  
  * @version $Id: org.apache.maven.plugin.pmd.CpdReport.html 816688 2012-05-08 15:14:44Z hboutemy $
 55  
  * @since 2.0
 56  
  * @goal cpd
 57  
  */
 58  10
 public class CpdReport
 59  
     extends AbstractPmdReport
 60  
 {
 61  
     /**
 62  
      * The minimum number of tokens that need to be duplicated before it causes a violation.
 63  
      *
 64  
      * @parameter expression="${minimumTokens}" default-value="100"
 65  
      */
 66  
     private int minimumTokens;
 67  
 
 68  
     /**
 69  
      * Skip the CPD report generation.  Most useful on the command line
 70  
      * via "-Dcpd.skip=true".
 71  
      *
 72  
      * @parameter expression="${cpd.skip}" default-value="false"
 73  
      * @since 2.1
 74  
      */
 75  
     private boolean skip;
 76  
 
 77  
     /**
 78  
      * If true, CPD ignores literal value differences when evaluating a duplicate block.
 79  
      * This means that <code>foo=42;</code> and <code>foo=43;</code> will be seen as equivalent.
 80  
      * You may want to run PMD with this option off to start with and then switch it on to see what it turns up.
 81  
      *
 82  
      * @parameter expression="${cpd.ignoreLiterals}" default-value="false"
 83  
      * @since 2.5
 84  
      */
 85  
     private boolean ignoreLiterals;
 86  
 
 87  
     /**
 88  
      * Similar to <code>ignoreLiterals</code> but for identifiers; i.e., variable names, methods names, and so forth.
 89  
      *
 90  
      * @parameter expression="${cpd.ignoreIdentifiers}" default-value="false"
 91  
      * @since 2.5
 92  
      */
 93  
     private boolean ignoreIdentifiers;
 94  
 
 95  
     /** {@inheritDoc} */
 96  
     public String getName( Locale locale )
 97  
     {
 98  0
         return getBundle( locale ).getString( "report.cpd.name" );
 99  
     }
 100  
 
 101  
     /** {@inheritDoc} */
 102  
     public String getDescription( Locale locale )
 103  
     {
 104  0
         return getBundle( locale ).getString( "report.cpd.description" );
 105  
     }
 106  
 
 107  
     /** {@inheritDoc} */
 108  
     public void executeReport( Locale locale )
 109  
         throws MavenReportException
 110  
     {
 111  
         try
 112  
         {
 113  8
             execute( locale );
 114  
         }
 115  
         finally
 116  
         {
 117  8
             if ( getSink() != null )
 118  
             {
 119  8
                 getSink().close();
 120  
             }
 121  
         }
 122  6
     }
 123  
 
 124  
     private void execute( Locale locale )
 125  
         throws MavenReportException
 126  
     {
 127  8
         if ( !skip && canGenerateReport() )
 128  
         {
 129  6
             ClassLoader origLoader = Thread.currentThread().getContextClassLoader();
 130  
             try
 131  
             {
 132  6
                 Thread.currentThread().setContextClassLoader( this.getClass().getClassLoader() );
 133  
 
 134  6
                 CPD cpd = generateReport( locale );
 135  
 
 136  6
                 if ( !isHtml() )
 137  
                 {
 138  6
                     writeNonHtml( cpd );
 139  
                 }
 140  
             }
 141  
             finally
 142  
             {
 143  6
                 Thread.currentThread().setContextClassLoader( origLoader );
 144  6
             }
 145  
 
 146  
         }
 147  6
     }
 148  
 
 149  
     private CPD generateReport( Locale locale )
 150  
         throws MavenReportException
 151  
     {
 152  6
         Properties p = new Properties();
 153  6
         if ( ignoreLiterals )
 154  
         {
 155  0
             p.setProperty( JavaTokenizer.IGNORE_LITERALS, "true" );
 156  
         }
 157  6
         if ( ignoreIdentifiers )
 158  
         {
 159  0
             p.setProperty( JavaTokenizer.IGNORE_IDENTIFIERS, "true" );
 160  
         }
 161  6
         CPD cpd = new CPD( minimumTokens, new JavaLanguage( p ) );
 162  
 
 163  6
         Map files = null;
 164  
         try
 165  
         {
 166  6
             files = getFilesToProcess();
 167  
 
 168  6
             if ( StringUtils.isNotEmpty( getSourceEncoding() ) )
 169  
             {
 170  6
                 cpd.setEncoding( getSourceEncoding() );
 171  
 
 172  
                 // test encoding as CPD will convert exception into a RuntimeException
 173  6
                 WriterFactory.newWriter( new ByteArrayOutputStream(), getSourceEncoding() );
 174  
             }
 175  0
             else if ( !files.isEmpty() )
 176  
             {
 177  0
                 getLog().warn(
 178  
                                "File encoding has not been set, using platform encoding "
 179  
                                    + WriterFactory.FILE_ENCODING + ", i.e. build is platform dependent!" );
 180  
             }
 181  
 
 182  6
             for ( Iterator it = files.keySet().iterator(); it.hasNext(); )
 183  
             {
 184  18
                 cpd.add( (File) it.next() );
 185  
             }
 186  
         }
 187  0
         catch ( UnsupportedEncodingException e )
 188  
         {
 189  0
             throw new MavenReportException( "Encoding '" + getSourceEncoding() + "' is not supported.", e );
 190  
         }
 191  0
         catch ( IOException e )
 192  
         {
 193  0
             throw new MavenReportException( e.getMessage(), e );
 194  6
         }
 195  6
         cpd.go();
 196  
 
 197  6
         CpdReportGenerator gen =
 198  
             new CpdReportGenerator( getSink(), files, getBundle( locale ), aggregate );
 199  6
         gen.generate( cpd.getMatches() );
 200  
 
 201  6
         return cpd;
 202  
     }
 203  
 
 204  
     void writeNonHtml( CPD cpd )
 205  
         throws MavenReportException
 206  
     {
 207  8
         Renderer r = createRenderer();
 208  
 
 209  8
         if ( r == null )
 210  
         {
 211  0
             return;
 212  
         }
 213  
 
 214  8
         String buffer = r.render( cpd.getMatches() );
 215  8
         Writer writer = null;
 216  
         try
 217  
         {
 218  8
             targetDirectory.mkdirs();
 219  8
             File targetFile = new File( targetDirectory, "cpd." + format );
 220  8
             FileOutputStream tStream = new FileOutputStream( targetFile );
 221  8
             writer = new OutputStreamWriter( tStream, getOutputEncoding() );
 222  8
             writer.write( buffer );
 223  8
             writer.close();
 224  
 
 225  8
             File siteDir = getReportOutputDirectory();
 226  8
             siteDir.mkdirs();
 227  8
             FileUtils.copyFile( targetFile, new File( siteDir, "cpd." + format ) );
 228  
         }
 229  0
         catch ( IOException ioe )
 230  
         {
 231  0
             throw new MavenReportException( ioe.getMessage(), ioe );
 232  
         }
 233  
         finally
 234  
         {
 235  8
             IOUtil.close( writer );
 236  8
         }
 237  8
     }
 238  
 
 239  
     /** {@inheritDoc} */
 240  
     public String getOutputName()
 241  
     {
 242  14
         return "cpd";
 243  
     }
 244  
 
 245  
     private static ResourceBundle getBundle( Locale locale )
 246  
     {
 247  8
         return ResourceBundle.getBundle( "cpd-report", locale, CpdReport.class.getClassLoader() );
 248  
     }
 249  
 
 250  
     /**
 251  
      * Create and return the correct renderer for the output type.
 252  
      *
 253  
      * @return the renderer based on the configured output
 254  
      * @throws org.apache.maven.reporting.MavenReportException
 255  
      *          if no renderer found for the output type
 256  
      */
 257  
     public Renderer createRenderer()
 258  
         throws MavenReportException
 259  
     {
 260  8
         Renderer renderer = null;
 261  8
         if ( "xml".equals( format ) )
 262  
         {
 263  6
             renderer = new XMLRenderer( getOutputEncoding() );
 264  
         }
 265  2
         else if ( "csv".equals( format ) )
 266  
         {
 267  2
             renderer = new CSVRenderer();
 268  
         }
 269  0
         else if ( !"".equals( format ) && !"none".equals( format ) )
 270  
         {
 271  
             try
 272  
             {
 273  0
                 renderer = (Renderer) Class.forName( format ).newInstance();
 274  
             }
 275  0
             catch ( Exception e )
 276  
             {
 277  0
                 throw new MavenReportException(
 278  
                     "Can't find CPD custom format " + format + ": " + e.getClass().getName() );
 279  0
             }
 280  
         }
 281  
 
 282  8
         return renderer;
 283  
     }
 284  
 }