1 4 package net.sourceforge.pmd; 5 6 import net.sourceforge.pmd.ast.ParseException; 7 import net.sourceforge.pmd.cpd.FileFinder; 8 import net.sourceforge.pmd.cpd.SourceFileOrDirectoryFilter; 9 import net.sourceforge.pmd.parsers.Parser; 10 import net.sourceforge.pmd.renderers.Renderer; 11 import net.sourceforge.pmd.sourcetypehandlers.SourceTypeHandler; 12 import net.sourceforge.pmd.sourcetypehandlers.SourceTypeHandlerBroker; 13 14 import java.io.BufferedInputStream ; 15 import java.io.BufferedWriter ; 16 import java.io.File ; 17 import java.io.FileWriter ; 18 import java.io.IOException ; 19 import java.io.InputStream ; 20 import java.io.InputStreamReader ; 21 import java.io.OutputStreamWriter ; 22 import java.io.Reader ; 23 import java.io.UnsupportedEncodingException ; 24 import java.io.Writer ; 25 import java.util.ArrayList ; 26 import java.util.Enumeration ; 27 import java.util.Iterator ; 28 import java.util.LinkedList ; 29 import java.util.List ; 30 import java.util.StringTokenizer ; 31 import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService; 32 import edu.emory.mathcs.backport.java.util.concurrent.Executors; 33 import edu.emory.mathcs.backport.java.util.concurrent.ThreadFactory; 34 import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit; 35 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger; 36 import edu.emory.mathcs.backport.java.util.Collections; 37 import java.util.zip.ZipEntry ; 38 import java.util.zip.ZipFile ; 39 40 public class PMD { 41 public static final String EOL = System.getProperty("line.separator", "\n"); 42 public static final String VERSION = "3.9"; 43 public static final String EXCLUDE_MARKER = "NOPMD"; 44 45 46 private String excludeMarker = EXCLUDE_MARKER; 47 private SourceTypeDiscoverer sourceTypeDiscoverer = new SourceTypeDiscoverer(); 48 49 public PMD() {} 50 51 60 public void processFile(Reader reader, RuleSets ruleSets, RuleContext ctx) 61 throws PMDException { 62 SourceType sourceType = getSourceTypeOfFile(ctx.getSourceCodeFilename()); 63 64 processFile(reader, ruleSets, ctx, sourceType); 65 } 66 67 77 public void processFile(Reader reader, RuleSets ruleSets, RuleContext ctx, 78 SourceType sourceType) throws PMDException { 79 try { 80 SourceTypeHandler sourceTypeHandler = SourceTypeHandlerBroker.getVisitorsFactoryForSourceType(sourceType); 81 ctx.setSourceType(sourceType); 82 Parser parser = sourceTypeHandler.getParser(); 83 parser.setExcludeMarker(excludeMarker); 84 Object rootNode = parser.parse(reader); 85 ctx.excludeLines(parser.getExcludeMap()); 86 Thread.yield(); 87 sourceTypeHandler.getSymbolFacade().start(rootNode); 88 89 Language language = SourceTypeToRuleLanguageMapper.getMappedLanguage(sourceType); 90 91 if (ruleSets.usesDFA(language)) { 92 sourceTypeHandler.getDataFlowFacade().start(rootNode); 93 } 94 95 if (ruleSets.usesTypeResolution(language)) { 96 sourceTypeHandler.getTypeResolutionFacade().start(rootNode); 97 } 98 99 List acus = new ArrayList (); 100 acus.add(rootNode); 101 102 ruleSets.apply(acus, ctx, language); 103 } catch (ParseException pe) { 104 throw new PMDException("Error while parsing " 105 + ctx.getSourceCodeFilename(), pe); 106 } catch (Exception e) { 107 throw new PMDException("Error while processing " 108 + ctx.getSourceCodeFilename(), e); 109 } finally { 110 try { 111 reader.close(); 112 } catch (IOException e) { 113 throw new PMDException("Error while closing " 114 + ctx.getSourceCodeFilename(), e); 115 } 116 } 117 } 118 119 129 private SourceType getSourceTypeOfFile(String fileName) { 130 SourceType sourceType = sourceTypeDiscoverer.getSourceTypeOfFile(fileName); 131 if (sourceType == null) { 132 sourceType = sourceTypeDiscoverer.getSourceTypeOfJavaFiles(); 135 } 136 return sourceType; 137 } 138 139 148 public void processFile(Reader reader, RuleSet ruleSet, RuleContext ctx) 149 throws PMDException { 150 processFile(reader, new RuleSets(ruleSet), ctx); 151 } 152 153 164 public void processFile(InputStream fileContents, String encoding, 165 RuleSet ruleSet, RuleContext ctx) throws PMDException { 166 try { 167 processFile(new InputStreamReader (fileContents, encoding), ruleSet, ctx); 168 } catch (UnsupportedEncodingException uee) { 169 throw new PMDException("Unsupported encoding exception: " 170 + uee.getMessage()); 171 } 172 } 173 174 185 public void processFile(InputStream fileContents, String encoding, 186 RuleSets ruleSets, RuleContext ctx) throws PMDException { 187 try { 188 processFile(new InputStreamReader (fileContents, encoding), ruleSets, ctx); 189 } catch (UnsupportedEncodingException uee) { 190 throw new PMDException("Unsupported encoding exception: " 191 + uee.getMessage()); 192 } 193 } 194 195 206 public void processFile(InputStream fileContents, RuleSet ruleSet, 207 RuleContext ctx) throws PMDException { 208 processFile(fileContents, System.getProperty("file.encoding"), ruleSet, ctx); 209 } 210 211 public void setExcludeMarker(String marker) { 212 this.excludeMarker = marker; 213 } 214 215 220 public void setJavaVersion(SourceType javaVersion) { 221 sourceTypeDiscoverer.setSourceTypeOfJavaFiles(javaVersion); 222 } 223 224 public static void main(String [] args) { 225 CommandLineOptions opts = new CommandLineOptions(args); 226 227 SourceFileSelector fileSelector = new SourceFileSelector(); 228 229 fileSelector.setSelectJavaFiles(opts.isCheckJavaFiles()); 230 fileSelector.setSelectJspFiles(opts.isCheckJspFiles()); 231 232 List files; 233 if (opts.containsCommaSeparatedFileList()) { 234 files = collectFromCommaDelimitedString(opts.getInputPath(), 235 fileSelector); 236 } else { 237 files = collectFilesFromOneName(opts.getInputPath(), fileSelector); 238 } 239 240 SourceType sourceType; 241 if (opts.getTargetJDK().equals("1.3")) { 242 if (opts.debugEnabled()) 243 System.out.println("In JDK 1.3 mode"); 244 sourceType = SourceType.JAVA_13; 245 } else if (opts.getTargetJDK().equals("1.5")) { 246 if (opts.debugEnabled()) 247 System.out.println("In JDK 1.5 mode"); 248 sourceType = SourceType.JAVA_15; 249 } else if (opts.getTargetJDK().equals("1.6")) { 250 if (opts.debugEnabled()) 251 System.out.println("In JDK 1.6 mode"); 252 sourceType = SourceType.JAVA_16; 253 } else { 254 if (opts.debugEnabled()) 255 System.out.println("In JDK 1.4 mode"); 256 sourceType = SourceType.JAVA_14; 257 } 258 259 RuleContext ctx = new RuleContext(); 260 Report report = new Report(); 261 ctx.setReport(report); 262 report.start(); 263 264 try { 265 RuleSetFactory ruleSetFactory = new RuleSetFactory(); 266 ruleSetFactory.setMinimumPriority(opts.getMinPriority()); 267 268 RuleSets rulesets = ruleSetFactory.createRuleSets(opts.getRulesets()); 269 printRuleNamesInDebug(opts.debugEnabled(), rulesets); 270 271 processFiles(opts.getCpus(), ruleSetFactory, sourceType, files, ctx, 272 opts.getRulesets(), opts.debugEnabled(), opts.shortNamesEnabled(), 273 opts.getInputPath(), opts.getEncoding(), opts.getExcludeMarker()); 274 } catch (RuleSetNotFoundException rsnfe) { 275 System.out.println(opts.usage()); 276 rsnfe.printStackTrace(); 277 } 278 report.end(); 279 280 Writer w = null; 281 try { 282 Renderer r = opts.createRenderer(); 283 if (opts.getReportFile() != null) { 284 w = new BufferedWriter (new FileWriter (opts.getReportFile())); 285 } else { 286 w = new OutputStreamWriter (System.out); 287 } 288 r.render(w, ctx.getReport()); 289 w.write(EOL); 290 w.flush(); 291 if (opts.getReportFile() != null) { 292 w.close(); 293 } 294 } catch (Exception e) { 295 System.out.println(e.getMessage()); 296 System.out.println(opts.usage()); 297 if (opts.debugEnabled()) { 298 e.printStackTrace(); 299 } 300 } finally { 301 if (opts.getReportFile() != null && w != null) { 302 try { 303 w.close(); 304 } catch (Exception e) { 305 System.out.println(e.getMessage()); 306 } 307 } 308 } 309 } 310 311 private static class PmdRunnable extends PMD implements Runnable { 312 private final ExecutorService executor; 313 private final DataSource dataSource; 314 private final String fileName; 315 private final boolean debugEnabled; 316 private final String encoding; 317 private final String rulesets; 318 319 public PmdRunnable(ExecutorService executor, DataSource dataSource, String fileName, SourceType sourceType, 320 boolean debugEnabled, String encoding, String rulesets, String excludeMarker) { 321 this.executor = executor; 322 this.dataSource = dataSource; 323 this.fileName = fileName; 324 this.debugEnabled = debugEnabled; 325 this.encoding = encoding; 326 this.rulesets = rulesets; 327 328 setJavaVersion(sourceType); 329 setExcludeMarker(excludeMarker); 330 } 331 332 public void run() { 333 PmdThread thread = (PmdThread) Thread.currentThread(); 334 335 RuleContext ctx = thread.getRuleContext(); 336 RuleSets rs = thread.getRuleSets(rulesets); 337 338 ctx.setSourceCodeFilename(fileName); 339 if (debugEnabled) { 340 System.out.println("Processing " + ctx.getSourceCodeFilename()); 341 } 342 343 try { 344 InputStream stream = new BufferedInputStream (dataSource.getInputStream()); 345 processFile(stream, encoding, rs, ctx); 346 } catch (PMDException pmde) { 347 if (debugEnabled) { 348 pmde.getReason().printStackTrace(); 349 } 350 ctx.getReport().addError( 351 new Report.ProcessingError(pmde.getMessage(), 352 fileName)); 353 } catch (Throwable t) { 354 if (debugEnabled) { 356 t.printStackTrace(); 357 } 358 ctx.getReport().addError( 359 new Report.ProcessingError(t.getMessage(), 360 fileName)); 361 362 executor.shutdownNow(); 363 } 364 } 365 366 } 367 368 private static class PmdThreadFactory implements ThreadFactory { 369 370 public PmdThreadFactory(RuleSetFactory ruleSetFactory) { 371 this.ruleSetFactory = ruleSetFactory; 372 } 373 374 private final RuleSetFactory ruleSetFactory; 375 private final AtomicInteger counter = new AtomicInteger(); 376 377 public Thread newThread(Runnable r) { 378 PmdThread t = new PmdThread(counter.incrementAndGet(), r, ruleSetFactory); 379 threadList.add(t); 380 return t; 381 } 382 383 public List threadList = Collections.synchronizedList(new LinkedList ()); 384 385 } 386 387 private static class PmdThread extends Thread { 388 389 public PmdThread(int id, Runnable r, RuleSetFactory ruleSetFactory) { 390 super(r, "PmdThread " + id); 391 this.id = id; 392 context = new RuleContext(); 393 context.setReport(new Report()); 394 this.ruleSetFactory = ruleSetFactory; 395 } 396 397 private int id; 398 private RuleContext context; 399 private RuleSets rulesets; 400 private RuleSetFactory ruleSetFactory; 401 402 public RuleContext getRuleContext() { 403 return context; 404 } 405 406 public RuleSets getRuleSets(String rsList) { 407 if (rulesets == null) { 408 try { 409 rulesets = ruleSetFactory.createRuleSets(rsList); 410 } catch (Exception e) { 411 e.printStackTrace(); 412 } 413 } 414 return rulesets; 415 } 416 417 public String toString() { 418 return "PmdThread " + id; 419 } 420 421 } 422 423 428 public static void processFiles(int threadCount, RuleSetFactory ruleSetFactory, SourceType sourceType, List files, RuleContext ctx, String rulesets, 429 boolean debugEnabled, boolean shortNamesEnabled, String inputPath, 430 String encoding, String excludeMarker) { 431 432 PmdThreadFactory factory = new PmdThreadFactory(ruleSetFactory); 433 ExecutorService executor = Executors.newFixedThreadPool(threadCount, factory); 434 435 for (Iterator i = files.iterator(); i.hasNext();) { 436 DataSource dataSource = (DataSource) i.next(); 437 String niceFileName = dataSource.getNiceFileName(shortNamesEnabled, 438 inputPath); 439 440 Runnable r = new PmdRunnable(executor, dataSource, niceFileName, sourceType, debugEnabled, 441 encoding, rulesets, excludeMarker); 442 443 executor.execute(r); 444 } 445 executor.shutdown(); 446 447 try { 448 executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); 449 } catch (InterruptedException e) { 450 } 451 452 Report mainReport = ctx.getReport(); 453 Iterator i = factory.threadList.iterator(); 454 while (i.hasNext()) { 455 PmdThread thread = (PmdThread) i.next(); 456 Report r = thread.context.getReport(); 457 mainReport.merge(r); 458 } 459 } 460 461 474 public void processFiles(List files, RuleContext ctx, RuleSets rulesets, 475 boolean debugEnabled, boolean shortNamesEnabled, String inputPath, 476 String encoding) throws IOException { 477 for (Iterator i = files.iterator(); i.hasNext();) { 478 DataSource dataSource = (DataSource) i.next(); 479 480 String niceFileName = dataSource.getNiceFileName(shortNamesEnabled, 481 inputPath); 482 ctx.setSourceCodeFilename(niceFileName); 483 if (debugEnabled) { 484 System.out.println("Processing " + ctx.getSourceCodeFilename()); 485 } 486 487 try { 488 InputStream stream = new BufferedInputStream (dataSource 489 .getInputStream()); 490 processFile(stream, encoding, rulesets, ctx); 491 } catch (PMDException pmde) { 492 if (debugEnabled) { 493 pmde.getReason().printStackTrace(); 494 } 495 ctx.getReport().addError(new Report.ProcessingError(pmde.getMessage(), niceFileName)); 496 } 497 } 498 } 499 500 506 private static void printRuleNamesInDebug(boolean debugEnabled, RuleSets rulesets) { 507 if (debugEnabled) { 508 for (Iterator i = rulesets.getAllRules().iterator(); i.hasNext();) { 509 Rule r = (Rule) i.next(); 510 System.out.println("Loaded rule " + r.getName()); 511 } 512 } 513 } 514 515 523 private static List collectFilesFromOneName(String inputFileName, 524 SourceFileSelector fileSelector) { 525 return collect(inputFileName, fileSelector); 526 } 527 528 535 private static List collectFromCommaDelimitedString(String fileList, 536 SourceFileSelector fileSelector) { 537 List files = new ArrayList (); 538 for (StringTokenizer st = new StringTokenizer (fileList, ","); st 539 .hasMoreTokens();) { 540 files.addAll(collect(st.nextToken(), fileSelector)); 541 } 542 return files; 543 } 544 545 553 private static List collect(String filename, SourceFileSelector fileSelector) { 554 File inputFile = new File (filename); 555 if (!inputFile.exists()) { 556 throw new RuntimeException ("File " + inputFile.getName() 557 + " doesn't exist"); 558 } 559 List dataSources = new ArrayList (); 560 if (!inputFile.isDirectory()) { 561 if (filename.endsWith(".zip") || filename.endsWith(".jar")) { 562 ZipFile zipFile; 563 try { 564 zipFile = new ZipFile (inputFile); 565 Enumeration e = zipFile.entries(); 566 while (e.hasMoreElements()) { 567 ZipEntry zipEntry = (ZipEntry ) e.nextElement(); 568 if (fileSelector.isWantedFile(zipEntry.getName())) { 569 dataSources.add(new ZipDataSource(zipFile, zipEntry)); 570 } 571 } 572 } catch (IOException ze) { 573 throw new RuntimeException ("Zip file " + inputFile.getName() 574 + " can't be opened"); 575 } 576 } else { 577 dataSources.add(new FileDataSource(inputFile)); 578 } 579 } else { 580 FileFinder finder = new FileFinder(); 581 List files = finder.findFilesFrom(inputFile.getAbsolutePath(), 582 new SourceFileOrDirectoryFilter(fileSelector), true); 583 for (Iterator i = files.iterator(); i.hasNext();) { 584 dataSources.add(new FileDataSource((File ) i.next())); 585 } 586 } 587 return dataSources; 588 } 589 590 } 591 592 593 | Popular Tags |