1 package com.puppycrawl.tools.checkstyle; 20 21 import java.io.File ; 22 import java.io.FileInputStream ; 23 import java.io.FileNotFoundException ; 24 import java.io.FileOutputStream ; 25 import java.io.IOException ; 26 import java.io.OutputStream ; 27 import java.util.ArrayList ; 28 import java.util.Iterator ; 29 import java.util.List ; 30 import java.util.Properties ; 31 import java.util.Hashtable ; 32 import java.util.ResourceBundle ; 33 import java.net.URL ; 34 35 import com.puppycrawl.tools.checkstyle.api.AuditListener; 36 import com.puppycrawl.tools.checkstyle.api.Configuration; 37 import com.puppycrawl.tools.checkstyle.api.SeverityLevelCounter; 38 import com.puppycrawl.tools.checkstyle.api.SeverityLevel; 39 import org.apache.tools.ant.AntClassLoader; 40 import org.apache.tools.ant.BuildException; 41 import org.apache.tools.ant.DirectoryScanner; 42 import org.apache.tools.ant.Project; 43 import org.apache.tools.ant.Task; 44 import org.apache.tools.ant.taskdefs.LogOutputStream; 45 import org.apache.tools.ant.types.EnumeratedAttribute; 46 import org.apache.tools.ant.types.FileSet; 47 import org.apache.tools.ant.types.Path; 48 import org.apache.tools.ant.types.Reference; 49 50 55 public class CheckStyleTask extends Task 56 { 57 58 private static final String E_XML = "xml"; 59 60 private static final String E_PLAIN = "plain"; 61 62 63 private Path mClasspath; 64 65 66 private String mFileName; 67 68 69 private String mConfigLocation; 70 71 72 private File mPackageNamesFile; 73 74 75 private boolean mFailOnViolation = true; 76 77 78 private String mFailureProperty; 79 80 81 private final List mFileSets = new ArrayList (); 82 83 84 private final List mFormatters = new ArrayList (); 85 86 87 private final List mOverrideProps = new ArrayList (); 88 89 90 private File mPropertiesFile; 91 92 93 private int mMaxErrors; 94 95 96 private int mMaxWarnings = Integer.MAX_VALUE; 97 98 102 108 public void setFailureProperty(String aPropertyName) 109 { 110 mFailureProperty = aPropertyName; 111 } 112 113 114 public void setFailOnViolation(boolean aFail) 115 { 116 mFailOnViolation = aFail; 117 } 118 119 123 public void setMaxErrors(int aMaxErrors) 124 { 125 mMaxErrors = aMaxErrors; 126 } 127 128 133 public void setMaxWarnings(int aMaxWarnings) 134 { 135 mMaxWarnings = aMaxWarnings; 136 } 137 138 142 public void addFileset(FileSet aFS) 143 { 144 mFileSets.add(aFS); 145 } 146 147 151 public void addFormatter(Formatter aFormatter) 152 { 153 mFormatters.add(aFormatter); 154 } 155 156 160 public void addProperty(Property aProperty) 161 { 162 mOverrideProps.add(aProperty); 163 } 164 165 169 public void setClasspath(Path aClasspath) 170 { 171 if (mClasspath == null) { 172 mClasspath = aClasspath; 173 } 174 else { 175 mClasspath.append(aClasspath); 176 } 177 } 178 179 183 public void setClasspathRef(Reference aClasspathRef) 184 { 185 createClasspath().setRefid(aClasspathRef); 186 } 187 188 189 public Path createClasspath() 190 { 191 if (mClasspath == null) { 192 mClasspath = new Path(getProject()); 193 } 194 return mClasspath.createPath(); 195 } 196 197 198 public void setFile(File aFile) 199 { 200 mFileName = aFile.getAbsolutePath(); 201 } 202 203 204 public void setConfig(File aFile) 205 { 206 setConfigLocation(aFile.getAbsolutePath()); 207 } 208 209 210 public void setConfigURL(URL aURL) 211 { 212 setConfigLocation(aURL.toExternalForm()); 213 } 214 215 219 private void setConfigLocation(String aLocation) 220 { 221 if (mConfigLocation != null) { 222 throw new BuildException("Attributes 'config' and 'configURL' " 223 + "must not be set at the same time"); 224 } 225 mConfigLocation = aLocation; 226 } 227 228 229 public void setPackageNamesFile(File aFile) 230 { 231 mPackageNamesFile = aFile; 232 } 233 234 238 243 public void setProperties(File aProps) 244 { 245 mPropertiesFile = aProps; 246 } 247 248 252 257 public void execute() throws BuildException 258 { 259 final long startTime = System.currentTimeMillis(); 260 final ClassLoader loader = Thread.currentThread() 261 .getContextClassLoader(); 262 try { 263 Thread.currentThread().setContextClassLoader( 264 getClass().getClassLoader()); 265 realExecute(); 266 } 267 finally { 268 Thread.currentThread().setContextClassLoader(loader); 269 final long endTime = System.currentTimeMillis(); 270 log("Total execution took " + (endTime - startTime) + " ms.", 271 Project.MSG_VERBOSE); 272 } 273 } 274 275 278 private void realExecute() 279 { 280 final ResourceBundle compilationProperties = ResourceBundle 282 .getBundle("checkstylecompilation"); 283 final String version = compilationProperties 284 .getString("checkstyle.compile.version"); 285 final String compileTimestamp = compilationProperties 286 .getString("checkstyle.compile.timestamp"); 287 log("checkstyle version " + version, Project.MSG_VERBOSE); 288 log("compiled on " + compileTimestamp, Project.MSG_VERBOSE); 289 290 if ((mFileName == null) && (mFileSets.size() == 0)) { 292 throw new BuildException( 293 "Must specify atleast one of 'file' or nested 'fileset'.", 294 getLocation()); 295 } 296 297 if (mConfigLocation == null) { 298 throw new BuildException("Must specify 'config'.", getLocation()); 299 } 300 301 Checker c = null; 303 try { 304 c = createChecker(); 305 306 final SeverityLevelCounter warningCounter = 307 new SeverityLevelCounter(SeverityLevel.WARNING); 308 c.addListener(warningCounter); 309 310 long startTime = System.currentTimeMillis(); 312 final File [] files = scanFileSets(); 313 long endTime = System.currentTimeMillis(); 314 log("To locate the files took " + (endTime - startTime) + " ms.", 315 Project.MSG_VERBOSE); 316 317 log("Running Checkstyle " + version + " on " + files.length 318 + " files", Project.MSG_INFO); 319 log("Using configuration " + mConfigLocation, Project.MSG_VERBOSE); 320 321 startTime = System.currentTimeMillis(); 322 final int numErrs = c.process(files); 323 endTime = System.currentTimeMillis(); 324 log("To process the files took " + (endTime - startTime) + " ms.", 325 Project.MSG_VERBOSE); 326 final int numWarnings = warningCounter.getCount(); 327 final boolean ok = (numErrs <= mMaxErrors) 328 && (numWarnings <= mMaxWarnings); 329 330 if (!ok && (mFailureProperty != null)) { 332 getProject().setProperty(mFailureProperty, "true"); 333 } 334 335 if (!ok && mFailOnViolation) { 336 throw new BuildException("Got " + numErrs + " errors and " 337 + numWarnings + " warnings.", getLocation()); 338 } 339 } 340 finally { 341 if (c != null) { 342 c.destroy(); 343 } 344 } 345 } 346 347 351 private Checker createChecker() 352 { 353 Checker c = null; 354 try { 355 final Properties props = createOverridingProperties(); 356 final Configuration config = ConfigurationLoader.loadConfiguration( 357 mConfigLocation, new PropertiesExpander(props), true); 358 359 final DefaultContext context = new DefaultContext(); 360 final ClassLoader loader = new AntClassLoader(getProject(), 361 mClasspath); 362 context.add("classloader", loader); 363 364 c = new Checker(); 365 366 if (mPackageNamesFile != null) { 368 final ModuleFactory moduleFactory = PackageNamesLoader 369 .loadModuleFactory(mPackageNamesFile.getAbsolutePath()); 370 c.setModuleFactory(moduleFactory); 371 } 372 c.contextualize(context); 373 c.configure(config); 374 375 final AuditListener[] listeners = getListeners(); 377 for (int i = 0; i < listeners.length; i++) { 378 c.addListener(listeners[i]); 379 } 380 } 381 catch (final Exception e) { 382 throw new BuildException("Unable to create a Checker: " 383 + e.getMessage(), e); 384 } 385 386 return c; 387 } 388 389 395 private Properties createOverridingProperties() 396 { 397 final Properties retVal = new Properties (); 398 399 if (mPropertiesFile != null) { 401 FileInputStream inStream = null; 402 try { 403 inStream = new FileInputStream (mPropertiesFile); 404 retVal.load(inStream); 405 } 406 catch (final FileNotFoundException e) { 407 throw new BuildException("Could not find Properties file '" 408 + mPropertiesFile + "'", e, getLocation()); 409 } 410 catch (final IOException e) { 411 throw new BuildException("Error loading Properties file '" 412 + mPropertiesFile + "'", e, getLocation()); 413 } 414 finally { 415 try { 416 if (inStream != null) { 417 inStream.close(); 418 } 419 } 420 catch (final IOException e) { 421 throw new BuildException("Error closing Properties file '" 422 + mPropertiesFile + "'", e, getLocation()); 423 } 424 } 425 } 426 427 final Hashtable antProps = this.getProject().getProperties(); 429 for (final Iterator it = antProps.keySet().iterator(); it.hasNext();) { 430 final String key = (String ) it.next(); 431 final String value = String.valueOf(antProps.get(key)); 432 retVal.put(key, value); 433 } 434 435 for (final Iterator it = mOverrideProps.iterator(); it.hasNext();) { 437 final Property p = (Property) it.next(); 438 retVal.put(p.getKey(), p.getValue()); 439 } 440 441 return retVal; 442 } 443 444 452 protected AuditListener[] getListeners() throws ClassNotFoundException , 453 InstantiationException , IllegalAccessException , IOException 454 { 455 final int formatterCount = Math.max(1, mFormatters.size()); 456 457 final AuditListener[] listeners = new AuditListener[formatterCount]; 458 459 if (mFormatters.size() == 0) { 461 final OutputStream debug = new LogOutputStream(this, 462 Project.MSG_DEBUG); 463 final OutputStream err = new LogOutputStream(this, Project.MSG_ERR); 464 listeners[0] = new DefaultLogger(debug, true, err, true); 465 } 466 else { 467 for (int i = 0; i < formatterCount; i++) { 468 final Formatter f = (Formatter) mFormatters.get(i); 469 listeners[i] = f.createListener(this); 470 } 471 } 472 return listeners; 473 } 474 475 479 protected File [] scanFileSets() 480 { 481 final ArrayList list = new ArrayList (); 482 if (mFileName != null) { 483 log("Adding standalone file for audit", Project.MSG_VERBOSE); 486 list.add(new File (mFileName)); 487 } 488 for (int i = 0; i < mFileSets.size(); i++) { 489 final FileSet fs = (FileSet) mFileSets.get(i); 490 final DirectoryScanner ds = fs.getDirectoryScanner(getProject()); 491 ds.scan(); 492 493 final String [] names = ds.getIncludedFiles(); 494 log(i + ") Adding " + names.length + " files from directory " 495 + ds.getBasedir(), Project.MSG_VERBOSE); 496 497 for (int j = 0; j < names.length; j++) { 498 final String pathname = ds.getBasedir() + File.separator 499 + names[j]; 500 list.add(new File (pathname)); 501 } 502 } 503 504 return (File []) list.toArray(new File [0]); 505 } 506 507 511 public static class FormatterType extends EnumeratedAttribute 512 { 513 514 private static final String [] VALUES = {E_XML, E_PLAIN}; 515 516 517 public String [] getValues() 518 { 519 return VALUES; 520 } 521 } 522 523 527 public static class Formatter 528 { 529 530 private FormatterType mFormatterType; 531 532 private File mToFile; 533 534 private boolean mUseFile = true; 535 536 540 public void setType(FormatterType aType) 541 { 542 final String val = aType.getValue(); 543 if (!E_XML.equals(val) && !E_PLAIN.equals(val)) { 544 throw new BuildException("Invalid formatter type: " + val); 545 } 546 547 mFormatterType = aType; 548 } 549 550 554 public void setTofile(File aTo) 555 { 556 mToFile = aTo; 557 } 558 559 563 public void setUseFile(boolean aUse) 564 { 565 mUseFile = aUse; 566 } 567 568 574 public AuditListener createListener(Task aTask) throws IOException 575 { 576 if ((mFormatterType != null) 577 && E_XML.equals(mFormatterType.getValue())) 578 { 579 return createXMLLogger(aTask); 580 } 581 return createDefaultLogger(aTask); 582 } 583 584 589 private AuditListener createDefaultLogger(Task aTask) 590 throws IOException 591 { 592 if ((mToFile == null) || !mUseFile) { 593 return new DefaultLogger( 594 new LogOutputStream(aTask, Project.MSG_DEBUG), 595 true, new LogOutputStream(aTask, Project.MSG_ERR), true); 596 } 597 return new DefaultLogger(new FileOutputStream (mToFile), true); 598 } 599 600 605 private AuditListener createXMLLogger(Task aTask) throws IOException 606 { 607 if ((mToFile == null) || !mUseFile) { 608 return new XMLLogger(new LogOutputStream(aTask, 609 Project.MSG_INFO), true); 610 } 611 return new XMLLogger(new FileOutputStream (mToFile), true); 612 } 613 } 614 615 618 public static class Property 619 { 620 621 private String mKey; 622 623 private String mValue; 624 625 626 public String getKey() 627 { 628 return mKey; 629 } 630 631 632 public void setKey(String aKey) 633 { 634 mKey = aKey; 635 } 636 637 638 public String getValue() 639 { 640 return mValue; 641 } 642 643 644 public void setValue(String aValue) 645 { 646 mValue = aValue; 647 } 648 649 650 public void setFile(File aValue) 651 { 652 setValue(aValue.getAbsolutePath()); 653 } 654 } 655 656 657 public static class Listener 658 { 659 660 private String mClassname; 661 662 663 public String getClassname() 664 { 665 return mClassname; 666 } 667 668 669 public void setClassname(String aClassname) 670 { 671 mClassname = aClassname; 672 } 673 } 674 } 675 | Popular Tags |