0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: *
0017: */
0018: package org.apache.tools.ant.taskdefs;
0019:
0020: import java.io.File;
0021: import java.io.FileWriter;
0022: import java.io.FilenameFilter;
0023: import java.io.IOException;
0024: import java.io.PrintWriter;
0025: import java.io.BufferedReader;
0026: import java.io.FileReader;
0027: import java.net.MalformedURLException;
0028: import java.net.URL;
0029: import java.util.ArrayList;
0030: import java.util.Enumeration;
0031: import java.util.Iterator;
0032: import java.util.Locale;
0033: import java.util.StringTokenizer;
0034: import java.util.Vector;
0035: import org.apache.tools.ant.BuildException;
0036: import org.apache.tools.ant.DirectoryScanner;
0037: import org.apache.tools.ant.MagicNames;
0038: import org.apache.tools.ant.Project;
0039: import org.apache.tools.ant.ProjectComponent;
0040: import org.apache.tools.ant.Task;
0041: import org.apache.tools.ant.types.Commandline;
0042: import org.apache.tools.ant.types.DirSet;
0043: import org.apache.tools.ant.types.EnumeratedAttribute;
0044: import org.apache.tools.ant.types.FileSet;
0045: import org.apache.tools.ant.types.Path;
0046: import org.apache.tools.ant.types.PatternSet;
0047: import org.apache.tools.ant.types.Reference;
0048: import org.apache.tools.ant.types.ResourceCollection;
0049: import org.apache.tools.ant.types.resources.FileResource;
0050: import org.apache.tools.ant.util.FileUtils;
0051: import org.apache.tools.ant.util.JavaEnvUtils;
0052:
0053: /**
0054: * Generates Javadoc documentation for a collection
0055: * of source code.
0056: *
0057: * <p>Current known limitations are:
0058: *
0059: * <p><ul>
0060: * <li>patterns must be of the form "xxx.*", every other pattern doesn't
0061: * work.
0062: * <li>there is no control on arguments sanity since they are left
0063: * to the Javadoc implementation.
0064: * </ul>
0065: *
0066: * <p>If no <code>doclet</code> is set, then the <code>version</code> and
0067: * <code>author</code> are by default <code>"yes"</code>.
0068: *
0069: * <p>Note: This task is run on another VM because the Javadoc code calls
0070: * <code>System.exit()</code> which would break Ant functionality.
0071: *
0072: * @since Ant 1.1
0073: *
0074: * @ant.task category="java"
0075: */
0076: public class Javadoc extends Task {
0077: /**
0078: * Inner class used to manage doclet parameters.
0079: */
0080: public class DocletParam {
0081: /** The parameter name */
0082: private String name;
0083:
0084: /** The parameter value */
0085: private String value;
0086:
0087: /**
0088: * Set the name of the parameter.
0089: *
0090: * @param name the name of the doclet parameter
0091: */
0092: public void setName(String name) {
0093: this .name = name;
0094: }
0095:
0096: /**
0097: * Get the parameter name.
0098: *
0099: * @return the parameter's name.
0100: */
0101: public String getName() {
0102: return name;
0103: }
0104:
0105: /**
0106: * Set the parameter value.
0107: *
0108: * Note that only string values are supported. No resolution of file
0109: * paths is performed.
0110: *
0111: * @param value the parameter value.
0112: */
0113: public void setValue(String value) {
0114: this .value = value;
0115: }
0116:
0117: /**
0118: * Get the parameter value.
0119: *
0120: * @return the parameter value.
0121: */
0122: public String getValue() {
0123: return value;
0124: }
0125: }
0126:
0127: /**
0128: * A project aware class used for Javadoc extensions which take a name
0129: * and a path such as doclet and taglet arguments.
0130: *
0131: */
0132: public static class ExtensionInfo extends ProjectComponent {
0133: /** The name of the extension */
0134: private String name;
0135:
0136: /** The optional path to use to load the extension */
0137: private Path path;
0138:
0139: /**
0140: * Set the name of the extension
0141: *
0142: * @param name the extension's name.
0143: */
0144: public void setName(String name) {
0145: this .name = name;
0146: }
0147:
0148: /**
0149: * Get the name of the extension.
0150: *
0151: * @return the extension's name.
0152: */
0153: public String getName() {
0154: return name;
0155: }
0156:
0157: /**
0158: * Set the path to use when loading the component.
0159: *
0160: * @param path a Path instance containing the classpath to use.
0161: */
0162: public void setPath(Path path) {
0163: if (this .path == null) {
0164: this .path = path;
0165: } else {
0166: this .path.append(path);
0167: }
0168: }
0169:
0170: /**
0171: * Get the extension's path.
0172: *
0173: * @return the path to be used to load the extension.
0174: * May be <code>null</code>
0175: */
0176: public Path getPath() {
0177: return path;
0178: }
0179:
0180: /**
0181: * Create an empty nested path to be configured by Ant with the
0182: * classpath for the extension.
0183: *
0184: * @return a new Path instance to be configured.
0185: */
0186: public Path createPath() {
0187: if (path == null) {
0188: path = new Path(getProject());
0189: }
0190: return path.createPath();
0191: }
0192:
0193: /**
0194: * Adds a reference to a CLASSPATH defined elsewhere.
0195: *
0196: * @param r the reference containing the path.
0197: */
0198: public void setPathRef(Reference r) {
0199: createPath().setRefid(r);
0200: }
0201: }
0202:
0203: /**
0204: * This class stores info about doclets.
0205: *
0206: */
0207: public class DocletInfo extends ExtensionInfo {
0208:
0209: /** Collection of doclet parameters. */
0210: private Vector params = new Vector();
0211:
0212: /**
0213: * Create a doclet parameter to be configured by Ant.
0214: *
0215: * @return a new DocletParam instance to be configured.
0216: */
0217: public DocletParam createParam() {
0218: DocletParam param = new DocletParam();
0219: params.addElement(param);
0220:
0221: return param;
0222: }
0223:
0224: /**
0225: * Get the doclet's parameters.
0226: *
0227: * @return an Enumeration of DocletParam instances.
0228: */
0229: public Enumeration getParams() {
0230: return params.elements();
0231: }
0232: }
0233:
0234: /**
0235: * Used to track info about the packages to be javadoc'd
0236: */
0237: public static class PackageName {
0238: /** The package name */
0239: private String name;
0240:
0241: /**
0242: * Set the name of the package
0243: *
0244: * @param name the package name.
0245: */
0246: public void setName(String name) {
0247: this .name = name.trim();
0248: }
0249:
0250: /**
0251: * Get the package name.
0252: *
0253: * @return the package's name.
0254: */
0255: public String getName() {
0256: return name;
0257: }
0258:
0259: /**
0260: * Return a string rep for this object.
0261: * @return the package name.
0262: */
0263: public String toString() {
0264: return getName();
0265: }
0266: }
0267:
0268: /**
0269: * This class is used to manage the source files to be processed.
0270: */
0271: public static class SourceFile {
0272: /** The source file */
0273: private File file;
0274:
0275: /**
0276: * Default constructor
0277: */
0278: public SourceFile() {
0279: //empty
0280: }
0281:
0282: /**
0283: * Constructor specifying the source file directly
0284: *
0285: * @param file the source file
0286: */
0287: public SourceFile(File file) {
0288: this .file = file;
0289: }
0290:
0291: /**
0292: * Set the source file.
0293: *
0294: * @param file the source file.
0295: */
0296: public void setFile(File file) {
0297: this .file = file;
0298: }
0299:
0300: /**
0301: * Get the source file.
0302: *
0303: * @return the source file.
0304: */
0305: public File getFile() {
0306: return file;
0307: }
0308: }
0309:
0310: /**
0311: * An HTML element in the Javadoc.
0312: *
0313: * This class is used for those Javadoc elements which contain HTML such as
0314: * footers, headers, etc.
0315: */
0316: public static class Html {
0317: /** The text for the element */
0318: private StringBuffer text = new StringBuffer();
0319:
0320: /**
0321: * Add text to the element.
0322: *
0323: * @param t the text to be added.
0324: */
0325: public void addText(String t) {
0326: text.append(t);
0327: }
0328:
0329: /**
0330: * Get the current text for the element.
0331: *
0332: * @return the current text.
0333: */
0334: public String getText() {
0335: return text.substring(0);
0336: }
0337: }
0338:
0339: /**
0340: * EnumeratedAttribute implementation supporting the Javadoc scoping
0341: * values.
0342: */
0343: public static class AccessType extends EnumeratedAttribute {
0344: /**
0345: * @return the allowed values for the access type.
0346: */
0347: public String[] getValues() {
0348: // Protected first so if any GUI tool offers a default
0349: // based on enum #0, it will be right.
0350: return new String[] { "protected", "public", "package",
0351: "private" };
0352: }
0353: }
0354:
0355: /**
0356: * Holds a collection of ResourceCollections.
0357: *
0358: * <p>A separate kind of container is needed since this task
0359: * contains special handling for FileSets that has to occur at
0360: * task runtime.</p>
0361: */
0362: public class ResourceCollectionContainer {
0363: private ArrayList rcs = new ArrayList();
0364:
0365: /**
0366: * Add a resource collection to the container.
0367: * @param rc the collection to add.
0368: */
0369: public void add(ResourceCollection rc) {
0370: rcs.add(rc);
0371: }
0372:
0373: /**
0374: * Get an iterator on the collection.
0375: * @return an iterator.
0376: */
0377: private Iterator iterator() {
0378: return rcs.iterator();
0379: }
0380: }
0381:
0382: private static final FileUtils FILE_UTILS = FileUtils
0383: .getFileUtils();
0384:
0385: /** The command line built to execute Javadoc. */
0386: private Commandline cmd = new Commandline();
0387:
0388: /**
0389: * Utility method to add an argument to the command line conditionally
0390: * based on the given flag.
0391: *
0392: * @param b the flag which controls if the argument is added.
0393: * @param arg the argument value.
0394: */
0395: private void addArgIf(boolean b, String arg) {
0396: if (b) {
0397: cmd.createArgument().setValue(arg);
0398: }
0399: }
0400:
0401: /**
0402: * Utility method to add a Javadoc argument.
0403: *
0404: * @param key the argument name.
0405: * @param value the argument value.
0406: */
0407: private void addArgIfNotEmpty(String key, String value) {
0408: if (value != null && value.length() != 0) {
0409: cmd.createArgument().setValue(key);
0410: cmd.createArgument().setValue(value);
0411: } else {
0412: log("Warning: Leaving out empty argument '" + key + "'",
0413: Project.MSG_WARN);
0414: }
0415: }
0416:
0417: /**
0418: * Flag which indicates if the task should fail if there is a
0419: * Javadoc error.
0420: */
0421: private boolean failOnError = false;
0422: private Path sourcePath = null;
0423: private File destDir = null;
0424: private Vector sourceFiles = new Vector();
0425: private Vector packageNames = new Vector();
0426: private Vector excludePackageNames = new Vector(1);
0427: private boolean author = true;
0428: private boolean version = true;
0429: private DocletInfo doclet = null;
0430: private Path classpath = null;
0431: private Path bootclasspath = null;
0432: private String group = null;
0433: private String packageList = null;
0434: private Vector links = new Vector();
0435: private Vector groups = new Vector();
0436: private Vector tags = new Vector();
0437: private boolean useDefaultExcludes = true;
0438: private Html doctitle = null;
0439: private Html header = null;
0440: private Html footer = null;
0441: private Html bottom = null;
0442: private boolean useExternalFile = false;
0443: private String source = null;
0444: private boolean linksource = false;
0445: private boolean breakiterator = false;
0446: private String noqualifier;
0447: private boolean includeNoSourcePackages = false;
0448: private boolean old = false;
0449: private String executable = null;
0450:
0451: private ResourceCollectionContainer nestedSourceFiles = new ResourceCollectionContainer();
0452: private Vector packageSets = new Vector();
0453:
0454: /**
0455: * Work around command line length limit by using an external file
0456: * for the sourcefiles.
0457: *
0458: * @param b true if an external file is to be used.
0459: */
0460: public void setUseExternalFile(boolean b) {
0461: useExternalFile = b;
0462: }
0463:
0464: /**
0465: * Sets whether default exclusions should be used or not.
0466: *
0467: * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
0468: * should be used, "false"|"off"|"no" when they
0469: * shouldn't be used.
0470: */
0471: public void setDefaultexcludes(boolean useDefaultExcludes) {
0472: this .useDefaultExcludes = useDefaultExcludes;
0473: }
0474:
0475: /**
0476: * Set the maximum memory to be used by the javadoc process
0477: *
0478: * @param max a string indicating the maximum memory according to the
0479: * JVM conventions (e.g. 128m is 128 Megabytes)
0480: */
0481: public void setMaxmemory(String max) {
0482: cmd.createArgument().setValue("-J-Xmx" + max);
0483: }
0484:
0485: /**
0486: * Set an additional parameter on the command line
0487: *
0488: * @param add the additional command line parameter for the javadoc task.
0489: */
0490: public void setAdditionalparam(String add) {
0491: cmd.createArgument().setLine(add);
0492: }
0493:
0494: /**
0495: * Adds a command-line argument.
0496: * @return a command-line argument to configure
0497: * @since Ant 1.6
0498: */
0499: public Commandline.Argument createArg() {
0500: return cmd.createArgument();
0501: }
0502:
0503: /**
0504: * Specify where to find source file
0505: *
0506: * @param src a Path instance containing the various source directories.
0507: */
0508: public void setSourcepath(Path src) {
0509: if (sourcePath == null) {
0510: sourcePath = src;
0511: } else {
0512: sourcePath.append(src);
0513: }
0514: }
0515:
0516: /**
0517: * Create a path to be configured with the locations of the source
0518: * files.
0519: *
0520: * @return a new Path instance to be configured by the Ant core.
0521: */
0522: public Path createSourcepath() {
0523: if (sourcePath == null) {
0524: sourcePath = new Path(getProject());
0525: }
0526: return sourcePath.createPath();
0527: }
0528:
0529: /**
0530: * Adds a reference to a CLASSPATH defined elsewhere.
0531: *
0532: * @param r the reference containing the source path definition.
0533: */
0534: public void setSourcepathRef(Reference r) {
0535: createSourcepath().setRefid(r);
0536: }
0537:
0538: /**
0539: * Set the directory where the Javadoc output will be generated.
0540: *
0541: * @param dir the destination directory.
0542: */
0543: public void setDestdir(File dir) {
0544: destDir = dir;
0545: cmd.createArgument().setValue("-d");
0546: cmd.createArgument().setFile(destDir);
0547: }
0548:
0549: /**
0550: * Set the list of source files to process.
0551: *
0552: * @param src a comma separated list of source files.
0553: */
0554: public void setSourcefiles(String src) {
0555: StringTokenizer tok = new StringTokenizer(src, ",");
0556: while (tok.hasMoreTokens()) {
0557: String f = tok.nextToken();
0558: SourceFile sf = new SourceFile();
0559: sf.setFile(getProject().resolveFile(f.trim()));
0560: addSource(sf);
0561: }
0562: }
0563:
0564: /**
0565: * Add a single source file.
0566: *
0567: * @param sf the source file to be processed.
0568: */
0569: public void addSource(SourceFile sf) {
0570: sourceFiles.addElement(sf);
0571: }
0572:
0573: /**
0574: * Set the package names to be processed.
0575: *
0576: * @param packages a comma separated list of packages specs
0577: * (may be wildcarded).
0578: *
0579: * @see #addPackage for wildcard information.
0580: */
0581: public void setPackagenames(String packages) {
0582: StringTokenizer tok = new StringTokenizer(packages, ",");
0583: while (tok.hasMoreTokens()) {
0584: String p = tok.nextToken();
0585: PackageName pn = new PackageName();
0586: pn.setName(p);
0587: addPackage(pn);
0588: }
0589: }
0590:
0591: /**
0592: * Add a single package to be processed.
0593: *
0594: * If the package name ends with ".*" the Javadoc task
0595: * will find and process all subpackages.
0596: *
0597: * @param pn the package name, possibly wildcarded.
0598: */
0599: public void addPackage(PackageName pn) {
0600: packageNames.addElement(pn);
0601: }
0602:
0603: /**
0604: * Set the list of packages to be excluded.
0605: *
0606: * @param packages a comma separated list of packages to be excluded.
0607: * This may not include wildcards.
0608: */
0609: public void setExcludePackageNames(String packages) {
0610: StringTokenizer tok = new StringTokenizer(packages, ",");
0611: while (tok.hasMoreTokens()) {
0612: String p = tok.nextToken();
0613: PackageName pn = new PackageName();
0614: pn.setName(p);
0615: addExcludePackage(pn);
0616: }
0617: }
0618:
0619: /**
0620: * Add a package to be excluded from the Javadoc run.
0621: *
0622: * @param pn the name of the package (wildcards are not permitted).
0623: */
0624: public void addExcludePackage(PackageName pn) {
0625: excludePackageNames.addElement(pn);
0626: }
0627:
0628: /**
0629: * Specify the file containing the overview to be included in the generated
0630: * documentation.
0631: *
0632: * @param f the file containing the overview.
0633: */
0634: public void setOverview(File f) {
0635: cmd.createArgument().setValue("-overview");
0636: cmd.createArgument().setFile(f);
0637: }
0638:
0639: /**
0640: * Indicate whether only public classes and members are to be included in
0641: * the scope processed
0642: *
0643: * @param b true if scope is to be public.
0644: */
0645: public void setPublic(boolean b) {
0646: addArgIf(b, "-public");
0647: }
0648:
0649: /**
0650: * Indicate whether only protected and public classes and members are to
0651: * be included in the scope processed
0652: *
0653: * @param b true if scope is to be protected.
0654: */
0655: public void setProtected(boolean b) {
0656: addArgIf(b, "-protected");
0657: }
0658:
0659: /**
0660: * Indicate whether only package, protected and public classes and
0661: * members are to be included in the scope processed
0662: *
0663: * @param b true if scope is to be package level.
0664: */
0665: public void setPackage(boolean b) {
0666: addArgIf(b, "-package");
0667: }
0668:
0669: /**
0670: * Indicate whether all classes and
0671: * members are to be included in the scope processed
0672: *
0673: * @param b true if scope is to be private level.
0674: */
0675: public void setPrivate(boolean b) {
0676: addArgIf(b, "-private");
0677: }
0678:
0679: /**
0680: * Set the scope to be processed. This is an alternative to the
0681: * use of the setPublic, setPrivate, etc methods. It gives better build
0682: * file control over what scope is processed.
0683: *
0684: * @param at the scope to be processed.
0685: */
0686: public void setAccess(AccessType at) {
0687: cmd.createArgument().setValue("-" + at.getValue());
0688: }
0689:
0690: /**
0691: * Set the class that starts the doclet used in generating the
0692: * documentation.
0693: *
0694: * @param docletName the name of the doclet class.
0695: */
0696: public void setDoclet(String docletName) {
0697: if (doclet == null) {
0698: doclet = new DocletInfo();
0699: doclet.setProject(getProject());
0700: }
0701: doclet.setName(docletName);
0702: }
0703:
0704: /**
0705: * Set the classpath used to find the doclet class.
0706: *
0707: * @param docletPath the doclet classpath.
0708: */
0709: public void setDocletPath(Path docletPath) {
0710: if (doclet == null) {
0711: doclet = new DocletInfo();
0712: doclet.setProject(getProject());
0713: }
0714: doclet.setPath(docletPath);
0715: }
0716:
0717: /**
0718: * Set the classpath used to find the doclet class by reference.
0719: *
0720: * @param r the reference to the Path instance to use as the doclet
0721: * classpath.
0722: */
0723: public void setDocletPathRef(Reference r) {
0724: if (doclet == null) {
0725: doclet = new DocletInfo();
0726: doclet.setProject(getProject());
0727: }
0728: doclet.createPath().setRefid(r);
0729: }
0730:
0731: /**
0732: * Create a doclet to be used in the documentation generation.
0733: *
0734: * @return a new DocletInfo instance to be configured.
0735: */
0736: public DocletInfo createDoclet() {
0737: if (doclet == null) {
0738: doclet = new DocletInfo();
0739: }
0740: return doclet;
0741: }
0742:
0743: /**
0744: * Add a taglet
0745: *
0746: * @param tagletInfo information about the taglet.
0747: */
0748: public void addTaglet(ExtensionInfo tagletInfo) {
0749: tags.addElement(tagletInfo);
0750: }
0751:
0752: /**
0753: * Indicate whether Javadoc should produce old style (JDK 1.1)
0754: * documentation.
0755: *
0756: * This is not supported by JDK 1.1 and has been phased out in JDK 1.4
0757: *
0758: * @param b if true attempt to generate old style documentation.
0759: */
0760: public void setOld(boolean b) {
0761: old = b;
0762: }
0763:
0764: /**
0765: * Set the classpath to be used for this Javadoc run.
0766: *
0767: * @param path an Ant Path object containing the compilation
0768: * classpath.
0769: */
0770: public void setClasspath(Path path) {
0771: if (classpath == null) {
0772: classpath = path;
0773: } else {
0774: classpath.append(path);
0775: }
0776: }
0777:
0778: /**
0779: * Create a Path to be configured with the classpath to use
0780: *
0781: * @return a new Path instance to be configured with the classpath.
0782: */
0783: public Path createClasspath() {
0784: if (classpath == null) {
0785: classpath = new Path(getProject());
0786: }
0787: return classpath.createPath();
0788: }
0789:
0790: /**
0791: * Adds a reference to a CLASSPATH defined elsewhere.
0792: *
0793: * @param r the reference to an instance defining the classpath.
0794: */
0795: public void setClasspathRef(Reference r) {
0796: createClasspath().setRefid(r);
0797: }
0798:
0799: /**
0800: * Set the boot classpath to use.
0801: *
0802: * @param path the boot classpath.
0803: */
0804: public void setBootclasspath(Path path) {
0805: if (bootclasspath == null) {
0806: bootclasspath = path;
0807: } else {
0808: bootclasspath.append(path);
0809: }
0810: }
0811:
0812: /**
0813: * Create a Path to be configured with the boot classpath
0814: *
0815: * @return a new Path instance to be configured with the boot classpath.
0816: */
0817: public Path createBootclasspath() {
0818: if (bootclasspath == null) {
0819: bootclasspath = new Path(getProject());
0820: }
0821: return bootclasspath.createPath();
0822: }
0823:
0824: /**
0825: * Adds a reference to a CLASSPATH defined elsewhere.
0826: *
0827: * @param r the reference to an instance defining the bootclasspath.
0828: */
0829: public void setBootClasspathRef(Reference r) {
0830: createBootclasspath().setRefid(r);
0831: }
0832:
0833: /**
0834: * Set the location of the extensions directories.
0835: *
0836: * @param path the string version of the path.
0837: * @deprecated since 1.5.x.
0838: * Use the {@link #setExtdirs(Path)} version.
0839: */
0840: public void setExtdirs(String path) {
0841: cmd.createArgument().setValue("-extdirs");
0842: cmd.createArgument().setValue(path);
0843: }
0844:
0845: /**
0846: * Set the location of the extensions directories.
0847: *
0848: * @param path a path containing the extension directories.
0849: */
0850: public void setExtdirs(Path path) {
0851: cmd.createArgument().setValue("-extdirs");
0852: cmd.createArgument().setPath(path);
0853: }
0854:
0855: /**
0856: * Run javadoc in verbose mode
0857: *
0858: * @param b true if operation is to be verbose.
0859: */
0860: public void setVerbose(boolean b) {
0861: addArgIf(b, "-verbose");
0862: }
0863:
0864: /**
0865: * Set the local to use in documentation generation.
0866: *
0867: * @param locale the locale to use.
0868: */
0869: public void setLocale(String locale) {
0870: // createArgument(true) is necessary to make sure -locale
0871: // is the first argument (required in 1.3+).
0872: cmd.createArgument(true).setValue(locale);
0873: cmd.createArgument(true).setValue("-locale");
0874: }
0875:
0876: /**
0877: * Set the encoding name of the source files,
0878: *
0879: * @param enc the name of the encoding for the source files.
0880: */
0881: public void setEncoding(String enc) {
0882: cmd.createArgument().setValue("-encoding");
0883: cmd.createArgument().setValue(enc);
0884: }
0885:
0886: /**
0887: * Include the version tag in the generated documentation.
0888: *
0889: * @param b true if the version tag should be included.
0890: */
0891: public void setVersion(boolean b) {
0892: this .version = b;
0893: }
0894:
0895: /**
0896: * Generate the "use" page for each package.
0897: *
0898: * @param b true if the use page should be generated.
0899: */
0900: public void setUse(boolean b) {
0901: addArgIf(b, "-use");
0902: }
0903:
0904: /**
0905: * Include the author tag in the generated documentation.
0906: *
0907: * @param b true if the author tag should be included.
0908: */
0909: public void setAuthor(boolean b) {
0910: author = b;
0911: }
0912:
0913: /**
0914: * Generate a split index
0915: *
0916: * @param b true if the index should be split into a file per letter.
0917: */
0918: public void setSplitindex(boolean b) {
0919: addArgIf(b, "-splitindex");
0920: }
0921:
0922: /**
0923: * Set the title to be placed in the HTML <title> tag of the
0924: * generated documentation.
0925: *
0926: * @param title the window title to use.
0927: */
0928: public void setWindowtitle(String title) {
0929: addArgIfNotEmpty("-windowtitle", title);
0930: }
0931:
0932: /**
0933: * Set the title of the generated overview page.
0934: *
0935: * @param doctitle the Document title.
0936: */
0937: public void setDoctitle(String doctitle) {
0938: Html h = new Html();
0939: h.addText(doctitle);
0940: addDoctitle(h);
0941: }
0942:
0943: /**
0944: * Add a document title to use for the overview page.
0945: *
0946: * @param text the HTML element containing the document title.
0947: */
0948: public void addDoctitle(Html text) {
0949: doctitle = text;
0950: }
0951:
0952: /**
0953: * Set the header text to be placed at the top of each output file.
0954: *
0955: * @param header the header text
0956: */
0957: public void setHeader(String header) {
0958: Html h = new Html();
0959: h.addText(header);
0960: addHeader(h);
0961: }
0962:
0963: /**
0964: * Set the header text to be placed at the top of each output file.
0965: *
0966: * @param text the header text
0967: */
0968: public void addHeader(Html text) {
0969: header = text;
0970: }
0971:
0972: /**
0973: * Set the footer text to be placed at the bottom of each output file.
0974: *
0975: * @param footer the footer text.
0976: */
0977: public void setFooter(String footer) {
0978: Html h = new Html();
0979: h.addText(footer);
0980: addFooter(h);
0981: }
0982:
0983: /**
0984: * Set the footer text to be placed at the bottom of each output file.
0985: *
0986: * @param text the footer text.
0987: */
0988: public void addFooter(Html text) {
0989: footer = text;
0990: }
0991:
0992: /**
0993: * Set the text to be placed at the bottom of each output file.
0994: *
0995: * @param bottom the bottom text.
0996: */
0997: public void setBottom(String bottom) {
0998: Html h = new Html();
0999: h.addText(bottom);
1000: addBottom(h);
1001: }
1002:
1003: /**
1004: * Set the text to be placed at the bottom of each output file.
1005: *
1006: * @param text the bottom text.
1007: */
1008: public void addBottom(Html text) {
1009: bottom = text;
1010: }
1011:
1012: /**
1013: * Link to docs at "url" using package list at "url2"
1014: * - separate the URLs by using a space character.
1015: *
1016: * @param src the offline link specification (url and package list)
1017: */
1018: public void setLinkoffline(String src) {
1019: LinkArgument le = createLink();
1020: le.setOffline(true);
1021: String linkOfflineError = "The linkoffline attribute must include"
1022: + " a URL and a package-list file location separated by a"
1023: + " space";
1024: if (src.trim().length() == 0) {
1025: throw new BuildException(linkOfflineError);
1026: }
1027: StringTokenizer tok = new StringTokenizer(src, " ", false);
1028: le.setHref(tok.nextToken());
1029:
1030: if (!tok.hasMoreTokens()) {
1031: throw new BuildException(linkOfflineError);
1032: }
1033: le.setPackagelistLoc(getProject().resolveFile(tok.nextToken()));
1034: }
1035:
1036: /**
1037: * Group specified packages together in overview page.
1038: *
1039: * @param src the group packages - a command separated list of group specs,
1040: * each one being a group name and package specification separated
1041: * by a space.
1042: */
1043: public void setGroup(String src) {
1044: group = src;
1045: }
1046:
1047: /**
1048: * Create links to Javadoc output at the given URL.
1049: * @param src the URL to link to
1050: */
1051: public void setLink(String src) {
1052: createLink().setHref(src);
1053: }
1054:
1055: /**
1056: * Control deprecation infromation
1057: *
1058: * @param b If true, do not include deprecated information.
1059: */
1060: public void setNodeprecated(boolean b) {
1061: addArgIf(b, "-nodeprecated");
1062: }
1063:
1064: /**
1065: * Control deprecated list generation
1066: *
1067: * @param b if true, do not generate deprecated list.
1068: */
1069: public void setNodeprecatedlist(boolean b) {
1070: addArgIf(b, "-nodeprecatedlist");
1071: }
1072:
1073: /**
1074: * Control class tree generation.
1075: *
1076: * @param b if true, do not generate class hierarchy.
1077: */
1078: public void setNotree(boolean b) {
1079: addArgIf(b, "-notree");
1080: }
1081:
1082: /**
1083: * Control generation of index.
1084: *
1085: * @param b if true, do not generate index.
1086: */
1087: public void setNoindex(boolean b) {
1088: addArgIf(b, "-noindex");
1089: }
1090:
1091: /**
1092: * Control generation of help link.
1093: *
1094: * @param b if true, do not generate help link
1095: */
1096: public void setNohelp(boolean b) {
1097: addArgIf(b, "-nohelp");
1098: }
1099:
1100: /**
1101: * Control generation of the navigation bar.
1102: *
1103: * @param b if true, do not generate navigation bar.
1104: */
1105: public void setNonavbar(boolean b) {
1106: addArgIf(b, "-nonavbar");
1107: }
1108:
1109: /**
1110: * Control warnings about serial tag.
1111: *
1112: * @param b if true, generate warning about the serial tag.
1113: */
1114: public void setSerialwarn(boolean b) {
1115: addArgIf(b, "-serialwarn");
1116: }
1117:
1118: /**
1119: * Specifies the CSS stylesheet file to use.
1120: *
1121: * @param f the file with the CSS to use.
1122: */
1123: public void setStylesheetfile(File f) {
1124: cmd.createArgument().setValue("-stylesheetfile");
1125: cmd.createArgument().setFile(f);
1126: }
1127:
1128: /**
1129: * Specifies the HTML help file to use.
1130: *
1131: * @param f the file containing help content.
1132: */
1133: public void setHelpfile(File f) {
1134: cmd.createArgument().setValue("-helpfile");
1135: cmd.createArgument().setFile(f);
1136: }
1137:
1138: /**
1139: * Output file encoding name.
1140: *
1141: * @param enc name of the encoding to use.
1142: */
1143: public void setDocencoding(String enc) {
1144: cmd.createArgument().setValue("-docencoding");
1145: cmd.createArgument().setValue(enc);
1146: }
1147:
1148: /**
1149: * The name of a file containing the packages to process.
1150: *
1151: * @param src the file containing the package list.
1152: */
1153: public void setPackageList(String src) {
1154: packageList = src;
1155: }
1156:
1157: /**
1158: * Create link to Javadoc output at the given URL.
1159: *
1160: * @return link argument to configure
1161: */
1162: public LinkArgument createLink() {
1163: LinkArgument la = new LinkArgument();
1164: links.addElement(la);
1165: return la;
1166: }
1167:
1168: /**
1169: * Represents a link triplet (href, whether link is offline,
1170: * location of the package list if off line)
1171: */
1172: public class LinkArgument {
1173: private String href;
1174: private boolean offline = false;
1175: private File packagelistLoc;
1176: private boolean resolveLink = false;
1177:
1178: /** Constructor for LinkArguement */
1179: public LinkArgument() {
1180: //empty
1181: }
1182:
1183: /**
1184: * Set the href attribute.
1185: * @param hr a <code>String</code> value
1186: */
1187: public void setHref(String hr) {
1188: href = hr;
1189: }
1190:
1191: /**
1192: * Get the href attribute.
1193: * @return the href attribute.
1194: */
1195: public String getHref() {
1196: return href;
1197: }
1198:
1199: /**
1200: * Set the packetlist location attribute.
1201: * @param src a <code>File</code> value
1202: */
1203: public void setPackagelistLoc(File src) {
1204: packagelistLoc = src;
1205: }
1206:
1207: /**
1208: * Get the packetList location attribute.
1209: * @return the packetList location attribute.
1210: */
1211: public File getPackagelistLoc() {
1212: return packagelistLoc;
1213: }
1214:
1215: /**
1216: * Set the offline attribute.
1217: * @param offline a <code>boolean</code> value
1218: */
1219: public void setOffline(boolean offline) {
1220: this .offline = offline;
1221: }
1222:
1223: /**
1224: * Get the linkOffline attribute.
1225: * @return the linkOffline attribute.
1226: */
1227: public boolean isLinkOffline() {
1228: return offline;
1229: }
1230:
1231: /**
1232: * Sets whether Ant should resolve the link attribute relative
1233: * to the current basedir.
1234: * @param resolve a <code>boolean</code> value
1235: */
1236: public void setResolveLink(boolean resolve) {
1237: this .resolveLink = resolve;
1238: }
1239:
1240: /**
1241: * should Ant resolve the link attribute relative to the
1242: * current basedir?
1243: * @return the resolveLink attribute.
1244: */
1245: public boolean shouldResolveLink() {
1246: return resolveLink;
1247: }
1248:
1249: }
1250:
1251: /**
1252: * Creates and adds a -tag argument. This is used to specify
1253: * custom tags. This argument is only available for Javadoc 1.4,
1254: * and will generate a verbose message (and then be ignored)
1255: * when run on Java versions below 1.4.
1256: * @return tag argument to be configured
1257: */
1258: public TagArgument createTag() {
1259: TagArgument ta = new TagArgument();
1260: tags.addElement(ta);
1261: return ta;
1262: }
1263:
1264: /**
1265: * Scope element verbose names. (Defined here as fields
1266: * cannot be static in inner classes.) The first letter
1267: * from each element is used to build up the scope string.
1268: */
1269: static final String[] SCOPE_ELEMENTS = { "overview", "packages",
1270: "types", "constructors", "methods", "fields" };
1271:
1272: /**
1273: * Class representing a -tag argument.
1274: */
1275: public class TagArgument extends FileSet {
1276: /** Name of the tag. */
1277: private String name = null;
1278: /** Whether or not the tag is enabled. */
1279: private boolean enabled = true;
1280: /**
1281: * Scope string of the tag. This will form the middle
1282: * argument of the -tag parameter when the tag is enabled
1283: * (with an X prepended for and is parsed from human-readable form.
1284: */
1285: private String scope = "a";
1286:
1287: /** Sole constructor. */
1288: public TagArgument() {
1289: //empty
1290: }
1291:
1292: /**
1293: * Sets the name of the tag.
1294: *
1295: * @param name The name of the tag.
1296: * Must not be <code>null</code> or empty.
1297: */
1298: public void setName(String name) {
1299: this .name = name;
1300: }
1301:
1302: /**
1303: * Sets the scope of the tag. This is in comma-separated
1304: * form, with each element being one of "all" (the default),
1305: * "overview", "packages", "types", "constructors", "methods",
1306: * "fields". The elements are treated in a case-insensitive
1307: * manner.
1308: *
1309: * @param verboseScope The scope of the tag.
1310: * Must not be <code>null</code>,
1311: * should not be empty.
1312: *
1313: * @exception BuildException if all is specified along with
1314: * other elements, if any elements are repeated, if no
1315: * elements are specified, or if any unrecognised elements are
1316: * specified.
1317: */
1318: public void setScope(String verboseScope) throws BuildException {
1319: verboseScope = verboseScope.toLowerCase(Locale.US);
1320:
1321: boolean[] elements = new boolean[SCOPE_ELEMENTS.length];
1322:
1323: boolean gotAll = false;
1324: boolean gotNotAll = false;
1325:
1326: // Go through the tokens one at a time, updating the
1327: // elements array and issuing warnings where appropriate.
1328: StringTokenizer tok = new StringTokenizer(verboseScope, ",");
1329: while (tok.hasMoreTokens()) {
1330: String next = tok.nextToken().trim();
1331: if (next.equals("all")) {
1332: if (gotAll) {
1333: getProject().log(
1334: "Repeated tag scope element: all",
1335: Project.MSG_VERBOSE);
1336: }
1337: gotAll = true;
1338: } else {
1339: int i;
1340: for (i = 0; i < SCOPE_ELEMENTS.length; i++) {
1341: if (next.equals(SCOPE_ELEMENTS[i])) {
1342: break;
1343: }
1344: }
1345: if (i == SCOPE_ELEMENTS.length) {
1346: throw new BuildException(
1347: "Unrecognised scope element: " + next);
1348: } else {
1349: if (elements[i]) {
1350: getProject()
1351: .log(
1352: "Repeated tag scope element: "
1353: + next,
1354: Project.MSG_VERBOSE);
1355: }
1356: elements[i] = true;
1357: gotNotAll = true;
1358: }
1359: }
1360: }
1361:
1362: if (gotNotAll && gotAll) {
1363: throw new BuildException(
1364: "Mixture of \"all\" and other scope "
1365: + "elements in tag parameter.");
1366: }
1367: if (!gotNotAll && !gotAll) {
1368: throw new BuildException(
1369: "No scope elements specified in tag "
1370: + "parameter.");
1371: }
1372: if (gotAll) {
1373: this .scope = "a";
1374: } else {
1375: StringBuffer buff = new StringBuffer(elements.length);
1376: for (int i = 0; i < elements.length; i++) {
1377: if (elements[i]) {
1378: buff.append(SCOPE_ELEMENTS[i].charAt(0));
1379: }
1380: }
1381: this .scope = buff.toString();
1382: }
1383: }
1384:
1385: /**
1386: * Sets whether or not the tag is enabled.
1387: *
1388: * @param enabled Whether or not this tag is enabled.
1389: */
1390: public void setEnabled(boolean enabled) {
1391: this .enabled = enabled;
1392: }
1393:
1394: /**
1395: * Returns the -tag parameter this argument represented.
1396: * @return the -tag parameter as a string
1397: * @exception BuildException if either the name or description
1398: * is <code>null</code> or empty.
1399: */
1400: public String getParameter() throws BuildException {
1401: if (name == null || name.equals("")) {
1402: throw new BuildException(
1403: "No name specified for custom tag.");
1404: }
1405: if (getDescription() != null) {
1406: return name + ":" + (enabled ? "" : "X") + scope + ":"
1407: + getDescription();
1408: } else {
1409: return name + ":" + (enabled ? "" : "X") + scope + ":"
1410: + name;
1411: }
1412: }
1413: }
1414:
1415: /**
1416: * Separates packages on the overview page into whatever
1417: * groups you specify, one group per table.
1418: * @return a group argument to be configured
1419: */
1420: public GroupArgument createGroup() {
1421: GroupArgument ga = new GroupArgument();
1422: groups.addElement(ga);
1423: return ga;
1424: }
1425:
1426: /**
1427: * A class corresponding to the group nested element.
1428: */
1429: public class GroupArgument {
1430: private Html title;
1431: private Vector packages = new Vector();
1432:
1433: /** Constructor for GroupArgument */
1434: public GroupArgument() {
1435: //empty
1436: }
1437:
1438: /**
1439: * Set the title attribute using a string.
1440: * @param src a <code>String</code> value
1441: */
1442: public void setTitle(String src) {
1443: Html h = new Html();
1444: h.addText(src);
1445: addTitle(h);
1446: }
1447:
1448: /**
1449: * Set the title attribute using a nested Html value.
1450: * @param text a <code>Html</code> value
1451: */
1452: public void addTitle(Html text) {
1453: title = text;
1454: }
1455:
1456: /**
1457: * Get the title.
1458: * @return the title
1459: */
1460: public String getTitle() {
1461: return title != null ? title.getText() : null;
1462: }
1463:
1464: /**
1465: * Set the packages to Javadoc on.
1466: * @param src a comma separated list of packages
1467: */
1468: public void setPackages(String src) {
1469: StringTokenizer tok = new StringTokenizer(src, ",");
1470: while (tok.hasMoreTokens()) {
1471: String p = tok.nextToken();
1472: PackageName pn = new PackageName();
1473: pn.setName(p);
1474: addPackage(pn);
1475: }
1476: }
1477:
1478: /**
1479: * Add a package nested element.
1480: * @param pn a nested element specifing the package.
1481: */
1482: public void addPackage(PackageName pn) {
1483: packages.addElement(pn);
1484: }
1485:
1486: /**
1487: * Get the packages as a collon separated list.
1488: * @return the packages as a string
1489: */
1490: public String getPackages() {
1491: StringBuffer p = new StringBuffer();
1492: for (int i = 0; i < packages.size(); i++) {
1493: if (i > 0) {
1494: p.append(":");
1495: }
1496: p.append(packages.elementAt(i).toString());
1497: }
1498: return p.toString();
1499: }
1500: }
1501:
1502: /**
1503: * Charset for cross-platform viewing of generated documentation.
1504: * @param src the name of the charset
1505: */
1506: public void setCharset(String src) {
1507: this .addArgIfNotEmpty("-charset", src);
1508: }
1509:
1510: /**
1511: * Should the build process fail if Javadoc fails (as indicated by
1512: * a non zero return code)?
1513: *
1514: * <p>Default is false.</p>
1515: * @param b a <code>boolean</code> value
1516: */
1517: public void setFailonerror(boolean b) {
1518: failOnError = b;
1519: }
1520:
1521: /**
1522: * Enables the -source switch, will be ignored if Javadoc is not
1523: * the 1.4 version.
1524: * @param source a <code>String</code> value
1525: * @since Ant 1.5
1526: */
1527: public void setSource(String source) {
1528: this .source = source;
1529: }
1530:
1531: /**
1532: * Sets the actual executable command to invoke, instead of the binary
1533: * <code>javadoc</code> found in Ant's JDK.
1534: * @param executable the command to invoke.
1535: * @since Ant 1.6.3
1536: */
1537: public void setExecutable(String executable) {
1538: this .executable = executable;
1539: }
1540:
1541: /**
1542: * Adds a packageset.
1543: *
1544: * <p>All included directories will be translated into package
1545: * names be converting the directory separator into dots.</p>
1546: * @param packageSet a directory set
1547: * @since 1.5
1548: */
1549: public void addPackageset(DirSet packageSet) {
1550: packageSets.addElement(packageSet);
1551: }
1552:
1553: /**
1554: * Adds a fileset.
1555: *
1556: * <p>All included files will be added as sourcefiles. The task
1557: * will automatically add
1558: * <code>includes="**/*.java"</code> to the
1559: * fileset.</p>
1560: * @param fs a file set
1561: * @since 1.5
1562: */
1563: public void addFileset(FileSet fs) {
1564: createSourceFiles().add(fs);
1565: }
1566:
1567: /**
1568: * Adds a container for resource collections.
1569: *
1570: * <p>All included files will be added as sourcefiles.</p>
1571: * @return the source files to configure.
1572: * @since 1.7
1573: */
1574: public ResourceCollectionContainer createSourceFiles() {
1575: return nestedSourceFiles;
1576: }
1577:
1578: /**
1579: * Enables the -linksource switch, will be ignored if Javadoc is not
1580: * the 1.4 version. Default is false
1581: * @param b a <code>String</code> value
1582: * @since Ant 1.6
1583: */
1584: public void setLinksource(boolean b) {
1585: this .linksource = b;
1586: }
1587:
1588: /**
1589: * Enables the -linksource switch, will be ignored if Javadoc is not
1590: * the 1.4 version. Default is false
1591: * @param b a <code>String</code> value
1592: * @since Ant 1.6
1593: */
1594: public void setBreakiterator(boolean b) {
1595: this .breakiterator = b;
1596: }
1597:
1598: /**
1599: * Enables the -noqualifier switch, will be ignored if Javadoc is not
1600: * the 1.4 version.
1601: * @param noqualifier the parameter to the -noqualifier switch
1602: * @since Ant 1.6
1603: */
1604: public void setNoqualifier(String noqualifier) {
1605: this .noqualifier = noqualifier;
1606: }
1607:
1608: /**
1609: * If set to true, Ant will also accept packages that only hold
1610: * package.html files but no Java sources.
1611: * @param b a <code>boolean</code> value.
1612: * @since Ant 1.6.3
1613: */
1614: public void setIncludeNoSourcePackages(boolean b) {
1615: this .includeNoSourcePackages = b;
1616: }
1617:
1618: /**
1619: * Execute the task.
1620: * @throws BuildException on error
1621: */
1622: public void execute() throws BuildException {
1623: if ("javadoc2".equals(getTaskType())) {
1624: log(
1625: "Warning: the task name <javadoc2> is deprecated. Use <javadoc> instead.",
1626: Project.MSG_WARN);
1627: }
1628:
1629: // Whether *this VM* is 1.4+ (but also check executable != null).
1630: boolean javadoc4 = !JavaEnvUtils
1631: .isJavaVersion(JavaEnvUtils.JAVA_1_2)
1632: && !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3);
1633: boolean javadoc5 = javadoc4
1634: && !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_4);
1635:
1636: Vector packagesToDoc = new Vector();
1637: Path sourceDirs = new Path(getProject());
1638:
1639: if (packageList != null && sourcePath == null) {
1640: String msg = "sourcePath attribute must be set when "
1641: + "specifying packagelist.";
1642: throw new BuildException(msg);
1643: }
1644:
1645: if (sourcePath != null) {
1646: sourceDirs.addExisting(sourcePath);
1647: }
1648:
1649: parsePackages(packagesToDoc, sourceDirs);
1650:
1651: if (packagesToDoc.size() != 0 && sourceDirs.size() == 0) {
1652: String msg = "sourcePath attribute must be set when "
1653: + "specifying package names.";
1654: throw new BuildException(msg);
1655: }
1656:
1657: Vector sourceFilesToDoc = (Vector) sourceFiles.clone();
1658: addSourceFiles(sourceFilesToDoc);
1659:
1660: if (packageList == null && packagesToDoc.size() == 0
1661: && sourceFilesToDoc.size() == 0) {
1662: throw new BuildException(
1663: "No source files and no packages have "
1664: + "been specified.");
1665: }
1666:
1667: log("Generating Javadoc", Project.MSG_INFO);
1668:
1669: Commandline toExecute = (Commandline) cmd.clone();
1670: if (executable != null) {
1671: toExecute.setExecutable(executable);
1672: } else {
1673: toExecute.setExecutable(JavaEnvUtils
1674: .getJdkExecutable("javadoc"));
1675: }
1676:
1677: // ------------------------------------------ general Javadoc arguments
1678: if (doctitle != null) {
1679: toExecute.createArgument().setValue("-doctitle");
1680: toExecute.createArgument().setValue(
1681: expand(doctitle.getText()));
1682: }
1683: if (header != null) {
1684: toExecute.createArgument().setValue("-header");
1685: toExecute.createArgument().setValue(
1686: expand(header.getText()));
1687: }
1688: if (footer != null) {
1689: toExecute.createArgument().setValue("-footer");
1690: toExecute.createArgument().setValue(
1691: expand(footer.getText()));
1692: }
1693: if (bottom != null) {
1694: toExecute.createArgument().setValue("-bottom");
1695: toExecute.createArgument().setValue(
1696: expand(bottom.getText()));
1697: }
1698:
1699: if (classpath == null) {
1700: classpath = (new Path(getProject()))
1701: .concatSystemClasspath("last");
1702: } else {
1703: classpath = classpath.concatSystemClasspath("ignore");
1704: }
1705:
1706: if (classpath.size() > 0) {
1707: toExecute.createArgument().setValue("-classpath");
1708: toExecute.createArgument().setPath(classpath);
1709: }
1710: if (sourceDirs.size() > 0) {
1711: toExecute.createArgument().setValue("-sourcepath");
1712: toExecute.createArgument().setPath(sourceDirs);
1713: }
1714:
1715: if (version && doclet == null) {
1716: toExecute.createArgument().setValue("-version");
1717: }
1718: if (author && doclet == null) {
1719: toExecute.createArgument().setValue("-author");
1720: }
1721:
1722: if (doclet == null && destDir == null) {
1723: throw new BuildException("destdir attribute must be set!");
1724: }
1725:
1726: // ---------------------------- javadoc2 arguments for default doclet
1727:
1728: if (doclet != null) {
1729: if (doclet.getName() == null) {
1730: throw new BuildException("The doclet name must be "
1731: + "specified.", getLocation());
1732: } else {
1733: toExecute.createArgument().setValue("-doclet");
1734: toExecute.createArgument().setValue(doclet.getName());
1735: if (doclet.getPath() != null) {
1736: Path docletPath = doclet.getPath()
1737: .concatSystemClasspath("ignore");
1738: if (docletPath.size() != 0) {
1739: toExecute.createArgument().setValue(
1740: "-docletpath");
1741: toExecute.createArgument().setPath(docletPath);
1742: }
1743: }
1744: for (Enumeration e = doclet.getParams(); e
1745: .hasMoreElements();) {
1746: DocletParam param = (DocletParam) e.nextElement();
1747: if (param.getName() == null) {
1748: throw new BuildException(
1749: "Doclet parameters must "
1750: + "have a name");
1751: }
1752:
1753: toExecute.createArgument()
1754: .setValue(param.getName());
1755: if (param.getValue() != null) {
1756: toExecute.createArgument().setValue(
1757: param.getValue());
1758: }
1759: }
1760: }
1761: }
1762: Path bcp = new Path(getProject());
1763: if (bootclasspath != null) {
1764: bcp.append(bootclasspath);
1765: }
1766: bcp = bcp.concatSystemBootClasspath("ignore");
1767: if (bcp.size() > 0) {
1768: toExecute.createArgument().setValue("-bootclasspath");
1769: toExecute.createArgument().setPath(bcp);
1770: }
1771:
1772: // add the links arguments
1773: if (links.size() != 0) {
1774: for (Enumeration e = links.elements(); e.hasMoreElements();) {
1775: LinkArgument la = (LinkArgument) e.nextElement();
1776:
1777: if (la.getHref() == null || la.getHref().length() == 0) {
1778: log("No href was given for the link - skipping",
1779: Project.MSG_VERBOSE);
1780: continue;
1781: }
1782: String link = null;
1783: if (la.shouldResolveLink()) {
1784: File hrefAsFile = getProject().resolveFile(
1785: la.getHref());
1786: if (hrefAsFile.exists()) {
1787: try {
1788: link = FILE_UTILS.getFileURL(hrefAsFile)
1789: .toExternalForm();
1790: } catch (MalformedURLException ex) {
1791: // should be impossible
1792: log("Warning: link location was invalid "
1793: + hrefAsFile, Project.MSG_WARN);
1794: }
1795: }
1796: }
1797: if (link == null) {
1798: // is the href a valid URL
1799: try {
1800: URL base = new URL("file://.");
1801: new URL(base, la.getHref());
1802: link = la.getHref();
1803: } catch (MalformedURLException mue) {
1804: // ok - just skip
1805: log(
1806: "Link href \""
1807: + la.getHref()
1808: + "\" is not a valid url - skipping link",
1809: Project.MSG_WARN);
1810: continue;
1811: }
1812: }
1813:
1814: if (la.isLinkOffline()) {
1815: File packageListLocation = la.getPackagelistLoc();
1816: if (packageListLocation == null) {
1817: throw new BuildException("The package list"
1818: + " location for link " + la.getHref()
1819: + " must be provided "
1820: + "because the link is " + "offline");
1821: }
1822: File packageListFile = new File(
1823: packageListLocation, "package-list");
1824: if (packageListFile.exists()) {
1825: try {
1826: String packageListURL = FILE_UTILS
1827: .getFileURL(packageListLocation)
1828: .toExternalForm();
1829: toExecute.createArgument().setValue(
1830: "-linkoffline");
1831: toExecute.createArgument().setValue(link);
1832: toExecute.createArgument().setValue(
1833: packageListURL);
1834: } catch (MalformedURLException ex) {
1835: log("Warning: Package list location was "
1836: + "invalid " + packageListLocation,
1837: Project.MSG_WARN);
1838: }
1839: } else {
1840: log("Warning: No package list was found at "
1841: + packageListLocation,
1842: Project.MSG_VERBOSE);
1843: }
1844: } else {
1845: toExecute.createArgument().setValue("-link");
1846: toExecute.createArgument().setValue(link);
1847: }
1848: }
1849: }
1850:
1851: // add the single group arguments
1852: // Javadoc 1.2 rules:
1853: // Multiple -group args allowed.
1854: // Each arg includes 3 strings: -group [name] [packagelist].
1855: // Elements in [packagelist] are colon-delimited.
1856: // An element in [packagelist] may end with the * wildcard.
1857:
1858: // Ant javadoc task rules for group attribute:
1859: // Args are comma-delimited.
1860: // Each arg is 2 space-delimited strings.
1861: // E.g., group="XSLT_Packages org.apache.xalan.xslt*,
1862: // XPath_Packages org.apache.xalan.xpath*"
1863: if (group != null) {
1864: StringTokenizer tok = new StringTokenizer(group, ",", false);
1865: while (tok.hasMoreTokens()) {
1866: String grp = tok.nextToken().trim();
1867: int space = grp.indexOf(" ");
1868: if (space > 0) {
1869: String name = grp.substring(0, space);
1870: String pkgList = grp.substring(space + 1);
1871: toExecute.createArgument().setValue("-group");
1872: toExecute.createArgument().setValue(name);
1873: toExecute.createArgument().setValue(pkgList);
1874: }
1875: }
1876: }
1877:
1878: // add the group arguments
1879: if (groups.size() != 0) {
1880: for (Enumeration e = groups.elements(); e.hasMoreElements();) {
1881: GroupArgument ga = (GroupArgument) e.nextElement();
1882: String title = ga.getTitle();
1883: String packages = ga.getPackages();
1884: if (title == null || packages == null) {
1885: throw new BuildException(
1886: "The title and packages must "
1887: + "be specified for group "
1888: + "elements.");
1889: }
1890: toExecute.createArgument().setValue("-group");
1891: toExecute.createArgument().setValue(expand(title));
1892: toExecute.createArgument().setValue(packages);
1893: }
1894: }
1895:
1896: // Javadoc 1.4 parameters
1897: if (javadoc4 || executable != null) {
1898: for (Enumeration e = tags.elements(); e.hasMoreElements();) {
1899: Object element = e.nextElement();
1900: if (element instanceof TagArgument) {
1901: TagArgument ta = (TagArgument) element;
1902: File tagDir = ta.getDir(getProject());
1903: if (tagDir == null) {
1904: // The tag element is not used as a fileset,
1905: // but specifies the tag directly.
1906: toExecute.createArgument().setValue("-tag");
1907: toExecute.createArgument().setValue(
1908: ta.getParameter());
1909: } else {
1910: // The tag element is used as a
1911: // fileset. Parse all the files and create
1912: // -tag arguments.
1913: DirectoryScanner tagDefScanner = ta
1914: .getDirectoryScanner(getProject());
1915: String[] files = tagDefScanner
1916: .getIncludedFiles();
1917: for (int i = 0; i < files.length; i++) {
1918: File tagDefFile = new File(tagDir, files[i]);
1919: try {
1920: BufferedReader in = new BufferedReader(
1921: new FileReader(tagDefFile));
1922: String line = null;
1923: while ((line = in.readLine()) != null) {
1924: toExecute.createArgument()
1925: .setValue("-tag");
1926: toExecute.createArgument()
1927: .setValue(line);
1928: }
1929: in.close();
1930: } catch (IOException ioe) {
1931: throw new BuildException(
1932: "Couldn't read "
1933: + " tag file from "
1934: + tagDefFile
1935: .getAbsolutePath(),
1936: ioe);
1937: }
1938: }
1939: }
1940: } else {
1941: ExtensionInfo tagletInfo = (ExtensionInfo) element;
1942: toExecute.createArgument().setValue("-taglet");
1943: toExecute.createArgument().setValue(
1944: tagletInfo.getName());
1945: if (tagletInfo.getPath() != null) {
1946: Path tagletPath = tagletInfo.getPath()
1947: .concatSystemClasspath("ignore");
1948: if (tagletPath.size() != 0) {
1949: toExecute.createArgument().setValue(
1950: "-tagletpath");
1951: toExecute.createArgument().setPath(
1952: tagletPath);
1953: }
1954: }
1955: }
1956: }
1957:
1958: String sourceArg = source != null ? source : getProject()
1959: .getProperty(MagicNames.BUILD_JAVAC_SOURCE);
1960: if (sourceArg != null) {
1961: toExecute.createArgument().setValue("-source");
1962: toExecute.createArgument().setValue(sourceArg);
1963: }
1964:
1965: if (linksource && doclet == null) {
1966: toExecute.createArgument().setValue("-linksource");
1967: }
1968: if (breakiterator && (doclet == null || javadoc5)) {
1969: toExecute.createArgument().setValue("-breakiterator");
1970: }
1971: if (noqualifier != null && doclet == null) {
1972: toExecute.createArgument().setValue("-noqualifier");
1973: toExecute.createArgument().setValue(noqualifier);
1974: }
1975: } else {
1976: // Not 1.4+.
1977: if (!tags.isEmpty()) {
1978: log(
1979: "-tag and -taglet options not supported on Javadoc < 1.4",
1980: Project.MSG_VERBOSE);
1981: }
1982: if (source != null) {
1983: log("-source option not supported on Javadoc < 1.4",
1984: Project.MSG_VERBOSE);
1985: }
1986: if (linksource) {
1987: log(
1988: "-linksource option not supported on Javadoc < 1.4",
1989: Project.MSG_VERBOSE);
1990: }
1991: if (breakiterator) {
1992: log(
1993: "-breakiterator option not supported on Javadoc < 1.4",
1994: Project.MSG_VERBOSE);
1995: }
1996: if (noqualifier != null) {
1997: log(
1998: "-noqualifier option not supported on Javadoc < 1.4",
1999: Project.MSG_VERBOSE);
2000: }
2001: }
2002: // Javadoc 1.2/1.3 parameters:
2003: if (!javadoc4 || executable != null) {
2004: if (old) {
2005: toExecute.createArgument().setValue("-1.1");
2006: }
2007: } else {
2008: if (old) {
2009: log(
2010: "Javadoc 1.4 doesn't support the -1.1 switch anymore",
2011: Project.MSG_WARN);
2012: }
2013: }
2014: // If using an external file, write the command line options to it
2015: if (useExternalFile && javadoc4) {
2016: writeExternalArgs(toExecute);
2017: }
2018:
2019: File tmpList = null;
2020: PrintWriter srcListWriter = null;
2021:
2022: try {
2023:
2024: /**
2025: * Write sourcefiles and package names to a temporary file
2026: * if requested.
2027: */
2028: if (useExternalFile) {
2029: if (tmpList == null) {
2030: tmpList = FILE_UTILS.createTempFile("javadoc", "",
2031: null);
2032: tmpList.deleteOnExit();
2033: toExecute.createArgument().setValue(
2034: "@" + tmpList.getAbsolutePath());
2035: }
2036: srcListWriter = new PrintWriter(new FileWriter(tmpList
2037: .getAbsolutePath(), true));
2038: }
2039:
2040: Enumeration e = packagesToDoc.elements();
2041: while (e.hasMoreElements()) {
2042: String packageName = (String) e.nextElement();
2043: if (useExternalFile) {
2044: srcListWriter.println(packageName);
2045: } else {
2046: toExecute.createArgument().setValue(packageName);
2047: }
2048: }
2049:
2050: e = sourceFilesToDoc.elements();
2051: while (e.hasMoreElements()) {
2052: SourceFile sf = (SourceFile) e.nextElement();
2053: String sourceFileName = sf.getFile().getAbsolutePath();
2054: if (useExternalFile) {
2055: // XXX what is the following doing?
2056: // should it run if !javadoc4 && executable != null?
2057: if (javadoc4 && sourceFileName.indexOf(" ") > -1) {
2058: String name = sourceFileName;
2059: if (File.separatorChar == '\\') {
2060: name = sourceFileName.replace(
2061: File.separatorChar, '/');
2062: }
2063: srcListWriter.println("\"" + name + "\"");
2064: } else {
2065: srcListWriter.println(sourceFileName);
2066: }
2067: } else {
2068: toExecute.createArgument().setValue(sourceFileName);
2069: }
2070: }
2071:
2072: } catch (IOException e) {
2073: tmpList.delete();
2074: throw new BuildException("Error creating temporary file",
2075: e, getLocation());
2076: } finally {
2077: if (srcListWriter != null) {
2078: srcListWriter.close();
2079: }
2080: }
2081:
2082: if (packageList != null) {
2083: toExecute.createArgument().setValue("@" + packageList);
2084: }
2085: log(toExecute.describeCommand(), Project.MSG_VERBOSE);
2086:
2087: log("Javadoc execution", Project.MSG_INFO);
2088:
2089: JavadocOutputStream out = new JavadocOutputStream(
2090: Project.MSG_INFO);
2091: JavadocOutputStream err = new JavadocOutputStream(
2092: Project.MSG_WARN);
2093: Execute exe = new Execute(new PumpStreamHandler(out, err));
2094: exe.setAntRun(getProject());
2095:
2096: /*
2097: * No reason to change the working directory as all filenames and
2098: * path components have been resolved already.
2099: *
2100: * Avoid problems with command line length in some environments.
2101: */
2102: exe.setWorkingDirectory(null);
2103: try {
2104: exe.setCommandline(toExecute.getCommandline());
2105: int ret = exe.execute();
2106: if (ret != 0 && failOnError) {
2107: throw new BuildException("Javadoc returned " + ret,
2108: getLocation());
2109: }
2110: } catch (IOException e) {
2111: throw new BuildException("Javadoc failed: " + e, e,
2112: getLocation());
2113: } finally {
2114: if (tmpList != null) {
2115: tmpList.delete();
2116: tmpList = null;
2117: }
2118:
2119: out.logFlush();
2120: err.logFlush();
2121: try {
2122: out.close();
2123: err.close();
2124: } catch (IOException e) {
2125: // ignore
2126: }
2127: }
2128: }
2129:
2130: private void writeExternalArgs(Commandline toExecute) {
2131: // If using an external file, write the command line options to it
2132: File optionsTmpFile = null;
2133: PrintWriter optionsListWriter = null;
2134: try {
2135: optionsTmpFile = FILE_UTILS.createTempFile(
2136: "javadocOptions", "", null);
2137: optionsTmpFile.deleteOnExit();
2138: String[] listOpt = toExecute.getArguments();
2139: toExecute.clearArgs();
2140: toExecute.createArgument().setValue(
2141: "@" + optionsTmpFile.getAbsolutePath());
2142: optionsListWriter = new PrintWriter(new FileWriter(
2143: optionsTmpFile.getAbsolutePath(), true));
2144: for (int i = 0; i < listOpt.length; i++) {
2145: String string = listOpt[i];
2146: if (string.startsWith("-J-")) {
2147: toExecute.createArgument().setValue(string);
2148: } else {
2149: if (string.startsWith("-")) {
2150: optionsListWriter.print(string);
2151: optionsListWriter.print(" ");
2152: } else {
2153: optionsListWriter.println(quoteString(string));
2154: }
2155: }
2156: }
2157: optionsListWriter.close();
2158: } catch (IOException ex) {
2159: if (optionsTmpFile != null) {
2160: optionsTmpFile.delete();
2161: }
2162: throw new BuildException(
2163: "Error creating or writing temporary file for javadoc options",
2164: ex, getLocation());
2165: } finally {
2166: FILE_UTILS.close(optionsListWriter);
2167: }
2168: }
2169:
2170: /**
2171: * Quote a string to place in a @ file.
2172: * @param str the string to quote
2173: * @return the quoted string, if there is no need to quote the string,
2174: * return the original string.
2175: */
2176: private String quoteString(String str) {
2177: if (str.indexOf(' ') == -1 && str.indexOf('\'') == -1
2178: && str.indexOf('"') == -1) {
2179: return str;
2180: }
2181: if (str.indexOf('\'') == -1) {
2182: return quoteString(str, '\'');
2183: } else {
2184: return quoteString(str, '"');
2185: }
2186: }
2187:
2188: private String quoteString(String str, char delim) {
2189: StringBuffer buf = new StringBuffer(str.length() * 2);
2190: buf.append(delim);
2191: if (str.indexOf('\\') != -1) {
2192: str = replace(str, '\\', "\\\\");
2193: }
2194: if (str.indexOf(delim) != -1) {
2195: str = replace(str, delim, "\\" + delim);
2196: }
2197: buf.append(str);
2198: buf.append(delim);
2199: return buf.toString();
2200: }
2201:
2202: private String replace(String str, char fromChar, String toString) {
2203: StringBuffer buf = new StringBuffer(str.length() * 2);
2204: for (int i = 0; i < str.length(); ++i) {
2205: char ch = str.charAt(i);
2206: if (ch == fromChar) {
2207: buf.append(toString);
2208: } else {
2209: buf.append(ch);
2210: }
2211: }
2212: return buf.toString();
2213: }
2214:
2215: /**
2216: * Add the files matched by the nested source files to the Vector
2217: * as SourceFile instances.
2218: *
2219: * @since 1.7
2220: */
2221: private void addSourceFiles(Vector sf) {
2222: Iterator e = nestedSourceFiles.iterator();
2223: while (e.hasNext()) {
2224: ResourceCollection rc = (ResourceCollection) e.next();
2225: if (!rc.isFilesystemOnly()) {
2226: throw new BuildException(
2227: "only file system based resources are"
2228: + " supported by javadoc");
2229: }
2230: if (rc instanceof FileSet) {
2231: FileSet fs = (FileSet) rc;
2232: if (!fs.hasPatterns() && !fs.hasSelectors()) {
2233: fs = (FileSet) fs.clone();
2234: fs.createInclude().setName("**/*.java");
2235: if (includeNoSourcePackages) {
2236: fs.createInclude().setName("**/package.html");
2237: }
2238: }
2239: }
2240: Iterator iter = rc.iterator();
2241: while (iter.hasNext()) {
2242: sf.addElement(new SourceFile(((FileResource) iter
2243: .next()).getFile()));
2244: }
2245: }
2246: }
2247:
2248: /**
2249: * Add the directories matched by the nested dirsets to the Vector
2250: * and the base directories of the dirsets to the Path. It also
2251: * handles the packages and excludepackages attributes and
2252: * elements.
2253: *
2254: * @since 1.5
2255: */
2256: private void parsePackages(Vector pn, Path sp) {
2257: Vector addedPackages = new Vector();
2258: Vector dirSets = (Vector) packageSets.clone();
2259:
2260: // for each sourcePath entry, add a directoryset with includes
2261: // taken from packagenames attribute and nested package
2262: // elements and excludes taken from excludepackages attribute
2263: // and nested excludepackage elements
2264: if (sourcePath != null) {
2265: PatternSet ps = new PatternSet();
2266: if (packageNames.size() > 0) {
2267: Enumeration e = packageNames.elements();
2268: while (e.hasMoreElements()) {
2269: PackageName p = (PackageName) e.nextElement();
2270: String pkg = p.getName().replace('.', '/');
2271: if (pkg.endsWith("*")) {
2272: pkg += "*";
2273: }
2274: ps.createInclude().setName(pkg);
2275: }
2276: } else {
2277: ps.createInclude().setName("**");
2278: }
2279:
2280: Enumeration e = excludePackageNames.elements();
2281: while (e.hasMoreElements()) {
2282: PackageName p = (PackageName) e.nextElement();
2283: String pkg = p.getName().replace('.', '/');
2284: if (pkg.endsWith("*")) {
2285: pkg += "*";
2286: }
2287: ps.createExclude().setName(pkg);
2288: }
2289:
2290: String[] pathElements = sourcePath.list();
2291: for (int i = 0; i < pathElements.length; i++) {
2292: File dir = new File(pathElements[i]);
2293: if (dir.isDirectory()) {
2294: DirSet ds = new DirSet();
2295: ds.setDefaultexcludes(useDefaultExcludes);
2296: ds.setDir(dir);
2297: ds.createPatternSet().addConfiguredPatternset(ps);
2298: dirSets.addElement(ds);
2299: } else {
2300: log("Skipping " + pathElements[i]
2301: + " since it is no directory.",
2302: Project.MSG_WARN);
2303: }
2304: }
2305: }
2306:
2307: Enumeration e = dirSets.elements();
2308: while (e.hasMoreElements()) {
2309: DirSet ds = (DirSet) e.nextElement();
2310: File baseDir = ds.getDir(getProject());
2311: log("scanning " + baseDir + " for packages.",
2312: Project.MSG_DEBUG);
2313: DirectoryScanner dsc = ds.getDirectoryScanner(getProject());
2314: String[] dirs = dsc.getIncludedDirectories();
2315: boolean containsPackages = false;
2316: for (int i = 0; i < dirs.length; i++) {
2317: // are there any java files in this directory?
2318: File pd = new File(baseDir, dirs[i]);
2319: String[] files = pd.list(new FilenameFilter() {
2320: public boolean accept(File dir1, String name) {
2321: return name.endsWith(".java")
2322: || (includeNoSourcePackages && name
2323: .equals("package.html"));
2324: }
2325: });
2326:
2327: if (files.length > 0) {
2328: if ("".equals(dirs[i])) {
2329: log(
2330: baseDir
2331: + " contains source files in the default package,"
2332: + " you must specify them as source files"
2333: + " not packages.",
2334: Project.MSG_WARN);
2335: } else {
2336: containsPackages = true;
2337: String packageName = dirs[i].replace(
2338: File.separatorChar, '.');
2339: if (!addedPackages.contains(packageName)) {
2340: addedPackages.addElement(packageName);
2341: pn.addElement(packageName);
2342: }
2343: }
2344: }
2345: }
2346: if (containsPackages) {
2347: // We don't need to care for duplicates here,
2348: // Path.list does it for us.
2349: sp.createPathElement().setLocation(baseDir);
2350: } else {
2351: log(
2352: baseDir
2353: + " doesn\'t contain any packages, dropping it.",
2354: Project.MSG_VERBOSE);
2355: }
2356: }
2357: }
2358:
2359: private class JavadocOutputStream extends LogOutputStream {
2360: JavadocOutputStream(int level) {
2361: super (Javadoc.this , level);
2362: }
2363:
2364: //
2365: // Override the logging of output in order to filter out Generating
2366: // messages. Generating messages are set to a priority of VERBOSE
2367: // unless they appear after what could be an informational message.
2368: //
2369: private String queuedLine = null;
2370:
2371: protected void processLine(String line, int messageLevel) {
2372: if (messageLevel == Project.MSG_INFO
2373: && line.startsWith("Generating ")) {
2374: if (queuedLine != null) {
2375: super .processLine(queuedLine, Project.MSG_VERBOSE);
2376: }
2377: queuedLine = line;
2378: } else {
2379: if (queuedLine != null) {
2380: if (line.startsWith("Building ")) {
2381: super .processLine(queuedLine,
2382: Project.MSG_VERBOSE);
2383: } else {
2384: super .processLine(queuedLine, Project.MSG_INFO);
2385: }
2386: queuedLine = null;
2387: }
2388: super .processLine(line, messageLevel);
2389: }
2390: }
2391:
2392: protected void logFlush() {
2393: if (queuedLine != null) {
2394: super .processLine(queuedLine, Project.MSG_VERBOSE);
2395: queuedLine = null;
2396: }
2397: }
2398: }
2399:
2400: /**
2401: * Convenience method to expand properties.
2402: * @param content the string to expand
2403: * @return the converted string
2404: */
2405: protected String expand(String content) {
2406: return getProject().replaceProperties(content);
2407: }
2408:
2409: }
|