You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

Javadoc.java 47 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Ant", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.tools.ant.taskdefs;
  55. import java.io.File;
  56. import java.io.PrintWriter;
  57. import java.io.FileWriter;
  58. import java.io.IOException;
  59. import java.io.FilenameFilter;
  60. import java.util.Locale;
  61. import java.util.Vector;
  62. import java.util.Enumeration;
  63. import java.util.StringTokenizer;
  64. import org.apache.tools.ant.BuildException;
  65. import org.apache.tools.ant.DirectoryScanner;
  66. import org.apache.tools.ant.Project;
  67. import org.apache.tools.ant.ProjectComponent;
  68. import org.apache.tools.ant.Task;
  69. import org.apache.tools.ant.types.Path;
  70. import org.apache.tools.ant.types.Reference;
  71. import org.apache.tools.ant.types.EnumeratedAttribute;
  72. import org.apache.tools.ant.types.Commandline;
  73. import org.apache.tools.ant.types.FileSet;
  74. import org.apache.tools.ant.util.FileUtils;
  75. import org.apache.tools.ant.util.JavaEnvUtils;
  76. /**
  77. * This task makes it easy to generate Javadoc documentation for a collection
  78. * of source code.
  79. *
  80. * <P>Current known limitations are:
  81. *
  82. * <P><UL>
  83. * <LI>patterns must be of the form "xxx.*", every other pattern doesn't
  84. * work.
  85. * <LI>the java comment-stripper reader is horribly slow
  86. * <LI>there is no control on arguments sanity since they are left
  87. * to the javadoc implementation.
  88. * <LI>argument J in javadoc1 is not supported (what is that for anyway?)
  89. * </UL>
  90. *
  91. * <P>If no <CODE>doclet</CODE> is set, then the <CODE>version</CODE> and
  92. * <CODE>author</CODE> are by default <CODE>"yes"</CODE>.
  93. *
  94. * <P>Note: This task is run on another VM because the Javadoc code calls
  95. * <CODE>System.exit()</CODE> which would break Ant functionality.
  96. *
  97. * @author Jon S. Stevens <a href="mailto:jon@clearink.com">jon@clearink.com</a>
  98. * @author Stefano Mazzocchi <a href="mailto:stefano@apache.org">stefano@apache.org</a>
  99. * @author Patrick Chanezon <a href="mailto:chanezon@netscape.com">chanezon@netscape.com</a>
  100. * @author Ernst de Haan <a href="mailto:ernst@jollem.com">ernst@jollem.com</a>
  101. * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
  102. *
  103. * @ant.task category="java"
  104. */
  105. public class Javadoc extends Task {
  106. public class DocletParam {
  107. private String name;
  108. private String value;
  109. public void setName(String name) {
  110. this.name = name;
  111. }
  112. public String getName() {
  113. return name;
  114. }
  115. public void setValue(String value) {
  116. this.value = value;
  117. }
  118. public String getValue() {
  119. return value;
  120. }
  121. }
  122. static public class ExtensionInfo extends ProjectComponent {
  123. private String name;
  124. private Path path;
  125. public void setName(String name) {
  126. this.name = name;
  127. }
  128. public String getName() {
  129. return name;
  130. }
  131. public void setPath(Path path) {
  132. if (this.path == null) {
  133. this.path = path;
  134. } else {
  135. this.path.append(path);
  136. }
  137. }
  138. public Path getPath() {
  139. return path;
  140. }
  141. public Path createPath() {
  142. if (path == null) {
  143. path = new Path(getProject());
  144. }
  145. return path.createPath();
  146. }
  147. /**
  148. * Adds a reference to a CLASSPATH defined elsewhere.
  149. */
  150. public void setPathRef(Reference r) {
  151. createPath().setRefid(r);
  152. }
  153. }
  154. public class DocletInfo extends ExtensionInfo {
  155. private Vector params = new Vector();
  156. public DocletParam createParam() {
  157. DocletParam param = new DocletParam();
  158. params.addElement(param);
  159. return param;
  160. }
  161. public Enumeration getParams() {
  162. return params.elements();
  163. }
  164. }
  165. public static class PackageName {
  166. private String name;
  167. public void setName(String name) {
  168. this.name = name;
  169. }
  170. public String getName() {
  171. return name;
  172. }
  173. public String toString() {
  174. return getName();
  175. }
  176. }
  177. public static class SourceFile {
  178. private File file;
  179. public void setFile(File file) {
  180. this.file = file;
  181. }
  182. public File getFile() {
  183. return file;
  184. }
  185. }
  186. public static class Html {
  187. private StringBuffer text = new StringBuffer();
  188. public void addText(String t) {
  189. text.append(t);
  190. }
  191. public String getText() {
  192. return text.toString();
  193. }
  194. }
  195. public static class AccessType extends EnumeratedAttribute {
  196. public String[] getValues() {
  197. // Protected first so if any GUI tool offers a default
  198. // based on enum #0, it will be right.
  199. return new String[] {"protected", "public", "package", "private"};
  200. }
  201. }
  202. private Commandline cmd = new Commandline();
  203. private static boolean javadoc1 =
  204. (JavaEnvUtils.getJavaVersion() == Project.JAVA_1_1);
  205. private static boolean javadoc4 =
  206. (JavaEnvUtils.getJavaVersion() != Project.JAVA_1_1 &&
  207. JavaEnvUtils.getJavaVersion() != Project.JAVA_1_2 &&
  208. JavaEnvUtils.getJavaVersion() != Project.JAVA_1_3);
  209. private void addArgIf(boolean b, String arg) {
  210. if (b) {
  211. cmd.createArgument().setValue(arg);
  212. }
  213. }
  214. private void add12ArgIfNotEmpty(String key, String value) {
  215. if (!javadoc1) {
  216. if (value != null && value.length() != 0) {
  217. cmd.createArgument().setValue(key);
  218. cmd.createArgument().setValue(value);
  219. } else {
  220. project.log(this,
  221. "Warning: Leaving out empty argument '" + key + "'",
  222. Project.MSG_WARN);
  223. }
  224. }
  225. }
  226. private void add12ArgIf(boolean b, String arg) {
  227. if (!javadoc1 && b) {
  228. cmd.createArgument().setValue(arg);
  229. }
  230. }
  231. private boolean failOnError = false;
  232. private Path sourcePath = null;
  233. private File destDir = null;
  234. private Vector sourceFiles = new Vector();
  235. private Vector packageNames = new Vector(5);
  236. private Vector excludePackageNames = new Vector(1);
  237. private boolean author = true;
  238. private boolean version = true;
  239. private DocletInfo doclet = null;
  240. private Path classpath = null;
  241. private Path bootclasspath = null;
  242. private String group = null;
  243. private String packageList = null;
  244. private Vector links = new Vector(2);
  245. private Vector groups = new Vector(2);
  246. private Vector tags = new Vector(5);
  247. private Vector taglets = new Vector(2);
  248. private boolean useDefaultExcludes = true;
  249. private Html doctitle = null;
  250. private Html header = null;
  251. private Html footer = null;
  252. private Html bottom = null;
  253. private boolean useExternalFile = false;
  254. private File tmpList = null;
  255. private FileUtils fileUtils = FileUtils.newFileUtils();
  256. /**
  257. * Work around command line length limit by using an external file
  258. * for the sourcefiles.
  259. */
  260. public void setUseExternalFile(boolean b) {
  261. if (!javadoc1) {
  262. useExternalFile = b;
  263. }
  264. }
  265. /**
  266. * Sets whether default exclusions should be used or not.
  267. *
  268. * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
  269. * should be used, "false"|"off"|"no" when they
  270. * shouldn't be used.
  271. */
  272. public void setDefaultexcludes(boolean useDefaultExcludes) {
  273. this.useDefaultExcludes = useDefaultExcludes;
  274. }
  275. public void setMaxmemory(String max){
  276. if(javadoc1){
  277. cmd.createArgument().setValue("-J-mx" + max);
  278. } else{
  279. cmd.createArgument().setValue("-J-Xmx" + max);
  280. }
  281. }
  282. public void setAdditionalparam(String add){
  283. cmd.createArgument().setLine(add);
  284. }
  285. public void setSourcepath(Path src) {
  286. if (sourcePath == null) {
  287. sourcePath = src;
  288. } else {
  289. sourcePath.append(src);
  290. }
  291. }
  292. public Path createSourcepath() {
  293. if (sourcePath == null) {
  294. sourcePath = new Path(project);
  295. }
  296. return sourcePath.createPath();
  297. }
  298. /**
  299. * Adds a reference to a CLASSPATH defined elsewhere.
  300. */
  301. public void setSourcepathRef(Reference r) {
  302. createSourcepath().setRefid(r);
  303. }
  304. public void setDestdir(File dir) {
  305. destDir = dir;
  306. cmd.createArgument().setValue("-d");
  307. cmd.createArgument().setFile(destDir);
  308. }
  309. public void setSourcefiles(String src) {
  310. StringTokenizer tok = new StringTokenizer(src, ",");
  311. while (tok.hasMoreTokens()) {
  312. String f = tok.nextToken();
  313. SourceFile sf = new SourceFile();
  314. sf.setFile(project.resolveFile(f));
  315. addSource(sf);
  316. }
  317. }
  318. public void addSource(SourceFile sf) {
  319. sourceFiles.addElement(sf);
  320. }
  321. public void setPackagenames(String src) {
  322. StringTokenizer tok = new StringTokenizer(src, ",");
  323. while (tok.hasMoreTokens()) {
  324. String p = tok.nextToken();
  325. PackageName pn = new PackageName();
  326. pn.setName(p);
  327. addPackage(pn);
  328. }
  329. }
  330. public void addPackage(PackageName pn) {
  331. packageNames.addElement(pn);
  332. }
  333. public void setExcludePackageNames(String src) {
  334. StringTokenizer tok = new StringTokenizer(src, ",");
  335. while (tok.hasMoreTokens()) {
  336. String p = tok.nextToken();
  337. PackageName pn = new PackageName();
  338. pn.setName(p);
  339. addExcludePackage(pn);
  340. }
  341. }
  342. public void addExcludePackage(PackageName pn) {
  343. excludePackageNames.addElement(pn);
  344. }
  345. public void setOverview(File f) {
  346. if (!javadoc1) {
  347. cmd.createArgument().setValue("-overview");
  348. cmd.createArgument().setFile(f);
  349. }
  350. }
  351. public void setPublic(boolean b) {
  352. addArgIf(b, "-public");
  353. }
  354. public void setProtected(boolean b) {
  355. addArgIf(b, "-protected");
  356. }
  357. public void setPackage(boolean b) {
  358. addArgIf(b, "-package");
  359. }
  360. public void setPrivate(boolean b) {
  361. addArgIf(b, "-private");
  362. }
  363. public void setAccess(AccessType at) {
  364. cmd.createArgument().setValue("-" + at.getValue());
  365. }
  366. public void setDoclet(String src) {
  367. if (doclet == null) {
  368. doclet = new DocletInfo();
  369. }
  370. doclet.setName(src);
  371. }
  372. public void setDocletPath(Path src) {
  373. if (doclet == null) {
  374. doclet = new DocletInfo();
  375. }
  376. doclet.setPath(src);
  377. }
  378. public void setDocletPathRef(Reference r) {
  379. if (doclet == null) {
  380. doclet = new DocletInfo();
  381. }
  382. doclet.createPath().setRefid(r);
  383. }
  384. public DocletInfo createDoclet() {
  385. doclet = new DocletInfo();
  386. return doclet;
  387. }
  388. public void addTaglet(ExtensionInfo tagletInfo) {
  389. taglets.addElement(tagletInfo);
  390. }
  391. public void setOld(boolean b) {
  392. add12ArgIf(b, "-1.1");
  393. }
  394. public void setClasspath(Path src) {
  395. if (classpath == null) {
  396. classpath = src;
  397. } else {
  398. classpath.append(src);
  399. }
  400. }
  401. public Path createClasspath() {
  402. if (classpath == null) {
  403. classpath = new Path(project);
  404. }
  405. return classpath.createPath();
  406. }
  407. /**
  408. * Adds a reference to a CLASSPATH defined elsewhere.
  409. */
  410. public void setClasspathRef(Reference r) {
  411. createClasspath().setRefid(r);
  412. }
  413. public void setBootclasspath(Path src) {
  414. if (bootclasspath == null) {
  415. bootclasspath = src;
  416. } else {
  417. bootclasspath.append(src);
  418. }
  419. }
  420. public Path createBootclasspath() {
  421. if (bootclasspath == null) {
  422. bootclasspath = new Path(project);
  423. }
  424. return bootclasspath.createPath();
  425. }
  426. /**
  427. * Adds a reference to a CLASSPATH defined elsewhere.
  428. */
  429. public void setBootClasspathRef(Reference r) {
  430. createBootclasspath().setRefid(r);
  431. }
  432. public void setExtdirs(String src) {
  433. if (!javadoc1) {
  434. cmd.createArgument().setValue("-extdirs");
  435. cmd.createArgument().setValue(src);
  436. }
  437. }
  438. public void setVerbose(boolean b) {
  439. add12ArgIf(b, "-verbose");
  440. }
  441. public void setLocale(String src) {
  442. if (!javadoc1) {
  443. // createArgument(true) is necessary to make sure, -locale
  444. // is the first argument (required in 1.3+).
  445. cmd.createArgument(true).setValue(src);
  446. cmd.createArgument(true).setValue("-locale");
  447. }
  448. }
  449. public void setEncoding(String enc) {
  450. cmd.createArgument().setValue("-encoding");
  451. cmd.createArgument().setValue(enc);
  452. }
  453. public void setVersion(boolean src) {
  454. version = src;
  455. }
  456. public void setUse(boolean b) {
  457. add12ArgIf(b, "-use");
  458. }
  459. public void setAuthor(boolean src) {
  460. author = src;
  461. }
  462. public void setSplitindex(boolean b) {
  463. add12ArgIf(b, "-splitindex");
  464. }
  465. public void setWindowtitle(String src) {
  466. add12ArgIfNotEmpty("-windowtitle", src);
  467. }
  468. public void setDoctitle(String src) {
  469. Html h = new Html();
  470. h.addText(src);
  471. addDoctitle(h);
  472. }
  473. public void addDoctitle(Html text) {
  474. if (!javadoc1) {
  475. doctitle = text;
  476. }
  477. }
  478. public void setHeader(String src) {
  479. Html h = new Html();
  480. h.addText(src);
  481. addHeader(h);
  482. }
  483. public void addHeader(Html text) {
  484. if (!javadoc1) {
  485. header = text;
  486. }
  487. }
  488. public void setFooter(String src) {
  489. Html h = new Html();
  490. h.addText(src);
  491. addFooter(h);
  492. }
  493. public void addFooter(Html text) {
  494. if (!javadoc1) {
  495. footer = text;
  496. }
  497. }
  498. public void setBottom(String src) {
  499. Html h = new Html();
  500. h.addText(src);
  501. addBottom(h);
  502. }
  503. public void addBottom(Html text) {
  504. if (!javadoc1) {
  505. bottom = text;
  506. }
  507. }
  508. public void setLinkoffline(String src) {
  509. if (!javadoc1) {
  510. LinkArgument le = createLink();
  511. le.setOffline(true);
  512. String linkOfflineError = "The linkoffline attribute must include a URL and " +
  513. "a package-list file location separated by a space";
  514. if (src.trim().length() == 0) {
  515. throw new BuildException(linkOfflineError);
  516. }
  517. StringTokenizer tok = new StringTokenizer(src, " ", false);
  518. le.setHref(tok.nextToken());
  519. if (!tok.hasMoreTokens()) {
  520. throw new BuildException(linkOfflineError);
  521. }
  522. le.setPackagelistLoc(project.resolveFile(tok.nextToken()));
  523. }
  524. }
  525. public void setGroup(String src) {
  526. group = src;
  527. }
  528. public void setLink(String src) {
  529. if (!javadoc1) {
  530. createLink().setHref(src);
  531. }
  532. }
  533. public void setNodeprecated(boolean b) {
  534. addArgIf(b, "-nodeprecated");
  535. }
  536. public void setNodeprecatedlist(boolean b) {
  537. add12ArgIf(b, "-nodeprecatedlist");
  538. }
  539. public void setNotree(boolean b) {
  540. addArgIf(b, "-notree");
  541. }
  542. public void setNoindex(boolean b) {
  543. addArgIf(b, "-noindex");
  544. }
  545. public void setNohelp(boolean b) {
  546. add12ArgIf(b, "-nohelp");
  547. }
  548. public void setNonavbar(boolean b) {
  549. add12ArgIf(b, "-nonavbar");
  550. }
  551. public void setSerialwarn(boolean b) {
  552. add12ArgIf(b, "-serialwarn");
  553. }
  554. public void setStylesheetfile(File f) {
  555. if (!javadoc1) {
  556. cmd.createArgument().setValue("-stylesheetfile");
  557. cmd.createArgument().setFile(f);
  558. }
  559. }
  560. public void setHelpfile(File f) {
  561. if (!javadoc1) {
  562. cmd.createArgument().setValue("-helpfile");
  563. cmd.createArgument().setFile(f);
  564. }
  565. }
  566. public void setDocencoding(String enc) {
  567. cmd.createArgument().setValue("-docencoding");
  568. cmd.createArgument().setValue(enc);
  569. }
  570. public void setPackageList(String src) {
  571. packageList = src;
  572. }
  573. public LinkArgument createLink() {
  574. LinkArgument la = new LinkArgument();
  575. links.addElement(la);
  576. return la;
  577. }
  578. public class LinkArgument {
  579. private String href;
  580. private boolean offline = false;
  581. private File packagelistLoc;
  582. public LinkArgument() {
  583. }
  584. public void setHref(String hr) {
  585. href = hr;
  586. }
  587. public String getHref() {
  588. return href;
  589. }
  590. public void setPackagelistLoc(File src) {
  591. packagelistLoc = src;
  592. }
  593. public File getPackagelistLoc() {
  594. return packagelistLoc;
  595. }
  596. public void setOffline(boolean offline) {
  597. this.offline = offline;
  598. }
  599. public boolean isLinkOffline() {
  600. return offline;
  601. }
  602. }
  603. /**
  604. * Creates and adds a -tag argument. This is used to specify
  605. * custom tags. This argument is only available for JavaDoc 1.4,
  606. * and will generate a verbose message (and then be ignored)
  607. * when run on Java versions below 1.4.
  608. *
  609. * @todo Add -taglet as well - need to preserve the order
  610. * of tag/taglet, so they need to be stored in the same list
  611. */
  612. public TagArgument createTag() {
  613. if (!javadoc4) {
  614. project.log ("-tag option not supported on JavaDoc < 1.4",
  615. Project.MSG_VERBOSE);
  616. }
  617. TagArgument ta = new TagArgument();
  618. tags.addElement (ta);
  619. return ta;
  620. }
  621. /**
  622. * Scope element verbose names. (Defined here as fields
  623. * cannot be static in inner classes.) The first letter
  624. * from each element is used to build up the scope string.
  625. */
  626. static final String[] SCOPE_ELEMENTS = {
  627. "overview", "packages", "types", "constructors",
  628. "methods", "fields"};
  629. /**
  630. * Class representing a -tag argument.
  631. */
  632. public class TagArgument {
  633. /** Name of the tag. */
  634. private String name=null;
  635. /** Description of the tag to place in the JavaDocs. */
  636. private String description=null;
  637. /** Whether or not the tag is enabled. */
  638. private boolean enabled=true;
  639. /**
  640. * Scope string of the tag. This will form the middle
  641. * argument of the -tag parameter when the tag is enabled
  642. * (with an X prepended for and is parsed from human-readable form.
  643. */
  644. private String scope="a";
  645. /** Sole constructor. */
  646. public TagArgument () {
  647. }
  648. /**
  649. * Sets the name of the tag.
  650. *
  651. * @param name The name of the tag.
  652. * Must not be <code>null</code> or empty.
  653. */
  654. public void setName (String name) {
  655. this.name=name;
  656. }
  657. /**
  658. * Sets the description of the tag. This is what appears in
  659. * the JavaDoc.
  660. *
  661. * @param description The description of the tag.
  662. * Must not be <code>null</code> or empty.
  663. */
  664. public void setDescription (String description) {
  665. this.description=description;
  666. }
  667. /**
  668. * Sets the scope of the tag. This is in comma-separated
  669. * form, with each element being one of "all" (the default),
  670. * "overview", "packages", "types", "constructors", "methods",
  671. * "fields". The elements are treated in a case-insensitive
  672. * manner.
  673. *
  674. * @param verboseScope The scope of the tag.
  675. * Must not be <code>null</code>,
  676. * should not be empty.
  677. *
  678. * @exception BuildException if all is specified along with other elements,
  679. * if any elements are repeated, if no elements are specified,
  680. * or if any unrecognised elements are specified.
  681. */
  682. public void setScope (String verboseScope) throws BuildException {
  683. verboseScope=verboseScope.toLowerCase (Locale.US);
  684. boolean[] elements=new boolean[SCOPE_ELEMENTS.length];
  685. boolean gotAll=false;
  686. boolean gotNotAll=false;
  687. // Go through the tokens one at a time, updating the
  688. // elements array and issuing warnings where appropriate.
  689. StringTokenizer tok = new StringTokenizer (verboseScope, ",");
  690. while (tok.hasMoreTokens()) {
  691. String next = tok.nextToken().trim();
  692. if (next.equals("all")) {
  693. if (gotAll) {
  694. getProject().log ("Repeated tag scope element: all",
  695. Project.MSG_VERBOSE);
  696. }
  697. gotAll=true;
  698. }
  699. else {
  700. int i;
  701. for (i=0; i < SCOPE_ELEMENTS.length; i++) {
  702. if (next.equals (SCOPE_ELEMENTS[i]))
  703. break;
  704. }
  705. if (i==SCOPE_ELEMENTS.length) {
  706. throw new BuildException ("Unrecognised scope element: "+next);
  707. }
  708. else {
  709. if (elements[i]) {
  710. getProject().log ("Repeated tag scope element: "+next,
  711. Project.MSG_VERBOSE);
  712. }
  713. elements[i]=true;
  714. gotNotAll=true;
  715. }
  716. }
  717. }
  718. if (gotNotAll && gotAll) {
  719. throw new BuildException ("Mixture of \"all\" and other scope elements "+
  720. "in tag parameter.");
  721. }
  722. if (!gotNotAll && !gotAll) {
  723. throw new BuildException ("No scope elements specified in tag parameter.");
  724. }
  725. if (gotAll) {
  726. this.scope="a";
  727. }
  728. else {
  729. StringBuffer buff = new StringBuffer (elements.length);
  730. for (int i=0; i < elements.length; i++) {
  731. if (elements[i]) {
  732. buff.append (SCOPE_ELEMENTS[i].charAt(0));
  733. }
  734. }
  735. this.scope=buff.toString();
  736. }
  737. }
  738. /**
  739. * Sets whether or not the tag is enabled.
  740. *
  741. * @param enabled Whether or not this tag is enabled.
  742. */
  743. public void setEnabled (boolean enabled) {
  744. this.enabled=enabled;
  745. }
  746. /**
  747. * Returns the -tag parameter this argument represented.
  748. *
  749. * @exception BuildException if either the name or description
  750. * is <code>null</code> or empty.
  751. */
  752. public String getParameter () throws BuildException {
  753. if (name==null || name.equals ("")) {
  754. throw new BuildException ("No name specified for custom tag.");
  755. }
  756. if (description==null || description.equals ("")){
  757. throw new BuildException
  758. ("No description specified for custom tag "+name);
  759. }
  760. return name+":"+(enabled ? "" : "X")+scope+":"+description;
  761. }
  762. }
  763. public GroupArgument createGroup() {
  764. GroupArgument ga = new GroupArgument();
  765. groups.addElement(ga);
  766. return ga;
  767. }
  768. public class GroupArgument {
  769. private Html title;
  770. private Vector packages = new Vector(3);
  771. public GroupArgument() {
  772. }
  773. public void setTitle(String src) {
  774. Html h = new Html();
  775. h.addText(src);
  776. addTitle(h);
  777. }
  778. public void addTitle(Html text) {
  779. title = text;
  780. }
  781. public String getTitle() {
  782. return title != null ? title.getText() : null;
  783. }
  784. public void setPackages(String src) {
  785. StringTokenizer tok = new StringTokenizer(src, ",");
  786. while (tok.hasMoreTokens()) {
  787. String p = tok.nextToken();
  788. PackageName pn = new PackageName();
  789. pn.setName(p);
  790. addPackage(pn);
  791. }
  792. }
  793. public void addPackage(PackageName pn) {
  794. packages.addElement(pn);
  795. }
  796. public String getPackages() {
  797. StringBuffer p = new StringBuffer();
  798. for (int i = 0; i < packages.size(); i++) {
  799. if ( i > 0 ) {
  800. p.append( ":" );
  801. }
  802. p.append( packages.elementAt(i).toString() );
  803. }
  804. return p.toString();
  805. }
  806. }
  807. public void setCharset(String src) {
  808. this.add12ArgIfNotEmpty("-charset", src);
  809. }
  810. /**
  811. * Should the build process fail if javadoc fails (as indicated by
  812. * a non zero return code)?
  813. *
  814. * <p>Default is false.</p>
  815. */
  816. public void setFailonerror(boolean b) {
  817. failOnError = b;
  818. }
  819. public void execute() throws BuildException {
  820. if ("javadoc2".equals(taskType)) {
  821. log("!! javadoc2 is deprecated. Use javadoc instead. !!");
  822. }
  823. if (sourcePath == null) {
  824. String msg = "sourcePath attribute must be set!";
  825. throw new BuildException(msg);
  826. }
  827. log("Generating Javadoc", Project.MSG_INFO);
  828. if (doctitle != null) {
  829. cmd.createArgument().setValue("-doctitle");
  830. cmd.createArgument().setValue(expand(doctitle.getText()));
  831. }
  832. if (header != null) {
  833. cmd.createArgument().setValue("-header");
  834. cmd.createArgument().setValue(expand(header.getText()));
  835. }
  836. if (footer != null) {
  837. cmd.createArgument().setValue("-footer");
  838. cmd.createArgument().setValue(expand(footer.getText()));
  839. }
  840. if (bottom != null) {
  841. cmd.createArgument().setValue("-bottom");
  842. cmd.createArgument().setValue(expand(bottom.getText()));
  843. }
  844. Commandline toExecute = (Commandline)cmd.clone();
  845. toExecute.setExecutable(JavaEnvUtils.getJdkExecutable("javadoc"));
  846. // ------------------------------------------------ general javadoc arguments
  847. if (classpath == null) {
  848. classpath = Path.systemClasspath;
  849. } else {
  850. classpath = classpath.concatSystemClasspath("ignore");
  851. }
  852. if (!javadoc1) {
  853. toExecute.createArgument().setValue("-classpath");
  854. toExecute.createArgument().setPath(classpath);
  855. toExecute.createArgument().setValue("-sourcepath");
  856. toExecute.createArgument().setPath(sourcePath);
  857. } else {
  858. toExecute.createArgument().setValue("-classpath");
  859. toExecute.createArgument().setValue(sourcePath.toString() +
  860. System.getProperty("path.separator") + classpath.toString());
  861. }
  862. if (version && doclet == null) {
  863. toExecute.createArgument().setValue("-version");
  864. }
  865. if (author && doclet == null) {
  866. toExecute.createArgument().setValue("-author");
  867. }
  868. if (javadoc1 || doclet == null) {
  869. if (destDir == null) {
  870. String msg = "destDir attribute must be set!";
  871. throw new BuildException(msg);
  872. }
  873. }
  874. // --------------------------------- javadoc2 arguments for default doclet
  875. // XXX: how do we handle a custom doclet?
  876. if (!javadoc1) {
  877. if (doclet != null) {
  878. if (doclet.getName() == null) {
  879. throw new BuildException("The doclet name must be specified.", location);
  880. }
  881. else {
  882. toExecute.createArgument().setValue("-doclet");
  883. toExecute.createArgument().setValue(doclet.getName());
  884. if (doclet.getPath() != null) {
  885. Path docletPath
  886. = doclet.getPath().concatSystemClasspath("ignore");
  887. if (docletPath.size() != 0) {
  888. toExecute.createArgument().setValue("-docletpath");
  889. toExecute.createArgument().setPath(docletPath);
  890. }
  891. }
  892. for (Enumeration e = doclet.getParams(); e.hasMoreElements();) {
  893. DocletParam param = (DocletParam)e.nextElement();
  894. if (param.getName() == null) {
  895. throw new BuildException("Doclet parameters must have a name");
  896. }
  897. toExecute.createArgument().setValue(param.getName());
  898. if (param.getValue() != null) {
  899. toExecute.createArgument().setValue(param.getValue());
  900. }
  901. }
  902. }
  903. }
  904. if (bootclasspath != null) {
  905. toExecute.createArgument().setValue("-bootclasspath");
  906. toExecute.createArgument().setPath(bootclasspath);
  907. }
  908. // add the links arguments
  909. if (links.size() != 0) {
  910. for (Enumeration e = links.elements(); e.hasMoreElements(); ) {
  911. LinkArgument la = (LinkArgument)e.nextElement();
  912. if (la.getHref() == null) {
  913. throw new BuildException("Links must provide the URL to the external class documentation.");
  914. }
  915. if (la.isLinkOffline()) {
  916. File packageListLocation = la.getPackagelistLoc();
  917. if (packageListLocation == null) {
  918. throw new BuildException("The package list location for link " + la.getHref() +
  919. " must be provided because the link is offline");
  920. }
  921. File packageList = new File(packageListLocation, "package-list");
  922. if (packageList.exists()) {
  923. toExecute.createArgument().setValue("-linkoffline");
  924. toExecute.createArgument().setValue(la.getHref());
  925. toExecute.createArgument().setValue(packageListLocation.getAbsolutePath());
  926. }
  927. else {
  928. log("Warning: No package list was found at " + packageListLocation,
  929. Project.MSG_VERBOSE);
  930. }
  931. }
  932. else {
  933. toExecute.createArgument().setValue("-link");
  934. toExecute.createArgument().setValue(la.getHref());
  935. }
  936. }
  937. }
  938. // add the single group arguments
  939. // Javadoc 1.2 rules:
  940. // Multiple -group args allowed.
  941. // Each arg includes 3 strings: -group [name] [packagelist].
  942. // Elements in [packagelist] are colon-delimited.
  943. // An element in [packagelist] may end with the * wildcard.
  944. // Ant javadoc task rules for group attribute:
  945. // Args are comma-delimited.
  946. // Each arg is 2 space-delimited strings.
  947. // E.g., group="XSLT_Packages org.apache.xalan.xslt*,XPath_Packages org.apache.xalan.xpath*"
  948. if (group != null) {
  949. StringTokenizer tok = new StringTokenizer(group, ",", false);
  950. while (tok.hasMoreTokens()) {
  951. String grp = tok.nextToken().trim();
  952. int space = grp.indexOf(" ");
  953. if (space > 0){
  954. String name = grp.substring(0, space);
  955. String pkgList = grp.substring(space + 1);
  956. toExecute.createArgument().setValue("-group");
  957. toExecute.createArgument().setValue(name);
  958. toExecute.createArgument().setValue(pkgList);
  959. }
  960. }
  961. }
  962. // add the group arguments
  963. if (groups.size() != 0) {
  964. for (Enumeration e = groups.elements(); e.hasMoreElements(); ) {
  965. GroupArgument ga = (GroupArgument)e.nextElement();
  966. String title = ga.getTitle();
  967. String packages = ga.getPackages();
  968. if (title == null || packages == null) {
  969. throw new BuildException("The title and packages must be specified for group elements.");
  970. }
  971. toExecute.createArgument().setValue("-group");
  972. toExecute.createArgument().setValue(expand(title));
  973. toExecute.createArgument().setValue(packages);
  974. }
  975. }
  976. // JavaDoc 1.4 parameters
  977. if (javadoc4) {
  978. for (Enumeration e = taglets.elements(); e.hasMoreElements(); ) {
  979. ExtensionInfo tagletInfo
  980. = (ExtensionInfo) e.nextElement();
  981. toExecute.createArgument().setValue("-taglet");
  982. toExecute.createArgument().setValue(tagletInfo.getName());
  983. if (tagletInfo.getPath() != null) {
  984. System.out.println("Taglet base path is " + tagletInfo.getPath());
  985. Path tagletPath
  986. = tagletInfo.getPath().concatSystemClasspath("ignore");
  987. if (tagletPath.size() != 0) {
  988. toExecute.createArgument().setValue("-tagletpath");
  989. toExecute.createArgument().setPath(tagletPath);
  990. }
  991. }
  992. }
  993. for (Enumeration e = tags.elements(); e.hasMoreElements(); ) {
  994. TagArgument ta = (TagArgument) e.nextElement();
  995. toExecute.createArgument().setValue ("-tag");
  996. toExecute.createArgument().setValue (ta.getParameter());
  997. }
  998. }
  999. }
  1000. tmpList = null;
  1001. if (packageNames.size() > 0) {
  1002. Vector packages = new Vector();
  1003. Enumeration enum = packageNames.elements();
  1004. while (enum.hasMoreElements()) {
  1005. PackageName pn = (PackageName) enum.nextElement();
  1006. String name = pn.getName().trim();
  1007. if (name.endsWith(".*")) {
  1008. packages.addElement(name);
  1009. } else {
  1010. toExecute.createArgument().setValue(name);
  1011. }
  1012. }
  1013. Vector excludePackages = new Vector();
  1014. if (excludePackageNames.size() > 0) {
  1015. enum = excludePackageNames.elements();
  1016. while (enum.hasMoreElements()) {
  1017. PackageName pn = (PackageName) enum.nextElement();
  1018. excludePackages.addElement(pn.getName().trim());
  1019. }
  1020. }
  1021. if (packages.size() > 0) {
  1022. evaluatePackages(toExecute, sourcePath, packages, excludePackages);
  1023. }
  1024. }
  1025. if (sourceFiles.size() > 0) {
  1026. PrintWriter srcListWriter = null;
  1027. try {
  1028. /**
  1029. * Write sourcefiles to a temporary file if requested.
  1030. */
  1031. if (useExternalFile) {
  1032. if (tmpList == null) {
  1033. tmpList = fileUtils.createTempFile("javadoc", "", null);
  1034. toExecute.createArgument().setValue("@" + tmpList.getAbsolutePath());
  1035. }
  1036. srcListWriter = new PrintWriter(new FileWriter(tmpList.getAbsolutePath(),
  1037. true));
  1038. }
  1039. Enumeration enum = sourceFiles.elements();
  1040. while (enum.hasMoreElements()) {
  1041. SourceFile sf = (SourceFile) enum.nextElement();
  1042. String sourceFileName = sf.getFile().getAbsolutePath();
  1043. if (useExternalFile) {
  1044. srcListWriter.println(sourceFileName);
  1045. } else {
  1046. toExecute.createArgument().setValue(sourceFileName);
  1047. }
  1048. }
  1049. } catch (IOException e) {
  1050. throw new BuildException("Error creating temporary file",
  1051. e, location);
  1052. } finally {
  1053. if (srcListWriter != null) {
  1054. srcListWriter.close();
  1055. }
  1056. }
  1057. }
  1058. if (packageList != null) {
  1059. toExecute.createArgument().setValue("@" + packageList);
  1060. }
  1061. log("Javadoc args: " + toExecute, Project.MSG_VERBOSE);
  1062. log("Javadoc execution", Project.MSG_INFO);
  1063. JavadocOutputStream out = new JavadocOutputStream(Project.MSG_INFO);
  1064. JavadocOutputStream err = new JavadocOutputStream(Project.MSG_WARN);
  1065. Execute exe = new Execute(new PumpStreamHandler(out, err));
  1066. exe.setAntRun(project);
  1067. /*
  1068. * No reason to change the working directory as all filenames and
  1069. * path components have been resolved already.
  1070. *
  1071. * Avoid problems with command line length in some environments.
  1072. */
  1073. exe.setWorkingDirectory(null);
  1074. try {
  1075. exe.setCommandline(toExecute.getCommandline());
  1076. int ret = exe.execute();
  1077. if (ret != 0 && failOnError) {
  1078. throw new BuildException("Javadoc returned "+ret, location);
  1079. }
  1080. } catch (IOException e) {
  1081. throw new BuildException("Javadoc failed: " + e, e, location);
  1082. } finally {
  1083. if (tmpList != null) {
  1084. tmpList.delete();
  1085. tmpList = null;
  1086. }
  1087. out.logFlush();
  1088. err.logFlush();
  1089. try {
  1090. out.close();
  1091. err.close();
  1092. } catch (IOException e) {}
  1093. }
  1094. }
  1095. /**
  1096. * Given a source path, a list of package patterns, fill the given list
  1097. * with the packages found in that path subdirs matching one of the given
  1098. * patterns.
  1099. */
  1100. private void evaluatePackages(Commandline toExecute, Path sourcePath,
  1101. Vector packages, Vector excludePackages) {
  1102. log("Source path = " + sourcePath.toString(), Project.MSG_VERBOSE);
  1103. StringBuffer msg = new StringBuffer("Packages = ");
  1104. for (int i=0; i<packages.size(); i++) {
  1105. if (i > 0) {
  1106. msg.append(",");
  1107. }
  1108. msg.append(packages.elementAt(i));
  1109. }
  1110. log(msg.toString(), Project.MSG_VERBOSE);
  1111. msg.setLength(0);
  1112. msg.append("Exclude Packages = ");
  1113. for (int i=0; i<excludePackages.size(); i++) {
  1114. if (i > 0) {
  1115. msg.append(",");
  1116. }
  1117. msg.append(excludePackages.elementAt(i));
  1118. }
  1119. log(msg.toString(), Project.MSG_VERBOSE);
  1120. Vector addedPackages = new Vector();
  1121. String[] list = sourcePath.list();
  1122. if (list == null) {
  1123. list = new String[0];
  1124. }
  1125. FileSet fs = new FileSet();
  1126. fs.setDefaultexcludes(useDefaultExcludes);
  1127. Enumeration e = packages.elements();
  1128. while (e.hasMoreElements()) {
  1129. String pkg = (String)e.nextElement();
  1130. pkg = pkg.replace('.','/');
  1131. if (pkg.endsWith("*")) {
  1132. pkg += "*";
  1133. }
  1134. fs.createInclude().setName(pkg);
  1135. } // while
  1136. e = excludePackages.elements();
  1137. while (e.hasMoreElements()) {
  1138. String pkg = (String)e.nextElement();
  1139. pkg = pkg.replace('.','/');
  1140. if (pkg.endsWith("*")) {
  1141. pkg += "*";
  1142. }
  1143. fs.createExclude().setName(pkg);
  1144. }
  1145. PrintWriter packageListWriter = null;
  1146. try {
  1147. if (useExternalFile) {
  1148. tmpList = fileUtils.createTempFile("javadoc", "", null);
  1149. toExecute.createArgument().setValue("@" + tmpList.getAbsolutePath());
  1150. packageListWriter = new PrintWriter(new FileWriter(tmpList));
  1151. }
  1152. for (int j=0; j<list.length; j++) {
  1153. File source = project.resolveFile(list[j]);
  1154. fs.setDir(source);
  1155. DirectoryScanner ds = fs.getDirectoryScanner(project);
  1156. String[] packageDirs = ds.getIncludedDirectories();
  1157. for (int i=0; i<packageDirs.length; i++) {
  1158. File pd = new File(source, packageDirs[i]);
  1159. String[] files = pd.list(new FilenameFilter () {
  1160. public boolean accept(File dir1, String name) {
  1161. if (name.endsWith(".java")) {
  1162. return true;
  1163. }
  1164. return false; // ignore dirs
  1165. }
  1166. });
  1167. if (files.length > 0) {
  1168. String pkgDir = packageDirs[i].replace('/','.').replace('\\','.');
  1169. if (!addedPackages.contains(pkgDir)) {
  1170. if (useExternalFile) {
  1171. packageListWriter.println(pkgDir);
  1172. } else {
  1173. toExecute.createArgument().setValue(pkgDir);
  1174. }
  1175. addedPackages.addElement(pkgDir);
  1176. }
  1177. }
  1178. }
  1179. }
  1180. } catch (IOException ioex) {
  1181. throw new BuildException("Error creating temporary file",
  1182. ioex, location);
  1183. } finally {
  1184. if (packageListWriter != null) {
  1185. packageListWriter.close();
  1186. }
  1187. }
  1188. }
  1189. private class JavadocOutputStream extends LogOutputStream {
  1190. JavadocOutputStream(int level) {
  1191. super(Javadoc.this, level);
  1192. }
  1193. //
  1194. // Override the logging of output in order to filter out Generating
  1195. // messages. Generating messages are set to a priority of VERBOSE
  1196. // unless they appear after what could be an informational message.
  1197. //
  1198. private String queuedLine = null;
  1199. protected void processLine(String line, int messageLevel) {
  1200. if (messageLevel == Project.MSG_INFO && line.startsWith("Generating ")) {
  1201. if (queuedLine != null) {
  1202. super.processLine(queuedLine, Project.MSG_VERBOSE);
  1203. }
  1204. queuedLine = line;
  1205. } else {
  1206. if (queuedLine != null) {
  1207. if (line.startsWith("Building ")) {
  1208. super.processLine(queuedLine, Project.MSG_VERBOSE);
  1209. } else {
  1210. super.processLine(queuedLine, Project.MSG_INFO);
  1211. }
  1212. queuedLine = null;
  1213. }
  1214. super.processLine(line, messageLevel);
  1215. }
  1216. }
  1217. protected void logFlush() {
  1218. if (queuedLine != null) {
  1219. super.processLine(queuedLine, Project.MSG_VERBOSE);
  1220. queuedLine = null;
  1221. }
  1222. }
  1223. }
  1224. /**
  1225. * Convenience method to expand properties.
  1226. */
  1227. protected String expand(String content) {
  1228. return project.replaceProperties(content);
  1229. }
  1230. }