001: package org.acm.seguin.pmd.ant;
002:
003: import org.acm.seguin.pmd.PMD;
004: import org.acm.seguin.pmd.PMDException;
005: import org.acm.seguin.pmd.Report;
006: import org.acm.seguin.pmd.Rule;
007: import org.acm.seguin.pmd.RuleContext;
008: import org.acm.seguin.pmd.RuleSet;
009: import org.acm.seguin.pmd.RuleSetFactory;
010: import org.acm.seguin.pmd.RuleSetNotFoundException;
011: import org.acm.seguin.pmd.renderers.Renderer;
012: import org.acm.seguin.pmd.renderers.TextRenderer;
013: import org.apache.tools.ant.AntClassLoader;
014: import org.apache.tools.ant.BuildException;
015: import org.apache.tools.ant.DirectoryScanner;
016: import org.apache.tools.ant.Project;
017: import org.apache.tools.ant.Task;
018: import org.apache.tools.ant.types.FileSet;
019: import org.apache.tools.ant.types.Path;
020: import org.apache.tools.ant.types.Reference;
021:
022: import java.io.File;
023: import java.io.FileInputStream;
024: import java.io.FileNotFoundException;
025: import java.io.IOException;
026: import java.io.Writer;
027: import java.util.ArrayList;
028: import java.util.Iterator;
029: import java.util.List;
030:
031: public class PMDTask extends Task {
032:
033: private Path classpath;
034: private List formatters = new ArrayList();
035: private List filesets = new ArrayList();
036: private boolean shortFilenames;
037: private boolean printToConsole;
038: private String ruleSetFiles;
039: private boolean failOnError;
040: private boolean failOnRuleViolation;
041:
042: /**
043: * The end of line string for this machine.
044: */
045: protected String EOL = System.getProperty("line.separator", "\n");
046:
047: public void setShortFilenames(boolean value) {
048: this .shortFilenames = value;
049: }
050:
051: public void setFailOnError(boolean fail) {
052: this .failOnError = fail;
053: }
054:
055: public void setFailOnRuleViolation(boolean fail) {
056: this .failOnRuleViolation = fail;
057: }
058:
059: public void setPrintToConsole(boolean printToConsole) {
060: this .printToConsole = printToConsole;
061: }
062:
063: public void setRuleSetFiles(String ruleSetFiles) {
064: this .ruleSetFiles = ruleSetFiles;
065: }
066:
067: public void addFileset(FileSet set) {
068: filesets.add(set);
069: }
070:
071: public void addFormatter(Formatter f) {
072: formatters.add(f);
073: }
074:
075: public void setClasspath(Path classpath) {
076: this .classpath = classpath;
077: }
078:
079: public Path getClasspath() {
080: return classpath;
081: }
082:
083: public Path createClasspath() {
084: if (classpath == null) {
085: classpath = new Path(getProject());
086: }
087: return classpath.createPath();
088: }
089:
090: public void setClasspathRef(Reference r) {
091: createLongClasspath().setRefid(r);
092: }
093:
094: public void execute() throws BuildException {
095: validate();
096:
097: RuleSet rules;
098: try {
099: RuleSetFactory ruleSetFactory = new RuleSetFactory();
100: if (classpath == null) {
101: log("Using the normal ClassLoader", Project.MSG_VERBOSE);
102: rules = ruleSetFactory.createRuleSet(ruleSetFiles);
103: } else {
104: log("Using the AntClassLoader", Project.MSG_VERBOSE);
105: rules = ruleSetFactory.createRuleSet(ruleSetFiles,
106: new AntClassLoader(project, classpath));
107: }
108: } catch (RuleSetNotFoundException e) {
109: throw new BuildException(e.getMessage());
110: }
111:
112: logRulesUsed(rules);
113:
114: PMD pmd = new PMD();
115: RuleContext ctx = new RuleContext();
116: ctx.setReport(new Report());
117: for (Iterator i = filesets.iterator(); i.hasNext();) {
118: FileSet fs = (FileSet) i.next();
119: DirectoryScanner ds = fs.getDirectoryScanner(project);
120: String[] srcFiles = ds.getIncludedFiles();
121: for (int j = 0; j < srcFiles.length; j++) {
122: File file = new File(ds.getBasedir()
123: + System.getProperty("file.separator")
124: + srcFiles[j]);
125: log("Processing file "
126: + file.getAbsoluteFile().toString(),
127: Project.MSG_VERBOSE);
128: ctx.setSourceCodeFilename(shortFilenames ? srcFiles[j]
129: : file.getAbsolutePath());
130: try {
131: pmd.processFile(new FileInputStream(file), rules,
132: ctx);
133: } catch (FileNotFoundException fnfe) {
134: if (failOnError) {
135: throw new BuildException(fnfe);
136: }
137: } catch (PMDException pmde) {
138: if (pmde.getReason() != null
139: && pmde.getReason().getMessage() != null) {
140: log(pmde.toString(), Project.MSG_VERBOSE);
141: }
142: if (failOnError) {
143: throw new BuildException(pmde);
144: }
145: ctx.getReport().addError(
146: new Report.ProcessingError(pmde
147: .getMessage(), ctx
148: .getSourceCodeFilename()));
149: }
150: }
151: }
152:
153: log(ctx.getReport().size() + " problems found",
154: Project.MSG_VERBOSE);
155:
156: if (!ctx.getReport().isEmpty()) {
157: for (Iterator i = formatters.iterator(); i.hasNext();) {
158: Formatter formatter = (Formatter) i.next();
159: log("Sending a report to " + formatter,
160: Project.MSG_VERBOSE);
161: String buffer = formatter.getRenderer().render(
162: ctx.getReport())
163: + EOL;
164: try {
165: Writer writer = formatter.getToFileWriter(project
166: .getBaseDir().toString());
167: writer.write(buffer, 0, buffer.length());
168: writer.close();
169: } catch (IOException ioe) {
170: throw new BuildException(ioe.getMessage());
171: }
172: }
173:
174: if (printToConsole) {
175: Renderer r = new TextRenderer();
176: log(r.render(ctx.getReport()), Project.MSG_INFO);
177: }
178:
179: if (failOnRuleViolation) {
180: throw new BuildException(
181: "Stopping build since PMD found "
182: + ctx.getReport().size()
183: + " rule violations in the code");
184: }
185: }
186: }
187:
188: private void logRulesUsed(RuleSet rules) {
189: log("Using these rulesets: " + ruleSetFiles,
190: Project.MSG_VERBOSE);
191: for (Iterator i = rules.getRules().iterator(); i.hasNext();) {
192: Rule rule = (Rule) i.next();
193: log("Using rule " + rule.getName(), Project.MSG_VERBOSE);
194: }
195: }
196:
197: private void validate() throws BuildException {
198: if (formatters.isEmpty() && !printToConsole) {
199: throw new BuildException(
200: "No formatter specified; and printToConsole was false");
201: }
202:
203: for (Iterator i = formatters.iterator(); i.hasNext();) {
204: Formatter f = (Formatter) i.next();
205: if (f.isToFileNull()) {
206: throw new BuildException(
207: "Formatter toFile attribute is required");
208: }
209: }
210:
211: if (ruleSetFiles == null) {
212: throw new BuildException("No rulesets specified");
213: }
214: }
215:
216: private Path createLongClasspath() {
217: if (classpath == null) {
218: classpath = new Path(project);
219: }
220: return classpath.createPath();
221: }
222:
223: }
|