View Javadoc

    1   /***
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.ant;
    5
    6   import net.sourceforge.pmd.PMD;
    7   import net.sourceforge.pmd.PMDException;
    8   import net.sourceforge.pmd.Report;
    9   import net.sourceforge.pmd.Rule;
    10  import net.sourceforge.pmd.RuleContext;
    11  import net.sourceforge.pmd.RuleSet;
    12  import net.sourceforge.pmd.RuleSetFactory;
    13  import net.sourceforge.pmd.RuleSetNotFoundException;
    14  import net.sourceforge.pmd.RuleSets;
    15  import net.sourceforge.pmd.SimpleRuleSetNameMapper;
    16  import net.sourceforge.pmd.SourceType;
    17  import org.apache.tools.ant.AntClassLoader;
    18  import org.apache.tools.ant.BuildException;
    19  import org.apache.tools.ant.DirectoryScanner;
    20  import org.apache.tools.ant.Project;
    21  import org.apache.tools.ant.Task;
    22  import org.apache.tools.ant.types.FileSet;
    23  import org.apache.tools.ant.types.Path;
    24  import org.apache.tools.ant.types.Reference;
    25
    26  import java.io.BufferedInputStream;
    27  import java.io.File;
    28  import java.io.FileInputStream;
    29  import java.io.FileNotFoundException;
    30  import java.io.PrintWriter;
    31  import java.io.StringWriter;
    32  import java.util.ArrayList;
    33  import java.util.Collection;
    34  import java.util.Iterator;
    35  import java.util.List;
    36
    37  public class PMDTask extends Task {
    38
    39      private Path classpath;
    40      private List formatters = new ArrayList();
    41      private List filesets = new ArrayList();
    42      private int minPriority = Rule.LOWEST_PRIORITY;
    43      private boolean shortFilenames;
    44      private String ruleSetFiles;
    45      private String encoding = System.getProperty("file.encoding");
    46      private boolean failOnError;
    47      private boolean failOnRuleViolation;
    48      private String targetJDK = "1.4";
    49      private String failuresPropertyName;
    50      private String excludeMarker;
    51      private final Collection nestedRules = new ArrayList();
    52
    53      public void setShortFilenames(boolean value) {
    54          this.shortFilenames = value;
    55      }
    56
    57      public void setTargetJDK(String value) {
    58          this.targetJDK = value;
    59      }
    60
    61      public void setExcludeMarker(String value) {
    62          this.excludeMarker = value;
    63      }
    64
    65      public void setFailOnError(boolean fail) {
    66          this.failOnError = fail;
    67      }
    68
    69      public void setFailOnRuleViolation(boolean fail) {
    70          this.failOnRuleViolation = fail;
    71      }
    72
    73      public void setRuleSetFiles(String ruleSetFiles) {
    74          this.ruleSetFiles = ruleSetFiles;
    75      }
    76
    77      public void setEncoding(String encoding) {
    78          this.encoding = encoding;
    79      }
    80
    81      public void setFailuresPropertyName(String failuresPropertyName) {
    82          this.failuresPropertyName = failuresPropertyName;
    83      }
    84
    85      public void setMinimumPriority(int minPriority) {
    86          this.minPriority = minPriority;
    87      }
    88
    89      public void addFileset(FileSet set) {
    90          filesets.add(set);
    91      }
    92
    93      public void addFormatter(Formatter f) {
    94          formatters.add(f);
    95      }
    96
    97      public void setClasspath(Path classpath) {
    98          this.classpath = classpath;
    99      }
    100
    101     public Path getClasspath() {
    102         return classpath;
    103     }
    104
    105     public Path createClasspath() {
    106         if (classpath == null) {
    107             classpath = new Path(getProject());
    108         }
    109         return classpath.createPath();
    110     }
    111
    112     public void setClasspathRef(Reference r) {
    113         createLongClasspath().setRefid(r);
    114     }
    115
    116     public void execute() throws BuildException {
    117         validate();
    118
    119         ruleSetFiles = new SimpleRuleSetNameMapper(ruleSetFiles).getRuleSets();
    120         RuleSets rules;
    121         try {
    122             RuleSetFactory ruleSetFactory = new RuleSetFactory();
    123             ruleSetFactory.setMinimumPriority(minPriority);
    124             if (classpath == null) {
    125                 log("Using the normal ClassLoader", Project.MSG_VERBOSE);
    126                 rules = ruleSetFactory.createRuleSets(ruleSetFiles);
    127             } else {
    128                 log("Using the AntClassLoader", Project.MSG_VERBOSE);
    129                 rules = ruleSetFactory.createRuleSets(ruleSetFiles, new AntClassLoader(getProject(), classpath));
    130             }
    131         } catch (RuleSetNotFoundException e) {
    132             throw new BuildException(e.getMessage());
    133         }
    134         logRulesUsed(rules);
    135
    136         PMD pmd;
    137         if (targetJDK.equals("1.3")) {
    138             log("Targeting Java language version 1.3", Project.MSG_VERBOSE);
    139             pmd = new PMD();
    140             pmd.setJavaVersion(SourceType.JAVA_13);
    141         } else if (targetJDK.equals("1.5")) {
    142             log("Targeting Java language version 1.5", Project.MSG_VERBOSE);
    143             pmd = new PMD();
    144             pmd.setJavaVersion(SourceType.JAVA_15);
    145         } else if (targetJDK.equals("1.6")) {
    146             log("Targeting Java language version 1.6", Project.MSG_VERBOSE);
    147             pmd = new PMD();
    148             pmd.setJavaVersion(SourceType.JAVA_16);
    149         } else if(targetJDK.equals("jsp")){
    150             log("Targeting JSP", Project.MSG_VERBOSE);
    151             pmd = new PMD();
    152             pmd.setJavaVersion(SourceType.JSP);
    153         } else {
    154             log("Targeting Java language version 1.4", Project.MSG_VERBOSE);
    155             pmd = new PMD();
    156         }
    157
    158         if (excludeMarker != null) {
    159             log("Setting exclude marker to be " + excludeMarker, Project.MSG_VERBOSE);
    160             pmd.setExcludeMarker(excludeMarker);
    161         }
    162
    163         RuleContext ctx = new RuleContext();
    164         Report report = new Report();
    165         ctx.setReport(report);
    166         report.start();
    167         for (Iterator i = filesets.iterator(); i.hasNext();) {
    168             FileSet fs = (FileSet) i.next();
    169             DirectoryScanner ds = fs.getDirectoryScanner(getProject());
    170             String[] srcFiles = ds.getIncludedFiles();
    171             for (int j = 0; j < srcFiles.length; j++) {
    172                 File file = new File(ds.getBasedir() + System.getProperty("file.separator") + srcFiles[j]);
    173                 log("Processing file " + file.getAbsoluteFile().toString(), Project.MSG_VERBOSE);
    174                 ctx.setSourceCodeFilename(shortFilenames ? srcFiles[j] : file.getAbsolutePath());
    175                 try {
    176                     pmd.processFile(new BufferedInputStream(new FileInputStream(file)), encoding, rules, ctx);
    177                 } catch (FileNotFoundException fnfe) {
    178                     if (failOnError) {
    179                         throw new BuildException(fnfe);
    180                     }
    181                 } catch (PMDException pmde) {
    182                     log(pmde.toString(), Project.MSG_VERBOSE);
    183                     if (pmde.getReason() != null) {
    184                         StringWriter strWriter = new StringWriter();
    185                         PrintWriter printWriter = new PrintWriter(strWriter);
    186                         pmde.getReason().printStackTrace(printWriter);
    187                         log(strWriter.toString(), Project.MSG_VERBOSE);
    188                     }
    189                     if (pmde.getReason() != null && pmde.getReason().getMessage() != null) {
    190                         log(pmde.getReason().getMessage(), Project.MSG_VERBOSE);
    191                     }
    192                     if (failOnError) {
    193                         throw new BuildException(pmde);
    194                     }
    195                     ctx.getReport().addError(new Report.ProcessingError(pmde.getMessage(), ctx.getSourceCodeFilename()));
    196                 }
    197             }
    198         }
    199         report.end();
    200
    201         log(ctx.getReport().size() + " problems found", Project.MSG_VERBOSE);
    202
    203         for (Iterator i = formatters.iterator(); i.hasNext();) {
    204             Formatter formatter = (Formatter) i.next();
    205             log("Sending a report to " + formatter, Project.MSG_VERBOSE);
    206             formatter.outputReport(ctx.getReport(), getProject().getBaseDir().toString());
    207         }
    208
    209         if (failuresPropertyName != null && ctx.getReport().size() > 0) {
    210             getProject().setProperty(failuresPropertyName, String.valueOf(ctx.getReport().size()));
    211             log("Setting property " + failuresPropertyName + " to " + ctx.getReport().size(), Project.MSG_VERBOSE);
    212         }
    213
    214         if (failOnRuleViolation && ctx.getReport().size() > 0) {
    215             throw new BuildException("Stopping build since PMD found " + ctx.getReport().size() + " rule violations in the code");
    216         }
    217     }
    218
    219     private void logRulesUsed(net.sourceforge.pmd.RuleSets rules) {
    220         log("Using these rulesets: " + ruleSetFiles, Project.MSG_VERBOSE);
    221
    222         RuleSet[] ruleSets = rules.getAllRuleSets();
    223         for (int j = 0; j < ruleSets.length; j++) {
    224             RuleSet ruleSet = ruleSets[j];
    225
    226             for (Iterator i = ruleSet.getRules().iterator(); i.hasNext();) {
    227                 Rule rule = (Rule) i.next();
    228                 log("Using rule " + rule.getName(), Project.MSG_VERBOSE);
    229             }
    230         }
    231     }
    232
    233     private void validate() throws BuildException {
    234         // TODO - check for empty Formatters List here?
    235         for (Iterator i = formatters.iterator(); i.hasNext();) {
    236             Formatter f = (Formatter) i.next();
    237             if (f.isNoOutputSupplied()) {
    238                 throw new BuildException("toFile or toConsole needs to be specified in Formatter");
    239             }
    240         }
    241
    242         if (ruleSetFiles == null) {
    243             if (nestedRules.isEmpty()) {
    244                 throw new BuildException("No rulesets specified");
    245             }
    246             ruleSetFiles = getNestedRuleSetFiles();
    247         }
    248
    249         if (!targetJDK.equals("1.3") && !targetJDK.equals("1.4") && !targetJDK.equals("1.5") && !targetJDK.equals("1.6") && !targetJDK.equals("jsp")) {
    250             throw new BuildException("The targetjdk attribute, if used, must be set to either '1.3', '1.4', '1.5', '1.6' or 'jsp'");
    251         }
    252     }
    253
    254     private String getNestedRuleSetFiles() {
    255         final StringBuffer sb = new StringBuffer();
    256         for (Iterator it = nestedRules.iterator(); it.hasNext();) {
    257             RuleSetWrapper rs = (RuleSetWrapper) it.next();
    258             sb.append(rs.getFile());
    259             if (it.hasNext()) {
    260                 sb.append(',');
    261             }
    262         }
    263         return sb.toString();
    264     }
    265
    266     private Path createLongClasspath() {
    267         if (classpath == null) {
    268             classpath = new Path(getProject());
    269         }
    270         return classpath.createPath();
    271     }
    272
    273     public void addRuleset(RuleSetWrapper r) {
    274         nestedRules.add(r);
    275     }
    276
    277 }
    278