001: package org.acm.seguin.pmd.cpd;
002:
003: import org.apache.tools.ant.BuildException;
004: import org.apache.tools.ant.DirectoryScanner;
005: import org.apache.tools.ant.Project;
006: import org.apache.tools.ant.Task;
007: import org.apache.tools.ant.types.EnumeratedAttribute;
008: import org.apache.tools.ant.types.FileSet;
009:
010: import java.io.File;
011: import java.io.IOException;
012: import java.util.ArrayList;
013: import java.util.Iterator;
014: import java.util.List;
015:
016: /**
017: * CPDTask
018: *
019: * Runs the CPD utility via ant. The ant task looks like this:
020: *
021: * <project name="CPDProj" default="main" basedir=".">
022: * <taskdef name="cpd" classname="org.acm.seguin.pmd.cpd.CPDTask" />
023: * <target name="main">
024: * <cpd minimumTokenCount="100" outputFile="c:\cpdrun.txt" verbose=true>
025: * <fileset dir="/path/to/my/src">
026: * <include name="*.java"/>
027: * </fileset>
028: * </cpd>
029: * </target>
030: *</project>
031: *
032: * Required: minimumTokenCount, outputFile, and at least one file
033: * Optional: verbose
034: */
035: public class CPDTask extends Task {
036:
037: private static final String TEXT_FORMAT = "text";
038: private static final String XML_FORMAT = "xml";
039:
040: private String format = TEXT_FORMAT;
041: private int minimumTokenCount;
042: private File outputFile;
043: private List filesets = new ArrayList();
044:
045: public void execute() throws BuildException {
046: try {
047: validateFields();
048:
049: log("Tokenizing files", Project.MSG_INFO);
050: CPD cpd = new CPD(minimumTokenCount, new JavaLanguage());
051: tokenizeFiles(cpd);
052:
053: log("Starting to analyze code", Project.MSG_INFO);
054: long timeTaken = analyzeCode(cpd);
055: log("Done analyzing code; that took " + timeTaken
056: + " milliseconds");
057:
058: log("Generating report", Project.MSG_INFO);
059: report(cpd);
060: } catch (IOException ioe) {
061: log(ioe.toString(), Project.MSG_ERR);
062: throw new BuildException(
063: "IOException during task execution", ioe);
064: } catch (ReportException re) {
065: log(re.toString(), Project.MSG_ERR);
066: throw new BuildException(
067: "ReportException during task execution", re);
068: }
069: }
070:
071: private void report(CPD cpd) throws ReportException {
072: if (!cpd.getMatches().hasNext()) {
073: log("No duplicates over " + minimumTokenCount
074: + " tokens found", Project.MSG_INFO);
075: }
076: Renderer renderer = createRenderer();
077: if (outputFile.isAbsolute()) {
078: new FileReporter(outputFile).report(renderer.render(cpd
079: .getMatches()));
080: } else {
081: new FileReporter(new File(project.getBaseDir(), outputFile
082: .toString()));
083: }
084: }
085:
086: private void tokenizeFiles(CPD cpd) throws IOException {
087: for (Iterator iterator = filesets.iterator(); iterator
088: .hasNext();) {
089: FileSet fileSet = (FileSet) iterator.next();
090: DirectoryScanner directoryScanner = fileSet
091: .getDirectoryScanner(project);
092: String[] includedFiles = directoryScanner
093: .getIncludedFiles();
094: for (int i = 0; i < includedFiles.length; i++) {
095: File file = new File(directoryScanner.getBasedir()
096: + System.getProperty("file.separator")
097: + includedFiles[i]);
098: log("Tokenizing " + file.getAbsolutePath(),
099: Project.MSG_VERBOSE);
100: cpd.add(file);
101: }
102: }
103: }
104:
105: private long analyzeCode(CPD cpd) {
106: long start = System.currentTimeMillis();
107: cpd.go();
108: long stop = System.currentTimeMillis();
109: return stop - start;
110: }
111:
112: private Renderer createRenderer() {
113: if (format.equals(TEXT_FORMAT)) {
114: return new SimpleRenderer();
115: } else
116: return new XMLRenderer();
117: }
118:
119: private void validateFields() throws BuildException {
120: if (minimumTokenCount == 0) {
121: throw new BuildException(
122: "minimumTokenCount is required and must be greater than zero");
123: } else if (outputFile == null) {
124: throw new BuildException(
125: "outputFile is a required attribute");
126: } else if (filesets.isEmpty()) {
127: throw new BuildException(
128: "Must include at least one FileSet");
129: }
130:
131: }
132:
133: public void addFileset(FileSet set) {
134: filesets.add(set);
135: }
136:
137: public void setMinimumTokenCount(int minimumTokenCount) {
138: this .minimumTokenCount = minimumTokenCount;
139: }
140:
141: public void setOutputFile(File outputFile) {
142: this .outputFile = outputFile;
143: }
144:
145: public void setFormat(FormatAttribute formatAttribute) {
146: format = formatAttribute.getValue();
147: }
148:
149: public static class FormatAttribute extends EnumeratedAttribute {
150: private String[] formats = new String[] { XML_FORMAT,
151: TEXT_FORMAT };
152:
153: public String[] getValues() {
154: return formats;
155: }
156: }
157: }
|