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.Iterator;
17  import java.util.List;
18  
19  /***
20   * CPDTask
21   * 
22   * Runs the CPD utility via ant. The ant task looks like this:
23   *
24   * <project name="CPDProj" default="main" basedir=".">
25   *  <taskdef name="cpd" classname="net.sourceforge.pmd.cpd.CPDTask" />
26   *	 <target name="main">
27   * 		<cpd 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   *
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 int minimumTokenCount;
45  	private File outputFile;
46      private List filesets = new ArrayList();
47  
48      public void execute() throws BuildException {
49        try {
50          validateFields();
51  
52          log("Tokenizing files", Project.MSG_INFO);
53          CPD cpd = new CPD(minimumTokenCount, new JavaLanguage());
54          tokenizeFiles(cpd);
55  
56          log("Starting to analyze code", Project.MSG_INFO);
57          long timeTaken = analyzeCode(cpd);
58          log("Done analyzing code; that took " + timeTaken + " milliseconds");
59  
60          log("Generating report", Project.MSG_INFO);
61          report(cpd);
62        } catch (IOException ioe) {
63          log(ioe.toString(), Project.MSG_ERR);
64          throw new BuildException("IOException during task execution", ioe);
65        } catch (ReportException re) {
66          log(re.toString(), Project.MSG_ERR);
67          throw new BuildException("ReportException during task execution", re);
68        }
69      }
70  
71      private void report(CPD cpd) throws ReportException {
72        if (!cpd.getMatches().hasNext()) {
73          log("No duplicates over " + minimumTokenCount + " tokens found", Project.MSG_INFO);
74        }
75        Renderer renderer = createRenderer();
76        if (outputFile.isAbsolute()) {
77          new FileReporter(outputFile).report(renderer.render(cpd.getMatches()));
78        } else {
79          new FileReporter(new File(getProject().getBaseDir(), outputFile.toString()));
80        }
81      }
82  
83  
84      private void tokenizeFiles(CPD cpd) throws IOException {
85        for (Iterator iterator = filesets.iterator(); iterator.hasNext();) {
86          FileSet fileSet = (FileSet) iterator.next();
87          DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject());
88          String[] includedFiles = directoryScanner.getIncludedFiles();
89          for (int i = 0; i < includedFiles.length; i++) {
90            File file = new File(directoryScanner.getBasedir() + System.getProperty("file.separator") + includedFiles[i]);
91            log("Tokenizing " + file.getAbsolutePath(), Project.MSG_VERBOSE);
92            cpd.add(file);
93          }
94        }
95      }
96  
97      private long analyzeCode(CPD cpd) {
98        long start = System.currentTimeMillis();
99        cpd.go();
100       long stop = System.currentTimeMillis();
101       return stop - start;
102     }
103 
104     private Renderer createRenderer() {
105       if (format.equals(TEXT_FORMAT)) {
106         return new SimpleRenderer();
107       } else if (format.equals(CSV_FORMAT)) {
108         return new CSVRenderer();
109       }
110       return new XMLRenderer();
111     }
112 
113 	private void validateFields() throws BuildException{
114 		if(minimumTokenCount == 0){
115 			throw new BuildException("minimumTokenCount is required and must be greater than zero");
116 		} else if(outputFile == null) {
117             throw new BuildException("outputFile is a required attribute");
118         } else if (filesets.isEmpty()) {
119             throw new BuildException("Must include at least one FileSet");
120         }
121 
122 	}
123 
124     public void addFileset(FileSet set) {
125         filesets.add(set);
126     }
127 
128 	public void setMinimumTokenCount(int minimumTokenCount) {
129 		this.minimumTokenCount = minimumTokenCount;
130 	}
131 
132 	public void setOutputFile(File outputFile) {
133 		this.outputFile = outputFile;
134 	}
135 
136     public void setFormat(FormatAttribute formatAttribute) {
137       format = formatAttribute.getValue();
138     }
139 
140     public static class FormatAttribute extends EnumeratedAttribute {
141       private String[] formats = new String[] {XML_FORMAT, TEXT_FORMAT, CSV_FORMAT};
142 
143       public String[] getValues() {
144         return formats;
145       }
146     }
147 }