View Javadoc

1   /***
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd;
5   
6   import net.sourceforge.pmd.ast.ASTCompilationUnit;
7   import net.sourceforge.pmd.ast.JavaParser;
8   import net.sourceforge.pmd.ast.ParseException;
9   import net.sourceforge.pmd.cpd.FileFinder;
10  import net.sourceforge.pmd.cpd.JavaLanguage;
11  import net.sourceforge.pmd.dfa.DataFlowFacade;
12  import net.sourceforge.pmd.renderers.Renderer;
13  import net.sourceforge.pmd.symboltable.SymbolFacade;
14  import net.sourceforge.pmd.jaxen.AttributeAxisIterator;
15  
16  import java.io.BufferedInputStream;
17  import java.io.File;
18  import java.io.FileNotFoundException;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.InputStreamReader;
22  import java.io.Reader;
23  import java.io.UnsupportedEncodingException;
24  import java.util.ArrayList;
25  import java.util.Enumeration;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.StringTokenizer;
29  import java.util.zip.ZipEntry;
30  import java.util.zip.ZipFile;
31  
32  public class PMD {
33  
34      public static final String EOL = System.getProperty("line.separator", "\n");
35      public static final String VERSION = "3.3";
36  
37      private TargetJDKVersion targetJDKVersion;
38      private String excludeMarker = ExcludeLines.EXCLUDE_MARKER;
39  
40      public PMD() {
41          this(new TargetJDK1_4());
42      }
43  
44      public PMD(TargetJDKVersion targetJDKVersion) {
45          this.targetJDKVersion = targetJDKVersion;
46      }
47  
48      /***
49       * Processes the file read by the reader agains the rule set.
50       *
51       * @param reader  input stream reader
52       * @param ruleSet set of rules to process against the file
53       * @param ctx     context in which PMD is operating.  This contains the Renderer and whatnot
54       * @throws PMDException if the input could not be parsed or processed
55       */
56      public void processFile(Reader reader, RuleSet ruleSet, RuleContext ctx) throws PMDException {
57          try {
58              ExcludeLines excluder = new ExcludeLines(reader, excludeMarker);
59              ctx.excludeLines(excluder.getLinesToExclude());
60  
61              JavaParser parser = targetJDKVersion.createParser(excluder.getCopyReader());
62              ASTCompilationUnit c = parser.CompilationUnit();
63              Thread.yield();
64  
65              // TODO - move SymbolFacade traversal inside JavaParser.CompilationUnit()
66              SymbolFacade stb = new SymbolFacade();
67              stb.initializeWith(c);
68  
69              if (ruleSet.usesDFA()) {
70                  DataFlowFacade dff = new DataFlowFacade();
71                  dff.initializeWith(c);
72              }
73  
74              List acus = new ArrayList();
75              acus.add(c);
76              ruleSet.apply(acus, ctx);
77              reader.close();
78          } catch (ParseException pe) {
79              throw new PMDException("Error while parsing " + ctx.getSourceCodeFilename(), pe);
80          } catch (Exception e) {
81              throw new PMDException("Error while processing " + ctx.getSourceCodeFilename(), e);
82          }
83      }
84  
85      /***
86       * Processes the input stream agains a rule set using the given input
87       * encoding.
88       *
89       * @param fileContents an input stream to analyze
90       * @param encoding     input stream's encoding
91       * @param ruleSet      set of rules to process against the file
92       * @param ctx          context in which PMD is operating.  This contains the Report and whatnot
93       * @throws PMDException if the input encoding is unsupported or the input
94       *                      stream could not be parsed
95       * @see #processFile(Reader, RuleSet, RuleContext)
96       */
97      public void processFile(InputStream fileContents, String encoding, RuleSet ruleSet, RuleContext ctx) throws PMDException {
98          try {
99              processFile(new InputStreamReader(fileContents, encoding), ruleSet, ctx);
100         } catch (UnsupportedEncodingException uee) {
101             throw new PMDException("Unsupported encoding exception: " + uee.getMessage());
102         }
103     }
104 
105     /***
106      * Processes the input stream against a rule set assuming the platform
107      * character set.
108      *
109      * @param fileContents input stream to check
110      * @param ruleSet      the set of rules to process against the source code
111      * @param ctx          the context in which PMD is operating.  This contains the Report and whatnot
112      * @throws PMDException if the input encoding is unsupported or the input
113      *                      input stream could not be parsed
114      * @see #processFile(InputStream, String, RuleSet, RuleContext)
115      */
116     public void processFile(InputStream fileContents, RuleSet ruleSet, RuleContext ctx) throws PMDException {
117         processFile(fileContents, System.getProperty("file.encoding"), ruleSet, ctx);
118     }
119 
120     public void setExcludeMarker(String marker) {
121         this.excludeMarker = marker;
122     }
123 
124 
125     public static void main(String[] args) {
126         CommandLineOptions opts = new CommandLineOptions(args);
127 
128         List files;
129         if (opts.containsCommaSeparatedFileList()) {
130             files = collectFromCommaDelimitedString(opts.getInputPath());
131         } else {
132             files = collectFilesFromOneName(opts.getInputPath());
133         }
134 
135         PMD pmd;
136         if (opts.getTargetJDK().equals("1.3")) {
137             if (opts.debugEnabled()) System.out.println("In JDK 1.3 mode");
138             pmd = new PMD(new TargetJDK1_3());
139         } else if (opts.getTargetJDK().equals("1.5")) {
140             if (opts.debugEnabled()) System.out.println("In JDK 1.5 mode");
141             pmd = new PMD(new TargetJDK1_5());
142         } else {
143             if (opts.debugEnabled()) System.out.println("In JDK 1.4 mode");
144             pmd = new PMD();
145         }
146         pmd.setExcludeMarker(opts.getExcludeMarker());
147 
148         RuleContext ctx = new RuleContext();
149         Report report = new Report();
150         ctx.setReport(report);
151         report.start();
152 
153         try {
154             RuleSetFactory ruleSetFactory = new RuleSetFactory();
155             RuleSet rules = ruleSetFactory.createRuleSet(opts.getRulesets());
156             if (opts.debugEnabled()) {
157                 for (Iterator i = rules.getRules().iterator(); i.hasNext();) {
158                     Rule r = (Rule)i.next();
159                     System.out.println("Loaded rule " + r.getName());
160                 }
161             }
162 
163             for (Iterator i = files.iterator(); i.hasNext();) {
164                 DataSource dataSource = (DataSource) i.next();
165                 String niceFileName = dataSource.getNiceFileName(opts.shortNamesEnabled(), opts.getInputPath());
166                 ctx.setSourceCodeFilename(niceFileName);
167                 if (opts.debugEnabled()) {
168                     System.out.println("Processing " + ctx.getSourceCodeFilename());
169                 }
170                 try {
171                     pmd.processFile(new BufferedInputStream(dataSource.getInputStream()), opts.getEncoding(), rules, ctx);
172                 } catch (PMDException pmde) {
173                     if (opts.debugEnabled()) {
174                         pmde.getReason().printStackTrace();
175                     }
176                     ctx.getReport().addError(new Report.ProcessingError(pmde.getMessage(), niceFileName));
177                 }
178             }
179         } catch (FileNotFoundException fnfe) {
180             System.out.println(opts.usage());
181             fnfe.printStackTrace();
182         } catch (RuleSetNotFoundException rsnfe) {
183             System.out.println(opts.usage());
184             rsnfe.printStackTrace();
185         } catch (IOException ioe) {
186             System.out.println(opts.usage());
187             ioe.printStackTrace();
188         }
189         report.end();
190 
191         try {
192             Renderer r = opts.createRenderer();
193             System.out.println(r.render(ctx.getReport()));
194         } catch (Exception e) {
195             System.out.println(e.getMessage());
196             System.out.println(opts.usage());
197             if (opts.debugEnabled()) {
198                 e.printStackTrace();
199             }
200         }
201     }
202 
203     /***
204      * Collects the given file into a list.
205      *
206      * @param inputFileName a file name
207      * @return the list of files collected from the <code>inputFileName</code>
208      * @see #collect(String)
209      */
210     private static List collectFilesFromOneName(String inputFileName) {
211         return collect(inputFileName);
212     }
213 
214     /***
215      * Collects the files from the given comma-separated list.
216      *
217      * @param fileList comma-separated list of filenames
218      * @return list of files collected from the <code>fileList</code>
219      */
220     private static List collectFromCommaDelimitedString(String fileList) {
221         List files = new ArrayList();
222         for (StringTokenizer st = new StringTokenizer(fileList, ","); st.hasMoreTokens();) {
223             files.addAll(collect(st.nextToken()));
224         }
225         return files;
226     }
227 
228     /***
229      * Collects the files from the given <code>filename</code>.
230      *
231      * @param filename the source from which to collect files
232      * @return a list of files found at the given <code>filename</code>
233      * @throws RuntimeException if <code>filename</code> is not found
234      */
235     private static List collect(String filename) {
236         File inputFile = new File(filename);
237         if (!inputFile.exists()) {
238             throw new RuntimeException("File " + inputFile.getName() + " doesn't exist");
239         }
240         List dataSources = new ArrayList();
241         if (!inputFile.isDirectory()) {
242             if (filename.endsWith(".zip") || filename.endsWith(".jar")) {
243                 ZipFile zipFile;
244                 try {
245                     zipFile = new ZipFile(inputFile);
246                     Enumeration e = zipFile.entries();
247                     while (e.hasMoreElements()) {
248                         ZipEntry zipEntry = (ZipEntry) e.nextElement();
249                         if (zipEntry.getName().endsWith(".java")) {
250                             dataSources.add(new ZipDataSource(zipFile, zipEntry));
251                         }
252                     }
253                 } catch (IOException ze) {
254                     throw new RuntimeException("Zip file " + inputFile.getName() + " can't be opened");
255                 }
256             } else {
257                 dataSources.add(new FileDataSource(inputFile));
258             }
259         } else {
260             FileFinder finder = new FileFinder();
261             List files = finder.findFilesFrom(inputFile.getAbsolutePath(), new JavaLanguage.JavaFileOrDirectoryFilter(), true);
262             for (Iterator i = files.iterator(); i.hasNext();) {
263                 dataSources.add(new FileDataSource((File) i.next()));
264             }
265         }
266         return dataSources;
267     }
268 
269 }