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