View Javadoc

    1   /**
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.cpd;
    5
    6   import org.apache.tools.ant.BuildException;
    7   import org.apache.tools.ant.DirectoryScanner;
    8   import org.apache.tools.ant.Project;
    9   import org.apache.tools.ant.Task;
    10  import org.apache.tools.ant.types.EnumeratedAttribute;
    11  import org.apache.tools.ant.types.FileSet;
    12
    13  import java.io.File;
    14  import java.io.IOException;
    15  import java.util.ArrayList;
    16  import java.util.List;
    17  import java.util.Properties;
    18
    19  /**
    20   * CPDTask
    21   * <p/>
    22   * Runs the CPD utility via ant. The ant task looks like this:
    23   * <p/>
    24   * <project name="CPDProj" default="main" basedir=".">
    25   * <taskdef name="cpd" classname="net.sourceforge.pmd.cpd.CPDTask" />
    26   * <target name="main">
    27   * <cpd encoding="UTF-16LE" language="java" ignoreIdentifiers="true" ignoreLiterals="true" ignoreAnnotations="true" minimumTokenCount="100" outputFile="c:\cpdrun.txt">
    28   * <fileset dir="/path/to/my/src">
    29   * <include name="*.java"/>
    30   * </fileset>
    31   * </cpd>
    32   * </target>
    33   * </project>
    34   * <p/>
    35   * Required: minimumTokenCount, outputFile, and at least one file
    36   */
    37  public class CPDTask extends Task {
    38
    39      private static final String TEXT_FORMAT = "text";
    40      private static final String XML_FORMAT = "xml";
    41      private static final String CSV_FORMAT = "csv";
    42
    43      private String format = TEXT_FORMAT;
    44      private String language = "java";
    45      private int minimumTokenCount;
    46      private boolean ignoreLiterals;
    47      private boolean ignoreIdentifiers;
    48      private boolean ignoreAnnotations;
    49      private File outputFile;
    50      private String encoding = System.getProperty("file.encoding");
    51      private List<FileSet> filesets = new ArrayList<FileSet>();
    52
    53      public void execute() throws BuildException {
    54          try {
    55              validateFields();
    56
    57              log("Starting run, minimumTokenCount is " + minimumTokenCount, Project.MSG_INFO);
    58
    59              log("Tokenizing files", Project.MSG_INFO);
    60              CPDConfiguration config = new CPDConfiguration(
    61              		minimumTokenCount, createLanguage(), encoding
    62              		);
    63              CPD cpd = new CPD(config);
    64              tokenizeFiles(cpd);
    65
    66              log("Starting to analyze code", Project.MSG_INFO);
    67              long timeTaken = analyzeCode(cpd);
    68              log("Done analyzing code; that took " + timeTaken + " milliseconds");
    69
    70              log("Generating report", Project.MSG_INFO);
    71              report(cpd);
    72          } catch (IOException ioe) {
    73              log(ioe.toString(), Project.MSG_ERR);
    74              throw new BuildException("IOException during task execution", ioe);
    75          } catch (ReportException re) {
    76              re.printStackTrace();
    77              log(re.toString(), Project.MSG_ERR);
    78              throw new BuildException("ReportException during task execution", re);
    79          }
    80      }
    81
    82      private Language createLanguage() {
    83          Properties p = new Properties();
    84          if (ignoreLiterals) {
    85              p.setProperty(JavaTokenizer.IGNORE_LITERALS, "true");
    86          }
    87          if (ignoreIdentifiers) {
    88              p.setProperty(JavaTokenizer.IGNORE_IDENTIFIERS, "true");
    89          }
    90          if (ignoreAnnotations) {
    91              p.setProperty(JavaTokenizer.IGNORE_ANNOTATIONS, "true");
    92          }
    93          return new LanguageFactory().createLanguage(language, p);
    94      }
    95
    96      private void report(CPD cpd) throws ReportException {
    97          if (!cpd.getMatches().hasNext()) {
    98              log("No duplicates over " + minimumTokenCount + " tokens found", Project.MSG_INFO);
    99          }
    100         Renderer renderer = createRenderer();
    101         FileReporter reporter;
    102         if (outputFile == null) {
    103         	reporter = new FileReporter(encoding);
    104         } else if (outputFile.isAbsolute()) {
    105             reporter = new FileReporter(outputFile, encoding);
    106         } else {
    107             reporter = new FileReporter(new File(getProject().getBaseDir(), outputFile.toString()), encoding);
    108         }
    109         reporter.report(renderer.render(cpd.getMatches()));
    110     }
    111
    112     private void tokenizeFiles(CPD cpd) throws IOException {
    113         for (FileSet fileSet: filesets) {
    114             DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject());
    115             String[] includedFiles = directoryScanner.getIncludedFiles();
    116             for (int i = 0; i < includedFiles.length; i++) {
    117                 File file = new File(directoryScanner.getBasedir() + System.getProperty("file.separator") + includedFiles[i]);
    118                 log("Tokenizing " + file.getAbsolutePath(), Project.MSG_VERBOSE);
    119                 cpd.add(file);
    120             }
    121         }
    122     }
    123
    124     private long analyzeCode(CPD cpd) {
    125         long start = System.currentTimeMillis();
    126         cpd.go();
    127         long stop = System.currentTimeMillis();
    128         return stop - start;
    129     }
    130
    131     private Renderer createRenderer() {
    132         if (format.equals(TEXT_FORMAT)) {
    133             return new SimpleRenderer();
    134         } else if (format.equals(CSV_FORMAT)) {
    135             return new CSVRenderer();
    136         }
    137         return new XMLRenderer();
    138     }
    139
    140     private void validateFields() throws BuildException {
    141         if (minimumTokenCount == 0) {
    142             throw new BuildException("minimumTokenCount is required and must be greater than zero");
    143         } else if (filesets.isEmpty()) {
    144             throw new BuildException("Must include at least one FileSet");
    145         }
    146     }
    147
    148     public void addFileset(FileSet set) {
    149         filesets.add(set);
    150     }
    151
    152     public void setMinimumTokenCount(int minimumTokenCount) {
    153         this.minimumTokenCount = minimumTokenCount;
    154     }
    155
    156     public void setIgnoreLiterals(boolean value) {
    157         this.ignoreLiterals = value;
    158     }
    159
    160     public void setIgnoreIdentifiers(boolean value) {
    161         this.ignoreIdentifiers = value;
    162     }
    163
    164     public void setIgnoreAnnotations(boolean value) {
    165         this.ignoreAnnotations = value;
    166     }
    167
    168     public void setOutputFile(File outputFile) {
    169         this.outputFile = outputFile;
    170     }
    171
    172     public void setFormat(FormatAttribute formatAttribute) {
    173         format = formatAttribute.getValue();
    174     }
    175
    176     public void setLanguage(LanguageAttribute languageAttribute) {
    177         language = languageAttribute.getValue();
    178     }
    179
    180     public void setEncoding(String encodingValue) {
    181         encoding = encodingValue;
    182     }
    183
    184     public static class FormatAttribute extends EnumeratedAttribute {
    185         private static final String[] FORMATS = new String[]{XML_FORMAT, TEXT_FORMAT, CSV_FORMAT};
    186         public String[] getValues() {
    187             return FORMATS;
    188         }
    189     }
    190
    191     public static class LanguageAttribute extends EnumeratedAttribute {
    192         public String[] getValues() {
    193             return LanguageFactory.supportedLanguages;
    194         }
    195     }
    196 }