View Javadoc
1 /* 2 3 */ 4 package attrib4j.ant; 5 6 import java.io.File; 7 import java.io.FileWriter; 8 import java.io.FilenameFilter; 9 import java.io.IOException; 10 import java.io.PrintWriter; 11 import java.util.Enumeration; 12 import java.util.StringTokenizer; 13 import java.util.Vector; 14 15 import org.apache.tools.ant.BuildException; 16 import org.apache.tools.ant.DirectoryScanner; 17 import org.apache.tools.ant.Project; 18 import org.apache.tools.ant.Task; 19 import org.apache.tools.ant.taskdefs.Execute; 20 import org.apache.tools.ant.taskdefs.Javac; 21 import org.apache.tools.ant.taskdefs.LogOutputStream; 22 import org.apache.tools.ant.taskdefs.PumpStreamHandler; 23 import org.apache.tools.ant.types.Commandline; 24 import org.apache.tools.ant.types.DirSet; 25 import org.apache.tools.ant.types.FileSet; 26 import org.apache.tools.ant.types.Path; 27 import org.apache.tools.ant.types.PatternSet; 28 import org.apache.tools.ant.types.Reference; 29 import org.apache.tools.ant.util.FileUtils; 30 import org.apache.tools.ant.util.JavaEnvUtils; 31 32 /*** 33 * A custom Ant task to run Attrib4 that supports the following syntax. 34 * <attrib4j sourcepath="${src}/main" 35 * classpath="${build}/classes" 36 * destdir="${dist}" 37 * loglevel="info" 38 * attributepackages="attrib4j.examples.attributes"> 39 * 40 * It also is a helper class to the Attrib4jCompilerAdapter 41 * 42 * It will eventually support running both the Sun JDK javadoc engine 43 * and alternative javadoc engines. Now heavily influenced from the 44 * Ant javadoc task. 45 * 46 * 47 * @author Mark.Pollack 48 */ 49 public class Attrib4jTask extends Task { 50 51 //Stuff specifc for using Sun JDK javadoc engine. 52 53 /*** 54 * Used to track info about the packages to be javadoc'd 55 */ 56 public static class PackageName { 57 /*** The package name *//package-summary/html">color="#AA0000">* The package name *//package-summary.html">/*** The package name *//package-summary.html">color="#AA0000">* The package name */ 58 private String name; 59 60 /*** 61 * Set the name of the package 62 * 63 * @param name the package name. 64 */ 65 public void setName(String name) { 66 this.name = name.trim(); 67 } 68 69 /*** 70 * Get the package name. 71 * 72 * @return the package's name. 73 */ 74 public String getName() { 75 return name; 76 } 77 78 /*** 79 * @see java.lang.Object#toString 80 */ 81 public String toString() { 82 return getName(); 83 } 84 } 85 86 /*** 87 * This class is used to manage the source files to be processed. 88 */ 89 public static class SourceFile { 90 /*** The source file */ 91 private File file; 92 93 public SourceFile() { 94 } 95 public SourceFile(File file) { 96 this.file = file; 97 } 98 99 /*** 100 * Set the source file. 101 * 102 * @param file the source file. 103 */ 104 public void setFile(File file) { 105 this.file = file; 106 } 107 108 /*** 109 * Get the source file. 110 * 111 * @return the source file. 112 */ 113 public File getFile() { 114 return file; 115 } 116 117 public String toString() { 118 return file.toString(); 119 } 120 } 121 122 /*** The command line built to execute Javadoc. */ 123 private Commandline cmd = new Commandline(); 124 125 /*** Flag which indicates if javadoc from JDK 1.1 is to be used. */ 126 //TODO: There are not doclets in 1.1. Think about removing. 127 private static boolean javadoc1 = 128 JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1); 129 130 /*** Flag which indicates if javadoc from JDK 1.4 is available */ 131 private static boolean javadoc4 = 132 (!JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1) 133 && !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2) 134 && !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3)); 135 136 /*** 137 * Flag which indicates if the task should fail if there is a 138 * javadoc error. 139 */ 140 private boolean failOnError = false; 141 private Path sourcePath = null; 142 143 /*** 144 * The packages that contain attribute. Used to prepend to 145 * the classname given as an attribute so as not to require 146 * using the fully qualified classname. 147 */ 148 private String attributePackages = null; 149 150 /*** 151 * Logging level for attrib4j. 152 */ 153 private String loglevel = "INFO"; 154 155 private File destDir = null; 156 private Vector sourceFiles = new Vector(); 157 private Vector packageNames = new Vector(5); 158 private Vector excludePackageNames = new Vector(1); 159 private boolean author = true; 160 private boolean version = true; 161 private Path classpath = null; 162 private Path bootclasspath = null; 163 164 private Path docletPath = null; 165 166 private String packageList = null; 167 private Vector tags = new Vector(5); 168 private boolean useDefaultExcludes = true; 169 private boolean useExternalFile = false; 170 private FileUtils fileUtils = FileUtils.newFileUtils(); 171 private String source = null; 172 173 private Vector fileSets = new Vector(); 174 private Vector packageSets = new Vector(); 175 176 /*** 177 * Work around command line length limit by using an external file 178 * for the sourcefiles. 179 * 180 * @param b true if an external file is to be used. 181 */ 182 public void setUseExternalFile(boolean b) { 183 if (!javadoc1) { 184 useExternalFile = b; 185 } 186 } 187 188 /*** 189 * Set the maximum memory to be used by the javadoc process 190 * 191 * @param max a string indicating the maximum memory according to the 192 * JVM conventions (e.g. 128m is 128 Megabytes) 193 */ 194 public void setMaxmemory(String max) { 195 if (javadoc1) { 196 cmd.createArgument().setValue("-J-mx" + max); 197 } else { 198 cmd.createArgument().setValue("-J-Xmx" + max); 199 } 200 } 201 202 /*** 203 * Specify where to find source file 204 * 205 * @param src a Path instance containing the various source directories. 206 */ 207 public void setSourcepath(Path src) { 208 if (sourcePath == null) { 209 sourcePath = src; 210 } else { 211 sourcePath.append(src); 212 } 213 } 214 215 public void setAttributePackages(String packages) { 216 attributePackages = packages; 217 } 218 219 public void setLoglevel(String level) { 220 loglevel = level; 221 } 222 223 /*** 224 * Create a path to be configured with the locations of the source 225 * files. 226 * 227 * @return a new Path instance to be configured by the Ant core. 228 */ 229 public Path createSourcepath() { 230 if (sourcePath == null) { 231 sourcePath = new Path(project); 232 } 233 return sourcePath.createPath(); 234 } 235 236 /*** 237 * Adds a reference to a CLASSPATH defined elsewhere. 238 * 239 * @param r the reference containing the source path definition. 240 */ 241 public void setSourcepathRef(Reference r) { 242 createSourcepath().setRefid(r); 243 } 244 245 /*** 246 * Set the directory where the Javadoc output will be generated. 247 * 248 * @param dir the destination directory. 249 */ 250 public void setDestdir(File dir) { 251 destDir = dir; 252 } 253 254 /*** 255 * Set the list of source files to process. 256 * 257 * @param src a comma separated list of source files. 258 */ 259 public void setSourcefiles(String src) { 260 StringTokenizer tok = new StringTokenizer(src, ","); 261 while (tok.hasMoreTokens()) { 262 String f = tok.nextToken(); 263 SourceFile sf = new SourceFile(); 264 sf.setFile(project.resolveFile(f)); 265 addSource(sf); 266 } 267 } 268 269 /*** 270 * Add a single source file. 271 * 272 * @param sf the source file to be processed. 273 */ 274 public void addSource(SourceFile sf) { 275 sourceFiles.addElement(sf); 276 } 277 278 /*** 279 * Set the package names to be processed. 280 * 281 * @param packages a comma separated list of packages specs 282 * (may be wildcarded). 283 * 284 * @see #addPackage for wildcard information. 285 */ 286 public void setPackagenames(String packages) { 287 StringTokenizer tok = new StringTokenizer(packages, ","); 288 while (tok.hasMoreTokens()) { 289 String p = tok.nextToken(); 290 PackageName pn = new PackageName(); 291 pn.setName(p); 292 addPackage(pn); 293 } 294 } 295 296 /*** 297 * Add a single package to be processed. 298 * 299 * If the package name ends with ".*" the Javadoc task 300 * will find and process all subpackages. 301 * 302 * @param pn the package name, possibly wildcarded. 303 */ 304 public void addPackage(PackageName pn) { 305 packageNames.addElement(pn); 306 } 307 308 /*** 309 * Set the list of packages to be excluded. 310 * 311 * @param packages a comma separated list of packages to be excluded. 312 * This may not include wildcards. 313 */ 314 public void setExcludePackageNames(String packages) { 315 StringTokenizer tok = new StringTokenizer(packages, ","); 316 while (tok.hasMoreTokens()) { 317 String p = tok.nextToken(); 318 PackageName pn = new PackageName(); 319 pn.setName(p); 320 addExcludePackage(pn); 321 } 322 } 323 324 /*** 325 * Add a package to be excluded from the javadoc run. 326 * 327 * @param pn the name of the package (wildcards are not permitted). 328 */ 329 public void addExcludePackage(PackageName pn) { 330 excludePackageNames.addElement(pn); 331 } 332 333 /*** 334 * Adds a fileset. 335 * 336 * <p>All included files will be added as sourcefiles. The task 337 * will automatically add 338 * <code>includes="**/*.java"</code> to the 339 * fileset.</p> 340 * 341 * @since 1.5 342 */ 343 public void addFileset(FileSet fs) { 344 fileSets.addElement(fs); 345 } 346 347 /*** 348 * Set the classpath to be used for this javadoc run. 349 * 350 * @param path an Ant Path object containing the compilation 351 * classpath. 352 */ 353 public void setClasspath(Path path) { 354 if (classpath == null) { 355 classpath = path; 356 } else { 357 classpath.append(path); 358 } 359 } 360 361 /*** 362 * Create a Path to be configured with the classpath to use 363 * 364 * @return a new Path instance to be configured with the classpath. 365 */ 366 public Path createClasspath() { 367 if (classpath == null) { 368 classpath = new Path(project); 369 } 370 return classpath.createPath(); 371 } 372 373 /*** 374 * Adds a reference to a CLASSPATH defined elsewhere. 375 * 376 * @param r the reference to an instance defining the classpath. 377 */ 378 public void setClasspathRef(Reference r) { 379 createClasspath().setRefid(r); 380 } 381 382 /*** 383 * Set the classpath used to find the doclet class. 384 * 385 * @param docletPath the doclet classpath. 386 */ 387 public void setDocletPath(Path docletPath) { 388 this.docletPath = docletPath; 389 } 390 391 392 public String setupAttrib4j(Javac javac) { 393 if (null == javac) { 394 return "null javac"; 395 } 396 setProject(javac.getProject()); 397 setLocation(javac.getLocation()); 398 setTaskName("javac-attrib4j"); 399 400 setSourcepath(javac.getSourcepath()); 401 setClasspath(javac.getClasspath()); 402 403 //Some wierd stuff to set the classpath 404 Path destPath = new Path(javac.getProject()); 405 destPath.setLocation(javac.getDestdir()); 406 setClasspath(destPath); 407 408 //list of files to compile from javac task...don't have a fileset anymore like 409 //in the javadoc task. 410 File[] javacSourceFiles = javac.getFileList(); 411 if (javacSourceFiles != null) { 412 for (int i = 0; i < javacSourceFiles.length; i++) { 413 sourceFiles.add(new SourceFile(javacSourceFiles[i])); 414 } 415 } 416 417 String attribDestdir = javac.getProject().getProperty("attrib4j.destdir"); 418 File f = new File(attribDestdir); 419 setDestdir(f); 420 421 setAttributePackages(javac.getProject().getProperty("attrib4j.packages")); 422 423 424 return null; 425 } 426 427 public void execute() throws BuildException { 428 429 log("*************************************", Project.MSG_INFO); 430 log("*Compiling Attributes using Javadoc *", Project.MSG_INFO); 431 432 433 Vector packagesToDoc = new Vector(); 434 Path sourceDirs = new Path(getProject()); 435 436 log("* sourceDirs = " + sourceDirs); 437 <b>if (packageList != null && sourcePath == null) { 438 String msg = 439 "sourcePath attribute must be set when " 440 + "specifying packagelist."; 441 throw new BuildException(msg); 442 } 443 444 if (sourcePath != null) { 445 sourceDirs.addExisting(sourcePath); 446 } 447 448 parsePackages(packagesToDoc, sourceDirs); 449 450 <b>if (packagesToDoc.size() != 0 && sourceDirs.size() == 0) { 451 String msg = 452 "sourcePath attribute must be set when " 453 + "specifying package names."; 454 throw new BuildException(msg); 455 } 456 457 Vector sourceFilesToDoc = (Vector) sourceFiles.clone(); 458 addFileSets(sourceFilesToDoc); 459 460 log("* packageList = " + packageList, Project.MSG_INFO); 461 log("* packagesToDoc = " + packagesToDoc, Project.MSG_INFO); 462 log("* sourceFilesToDoc = " + sourceFilesToDoc, Project.MSG_INFO); 463 <b>if (packageList == null 464 && packagesToDoc.size() == 0 465 && sourceFilesToDoc.size() == 0) { 466 throw new BuildException( 467 "No source files and no packages have " + "been specified."); 468 } 469 470 471 Commandline toExecute = (Commandline) cmd.clone(); 472 toExecute.setExecutable(JavaEnvUtils.getJdkExecutable("javadoc")); 473 474 //need access to private, protected and package delcarations. 475 toExecute.createArgument().setValue("-private"); 476 477 if (classpath == null) { 478 classpath = Path.systemClasspath; 479 } else { 480 //Why doesn't this work with "ignore" as in the original ant task from which 481 //this was copied? 482 //classpath = classpath.concatSystemClasspath("ignore"); 483 classpath = classpath.concatSystemClasspath(); 484 } 485 log("*Classpath = " + classpath, Project.MSG_INFO); 486 log("* *", Project.MSG_INFO); 487 log("*************************************", Project.MSG_INFO); 488 //When running from Ant, if attrib4j.jar and bcel.jar are in ANT_HOME/lib 489 //then these jars will be present on the Path.systemClasspath. 490 //Set the doclet classpath equal to the same thing. 491 docletPath = classpath; 492 493 if (!javadoc1) { 494 if (classpath.size() > 0) { 495 toExecute.createArgument().setValue("-classpath"); 496 toExecute.createArgument().setPath(classpath); 497 } 498 if (sourceDirs.size() > 0) { 499 toExecute.createArgument().setValue("-sourcepath"); 500 toExecute.createArgument().setPath(sourceDirs); 501 } 502 } else { 503 sourceDirs.append(classpath); 504 if (sourceDirs.size() > 0) { 505 toExecute.createArgument().setValue("-classpath"); 506 toExecute.createArgument().setPath(sourceDirs); 507 } 508 } 509 510 if (javadoc1) { 511 if (destDir == null) { 512 String msg = "destDir attribute must be set!"; 513 throw new BuildException(msg); 514 } 515 } 516 517 if (!javadoc1) { 518 toExecute.createArgument().setValue("-doclet"); 519 toExecute.createArgument().setValue("attrib4j.AttributeDoclet"); 520 521 if (docletPath == null) { 522 String msg = "docletpath must be set"; 523 throw new BuildException(msg); 524 } 525 toExecute.createArgument().setValue("-docletpath"); 526 toExecute.createArgument().setPath(docletPath); 527 528 toExecute.createArgument().setValue("-userclasspath"); 529 toExecute.createArgument().setPath(classpath); 530 531 toExecute.createArgument().setValue("-attributepackages"); 532 toExecute.createArgument().setValue(attributePackages); 533 534 toExecute.createArgument().setValue("-d"); 535 toExecute.createArgument().setFile(destDir); 536 537 toExecute.createArgument().setValue("-loglevel"); 538 toExecute.createArgument().setValue(loglevel); 539 540 } 541 542 File tmpList = null; 543 PrintWriter srcListWriter = null; 544 try { 545 546 /*** 547 * Write sourcefiles and package names to a temporary file 548 * if requested. 549 */ 550 if (useExternalFile) { 551 if (tmpList == null) { 552 tmpList = fileUtils.createTempFile("javadoc", "", null); 553 toExecute.createArgument().setValue( 554 "@" + tmpList.getAbsolutePath()); 555 } 556 srcListWriter = 557 new PrintWriter( 558 new FileWriter(tmpList.getAbsolutePath(), true)); 559 } 560 561 Enumeration enum = packagesToDoc.elements(); 562 while (enum.hasMoreElements()) { 563 String packageName = (String) enum.nextElement(); 564 if (useExternalFile) { 565 srcListWriter.println(packageName); 566 } else { 567 toExecute.createArgument().setValue(packageName); 568 } 569 } 570 571 enum = sourceFilesToDoc.elements(); 572 while (enum.hasMoreElements()) { 573 SourceFile sf = (SourceFile) enum.nextElement(); 574 String sourceFileName = sf.getFile().getAbsolutePath(); 575 if (useExternalFile) { 576 srcListWriter.println(sourceFileName); 577 } else { 578 toExecute.createArgument().setValue(sourceFileName); 579 } 580 } 581 582 } catch (IOException e) { 583 tmpList.delete(); 584 throw new BuildException( 585 "Error creating temporary file", 586 e, 587 location); 588 } finally { 589 if (srcListWriter != null) { 590 srcListWriter.close(); 591 } 592 } 593 594 <b>if (packageList != null) { 595 toExecute.createArgument().setValue("@" + packageList); 596 } 597 log(toExecute.describeCommand(), Project.MSG_VERBOSE); 598 //log(toExecute.describeCommand(), Project.MSG_INFO); 599 600 log("Javadoc execution", Project.MSG_INFO); 601 602 JavadocOutputStream out = new JavadocOutputStream(Project.MSG_INFO); 603 JavadocOutputStream err = new JavadocOutputStream(Project.MSG_WARN); 604 Execute exe = new Execute(new PumpStreamHandler(out, err)); 605 exe.setAntRun(project); 606 607 /* 608 * No reason to change the working directory as all filenames and 609 * path components have been resolved already. 610 * 611 * Avoid problems with command line length in some environments. 612 */ 613 exe.setWorkingDirectory(null); 614 try { 615 exe.setCommandline(toExecute.getCommandline()); 616 int ret = exe.execute(); 617 if (ret != 0 && failOnError) { 618 throw new BuildException("Javadoc returned " + ret, location); 619 } 620 } catch (IOException e) { 621 throw new BuildException("Javadoc failed: " + e, e, location); 622 } finally { 623 if (tmpList != null) { 624 tmpList.delete(); 625 tmpList = null; 626 } 627 628 out.logFlush(); 629 err.logFlush(); 630 try { 631 out.close(); 632 err.close(); 633 } catch (IOException e) { 634 } 635 } 636 637 } 638 639 private class JavadocOutputStream extends LogOutputStream { 640 JavadocOutputStream(int level) { 641 super(Attrib4jTask.this, level); 642 } 643 644 // 645 // Override the logging of output in order to filter out Generating 646 // messages. Generating messages are set to a priority of VERBOSE 647 // unless they appear after what could be an informational message. 648 // 649 private String queuedLine = null; 650 protected void processLine(String line, int messageLevel) { 651 if (messageLevel == Project.MSG_INFO 652 && line.startsWith("Generating ")) { 653 if (queuedLine != null) { 654 super.processLine(queuedLine, Project.MSG_VERBOSE); 655 } 656 queuedLine = line; 657 } else { 658 if (queuedLine != null) { 659 if (line.startsWith("Building ")) { 660 super.processLine(queuedLine, Project.MSG_VERBOSE); 661 } else { 662 super.processLine(queuedLine, Project.MSG_INFO); 663 } 664 queuedLine = null; 665 } 666 super.processLine(line, messageLevel); 667 } 668 } 669 670 protected void logFlush() { 671 if (queuedLine != null) { 672 super.processLine(queuedLine, Project.MSG_VERBOSE); 673 queuedLine = null; 674 } 675 } 676 } 677 678 /*** 679 * Add the directories matched by the nested dirsets to the Vector 680 * and the base directories of the dirsets to the Path. It also 681 * handles the packages and excludepackages attributes and 682 * elements. 683 * 684 * @since 1.5 685 */ 686 private void parsePackages(Vector pn, Path sp) { 687 Vector addedPackages = new Vector(); 688 Vector dirSets = (Vector) packageSets.clone(); 689 690 // for each sourcePath entry, add a directoryset with includes 691 // taken from packagenames attribute and nested package 692 // elements and excludes taken from excludepackages attribute 693 // and nested excludepackage elements 694 if (sourcePath != null && packageNames.size() > 0) { 695 PatternSet ps = new PatternSet(); 696 Enumeration enum = packageNames.elements(); 697 while (enum.hasMoreElements()) { 698 PackageName p = (PackageName) enum.nextElement(); 699 String pkg = p.getName().replace('.', '/'); 700 if (pkg.endsWith("*")) { 701 pkg += "*"; 702 } 703 ps.createInclude().setName(pkg); 704 } 705 706 enum = excludePackageNames.elements(); 707 while (enum.hasMoreElements()) { 708 PackageName p = (PackageName) enum.nextElement(); 709 String pkg = p.getName().replace('.', '/'); 710 if (pkg.endsWith("*")) { 711 pkg += "*"; 712 } 713 ps.createExclude().setName(pkg); 714 } 715 716 String[] pathElements = sourcePath.list(); 717 for (int i = 0; i < pathElements.length; i++) { 718 DirSet ds = new DirSet(); 719 ds.setDefaultexcludes(useDefaultExcludes); 720 ds.setDir(new File(pathElements[i])); 721 ds.createPatternSet().addConfiguredPatternset(ps); 722 dirSets.addElement(ds); 723 } 724 } 725 726 Enumeration enum = dirSets.elements(); 727 while (enum.hasMoreElements()) { 728 DirSet ds = (DirSet) enum.nextElement(); 729 File baseDir = ds.getDir(getProject()); 730 log("scanning " + baseDir + " for packages.", Project.MSG_DEBUG); 731 DirectoryScanner dsc = ds.getDirectoryScanner(getProject()); 732 String[] dirs = dsc.getIncludedDirectories(); 733 boolean containsPackages = false; 734 for (int i = 0; i < dirs.length; i++) { 735 // are there any java files in this directory? 736 File pd = new File(baseDir, dirs[i]); 737 String[] files = pd.list(new FilenameFilter() { 738 public boolean accept(File dir1, String name) { 739 if (name.endsWith(".java")) { 740 return true; 741 } 742 return false; // ignore dirs 743 } 744 }); 745 746 if (files.length > 0) { 747 containsPackages = true; 748 String packageName = 749 dirs[i].replace(File.separatorChar, '.'); 750 if (!addedPackages.contains(packageName)) { 751 addedPackages.addElement(packageName); 752 pn.addElement(packageName); 753 } 754 } 755 } 756 if (containsPackages) { 757 // We don't need to care for duplicates here, 758 // Path.list does it for us. 759 sp.createPathElement().setLocation(baseDir); 760 } else { 761 log( 762 baseDir + " doesn\'t contain any packages, dropping it.", 763 Project.MSG_VERBOSE); 764 } 765 } 766 } 767 768 769 770 /*** 771 * Add the files matched by the nested filesets to the Vector as 772 * SourceFile instances. 773 * 774 * @since 1.5 775 */ 776 private void addFileSets(Vector sf) { 777 Enumeration enum = fileSets.elements(); 778 while (enum.hasMoreElements()) { 779 FileSet fs = (FileSet) enum.nextElement(); 780 if (!fs.hasPatterns() && !fs.hasSelectors()) { 781 fs = (FileSet) fs.clone(); 782 fs.createInclude().setName("**/*.java"); 783 } 784 File baseDir = fs.getDir(getProject()); 785 DirectoryScanner ds = fs.getDirectoryScanner(getProject()); 786 String[] files = ds.getIncludedFiles(); 787 for (int i = 0; i < files.length; i++) { 788 sf.addElement(new SourceFile(new File(baseDir, files[i]))); 789 } 790 } 791 } 792 793 }

This page was automatically generated by Maven