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 83 kB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
11 years ago
11 years ago
11 years ago
11 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
11 years ago
11 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
11 years ago
11 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
7 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package org.apache.tools.ant.taskdefs;
  19. import java.io.BufferedReader;
  20. import java.io.BufferedWriter;
  21. import java.io.File;
  22. import java.io.FileNotFoundException;
  23. import java.io.FileReader;
  24. import java.io.FileWriter;
  25. import java.io.IOException;
  26. import java.io.InputStream;
  27. import java.io.InputStreamReader;
  28. import java.io.OutputStreamWriter;
  29. import java.net.MalformedURLException;
  30. import java.net.URL;
  31. import java.nio.file.Files;
  32. import java.util.ArrayList;
  33. import java.util.Collections;
  34. import java.util.Enumeration;
  35. import java.util.HashSet;
  36. import java.util.Iterator;
  37. import java.util.List;
  38. import java.util.Locale;
  39. import java.util.Set;
  40. import java.util.StringTokenizer;
  41. import java.util.Vector;
  42. import java.util.stream.Collectors;
  43. import org.apache.tools.ant.BuildException;
  44. import org.apache.tools.ant.DirectoryScanner;
  45. import org.apache.tools.ant.MagicNames;
  46. import org.apache.tools.ant.Project;
  47. import org.apache.tools.ant.ProjectComponent;
  48. import org.apache.tools.ant.Task;
  49. import org.apache.tools.ant.types.Commandline;
  50. import org.apache.tools.ant.types.DirSet;
  51. import org.apache.tools.ant.types.EnumeratedAttribute;
  52. import org.apache.tools.ant.types.FileSet;
  53. import org.apache.tools.ant.types.Path;
  54. import org.apache.tools.ant.types.PatternSet;
  55. import org.apache.tools.ant.types.Reference;
  56. import org.apache.tools.ant.types.Resource;
  57. import org.apache.tools.ant.types.ResourceCollection;
  58. import org.apache.tools.ant.types.resources.FileProvider;
  59. import org.apache.tools.ant.util.FileUtils;
  60. import org.apache.tools.ant.util.JavaEnvUtils;
  61. /**
  62. * Generates Javadoc documentation for a collection
  63. * of source code.
  64. *
  65. * <p>Current known limitations are:</p>
  66. *
  67. * <ul>
  68. * <li>patterns must be of the form "xxx.*", every other pattern doesn't
  69. * work.
  70. * <li>there is no control on arguments sanity since they are left
  71. * to the Javadoc implementation.
  72. * </ul>
  73. *
  74. * <p>If no <code>doclet</code> is set, then the <code>version</code> and
  75. * <code>author</code> are by default <code>"yes"</code>.</p>
  76. *
  77. * <p>Note: This task is run on another VM because the Javadoc code calls
  78. * <code>System.exit()</code> which would break Ant functionality.</p>
  79. *
  80. * @since Ant 1.1
  81. *
  82. * @ant.task category="java"
  83. */
  84. public class Javadoc extends Task {
  85. // Whether *this VM* is 1.4+ (but also check executable != null).
  86. private static final boolean JAVADOC_5 =
  87. !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_4);
  88. private static final String LOAD_FRAME = "function loadFrames() {";
  89. private static final int LOAD_FRAME_LEN = LOAD_FRAME.length();
  90. /**
  91. * Inner class used to manage doclet parameters.
  92. */
  93. public class DocletParam {
  94. /** The parameter name */
  95. private String name;
  96. /** The parameter value */
  97. private String value;
  98. /**
  99. * Set the name of the parameter.
  100. *
  101. * @param name the name of the doclet parameter
  102. */
  103. public void setName(final String name) {
  104. this.name = name;
  105. }
  106. /**
  107. * Get the parameter name.
  108. *
  109. * @return the parameter's name.
  110. */
  111. public String getName() {
  112. return name;
  113. }
  114. /**
  115. * Set the parameter value.
  116. *
  117. * Note that only string values are supported. No resolution of file
  118. * paths is performed.
  119. *
  120. * @param value the parameter value.
  121. */
  122. public void setValue(final String value) {
  123. this.value = value;
  124. }
  125. /**
  126. * Get the parameter value.
  127. *
  128. * @return the parameter value.
  129. */
  130. public String getValue() {
  131. return value;
  132. }
  133. }
  134. /**
  135. * A project aware class used for Javadoc extensions which take a name
  136. * and a path such as doclet and taglet arguments.
  137. *
  138. */
  139. public static class ExtensionInfo extends ProjectComponent {
  140. /** The name of the extension */
  141. private String name;
  142. /** The optional path to use to load the extension */
  143. private Path path;
  144. /**
  145. * Set the name of the extension
  146. *
  147. * @param name the extension's name.
  148. */
  149. public void setName(final String name) {
  150. this.name = name;
  151. }
  152. /**
  153. * Get the name of the extension.
  154. *
  155. * @return the extension's name.
  156. */
  157. public String getName() {
  158. return name;
  159. }
  160. /**
  161. * Set the path to use when loading the component.
  162. *
  163. * @param path a Path instance containing the classpath to use.
  164. */
  165. public void setPath(final Path path) {
  166. if (this.path == null) {
  167. this.path = path;
  168. } else {
  169. this.path.append(path);
  170. }
  171. }
  172. /**
  173. * Get the extension's path.
  174. *
  175. * @return the path to be used to load the extension.
  176. * May be <code>null</code>
  177. */
  178. public Path getPath() {
  179. return path;
  180. }
  181. /**
  182. * Create an empty nested path to be configured by Ant with the
  183. * classpath for the extension.
  184. *
  185. * @return a new Path instance to be configured.
  186. */
  187. public Path createPath() {
  188. if (path == null) {
  189. path = new Path(getProject());
  190. }
  191. return path.createPath();
  192. }
  193. /**
  194. * Adds a reference to a CLASSPATH defined elsewhere.
  195. *
  196. * @param r the reference containing the path.
  197. */
  198. public void setPathRef(final Reference r) {
  199. createPath().setRefid(r);
  200. }
  201. }
  202. /**
  203. * This class stores info about doclets.
  204. *
  205. */
  206. public class DocletInfo extends ExtensionInfo {
  207. /** Collection of doclet parameters. */
  208. private final List<DocletParam> params = new Vector<>();
  209. /**
  210. * Create a doclet parameter to be configured by Ant.
  211. *
  212. * @return a new DocletParam instance to be configured.
  213. */
  214. public DocletParam createParam() {
  215. final DocletParam param = new DocletParam();
  216. params.add(param);
  217. return param;
  218. }
  219. /**
  220. * Get the doclet's parameters.
  221. *
  222. * @return an Enumeration of DocletParam instances.
  223. */
  224. public Enumeration<DocletParam> getParams() {
  225. return Collections.enumeration(params);
  226. }
  227. }
  228. /**
  229. * Used to track info about the packages to be javadoc'd
  230. */
  231. public static class PackageName {
  232. /** The package name */
  233. private String name;
  234. /**
  235. * Set the name of the package
  236. *
  237. * @param name the package name.
  238. */
  239. public void setName(final String name) {
  240. this.name = name.trim();
  241. }
  242. /**
  243. * Get the package name.
  244. *
  245. * @return the package's name.
  246. */
  247. public String getName() {
  248. return name;
  249. }
  250. /**
  251. * Return a string rep for this object.
  252. * @return the package name.
  253. */
  254. @Override
  255. public String toString() {
  256. return getName();
  257. }
  258. }
  259. /**
  260. * This class is used to manage the source files to be processed.
  261. */
  262. public static class SourceFile {
  263. /** The source file */
  264. private File file;
  265. /**
  266. * Default constructor
  267. */
  268. public SourceFile() {
  269. //empty
  270. }
  271. /**
  272. * Constructor specifying the source file directly
  273. *
  274. * @param file the source file
  275. */
  276. public SourceFile(final File file) {
  277. this.file = file;
  278. }
  279. /**
  280. * Set the source file.
  281. *
  282. * @param file the source file.
  283. */
  284. public void setFile(final File file) {
  285. this.file = file;
  286. }
  287. /**
  288. * Get the source file.
  289. *
  290. * @return the source file.
  291. */
  292. public File getFile() {
  293. return file;
  294. }
  295. }
  296. /**
  297. * An HTML element in the Javadoc.
  298. *
  299. * This class is used for those Javadoc elements which contain HTML such as
  300. * footers, headers, etc.
  301. */
  302. public static class Html {
  303. /** The text for the element */
  304. private final StringBuffer text = new StringBuffer();
  305. /**
  306. * Add text to the element.
  307. *
  308. * @param t the text to be added.
  309. */
  310. public void addText(final String t) {
  311. text.append(t);
  312. }
  313. /**
  314. * Get the current text for the element.
  315. *
  316. * @return the current text.
  317. */
  318. public String getText() {
  319. return text.substring(0);
  320. }
  321. }
  322. /**
  323. * EnumeratedAttribute implementation supporting the Javadoc scoping
  324. * values.
  325. */
  326. public static class AccessType extends EnumeratedAttribute {
  327. /**
  328. * @return the allowed values for the access type.
  329. */
  330. @Override
  331. public String[] getValues() {
  332. // Protected first so if any GUI tool offers a default
  333. // based on enum #0, it will be right.
  334. return new String[] {"protected", "public", "package", "private"};
  335. }
  336. }
  337. /**
  338. * Holds a collection of ResourceCollections.
  339. *
  340. * <p>A separate kind of container is needed since this task
  341. * contains special handling for FileSets that has to occur at
  342. * task runtime.</p>
  343. */
  344. public class ResourceCollectionContainer
  345. implements Iterable<ResourceCollection> {
  346. private final List<ResourceCollection> rcs = new ArrayList<>();
  347. /**
  348. * Add a resource collection to the container.
  349. * @param rc the collection to add.
  350. */
  351. public void add(final ResourceCollection rc) {
  352. rcs.add(rc);
  353. }
  354. /**
  355. * Get an iterator on the collection.
  356. * @return an iterator.
  357. */
  358. @Override
  359. public Iterator<ResourceCollection> iterator() {
  360. return rcs.iterator();
  361. }
  362. }
  363. private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
  364. /** The command line built to execute Javadoc. */
  365. private final Commandline cmd = new Commandline();
  366. /**
  367. * Utility method to add an argument to the command line conditionally
  368. * based on the given flag.
  369. *
  370. * @param b the flag which controls if the argument is added.
  371. * @param arg the argument value.
  372. */
  373. private void addArgIf(final boolean b, final String arg) {
  374. if (b) {
  375. cmd.createArgument().setValue(arg);
  376. }
  377. }
  378. /**
  379. * Utility method to add a Javadoc argument.
  380. *
  381. * @param key the argument name.
  382. * @param value the argument value.
  383. */
  384. private void addArgIfNotEmpty(final String key, final String value) {
  385. if (value == null || value.isEmpty()) {
  386. log("Warning: Leaving out empty argument '" + key + "'",
  387. Project.MSG_WARN);
  388. } else {
  389. cmd.createArgument().setValue(key);
  390. cmd.createArgument().setValue(value);
  391. }
  392. }
  393. /**
  394. * Flag which indicates if the task should fail if there is a
  395. * Javadoc error.
  396. */
  397. private boolean failOnError = false;
  398. /**
  399. * Flag which indicates if the task should fail if there is a
  400. * Javadoc warning.
  401. */
  402. private boolean failOnWarning = false;
  403. private Path sourcePath = null;
  404. private File destDir = null;
  405. private final List<SourceFile> sourceFiles = new Vector<>();
  406. private final List<PackageName> packageNames = new Vector<>();
  407. private final List<PackageName> excludePackageNames = new Vector<>(1);
  408. private boolean author = true;
  409. private boolean version = true;
  410. private DocletInfo doclet = null;
  411. private Path classpath = null;
  412. private Path bootclasspath = null;
  413. private String group = null;
  414. private String packageList = null;
  415. private final List<LinkArgument> links = new Vector<>();
  416. private final List<GroupArgument> groups = new Vector<>();
  417. private final List<Object> tags = new Vector<>();
  418. private boolean useDefaultExcludes = true;
  419. private Html doctitle = null;
  420. private Html header = null;
  421. private Html footer = null;
  422. private Html bottom = null;
  423. private boolean useExternalFile = false;
  424. private String source = null;
  425. private boolean linksource = false;
  426. private boolean breakiterator = false;
  427. private String noqualifier;
  428. private boolean includeNoSourcePackages = false;
  429. private String executable = null;
  430. private boolean docFilesSubDirs = false;
  431. private String excludeDocFilesSubDir = null;
  432. private String docEncoding = null;
  433. private boolean postProcessGeneratedJavadocs = true;
  434. private final ResourceCollectionContainer nestedSourceFiles
  435. = new ResourceCollectionContainer();
  436. private final List<DirSet> packageSets = new Vector<>();
  437. /**
  438. * Work around command line length limit by using an external file
  439. * for the sourcefiles.
  440. *
  441. * @param b true if an external file is to be used.
  442. */
  443. public void setUseExternalFile(final boolean b) {
  444. useExternalFile = b;
  445. }
  446. /**
  447. * Sets whether default exclusions should be used or not.
  448. *
  449. * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
  450. * should be used, "false"|"off"|"no" when they
  451. * shouldn't be used.
  452. */
  453. public void setDefaultexcludes(final boolean useDefaultExcludes) {
  454. this.useDefaultExcludes = useDefaultExcludes;
  455. }
  456. /**
  457. * Set the maximum memory to be used by the javadoc process
  458. *
  459. * @param max a string indicating the maximum memory according to the
  460. * JVM conventions (e.g. 128m is 128 Megabytes)
  461. */
  462. public void setMaxmemory(final String max) {
  463. cmd.createArgument().setValue("-J-Xmx" + max);
  464. }
  465. /**
  466. * Set an additional parameter on the command line
  467. *
  468. * @param add the additional command line parameter for the javadoc task.
  469. */
  470. public void setAdditionalparam(final String add) {
  471. cmd.createArgument().setLine(add);
  472. }
  473. /**
  474. * Adds a command-line argument.
  475. * @return a command-line argument to configure
  476. * @since Ant 1.6
  477. */
  478. public Commandline.Argument createArg() {
  479. return cmd.createArgument();
  480. }
  481. /**
  482. * Specify where to find source file
  483. *
  484. * @param src a Path instance containing the various source directories.
  485. */
  486. public void setSourcepath(final Path src) {
  487. if (sourcePath == null) {
  488. sourcePath = src;
  489. } else {
  490. sourcePath.append(src);
  491. }
  492. }
  493. /**
  494. * Create a path to be configured with the locations of the source
  495. * files.
  496. *
  497. * @return a new Path instance to be configured by the Ant core.
  498. */
  499. public Path createSourcepath() {
  500. if (sourcePath == null) {
  501. sourcePath = new Path(getProject());
  502. }
  503. return sourcePath.createPath();
  504. }
  505. /**
  506. * Adds a reference to a CLASSPATH defined elsewhere.
  507. *
  508. * @param r the reference containing the source path definition.
  509. */
  510. public void setSourcepathRef(final Reference r) {
  511. createSourcepath().setRefid(r);
  512. }
  513. /**
  514. * Set the directory where the Javadoc output will be generated.
  515. *
  516. * @param dir the destination directory.
  517. */
  518. public void setDestdir(final File dir) {
  519. destDir = dir;
  520. cmd.createArgument().setValue("-d");
  521. cmd.createArgument().setFile(destDir);
  522. }
  523. /**
  524. * Set the list of source files to process.
  525. *
  526. * @param src a comma separated list of source files.
  527. */
  528. public void setSourcefiles(final String src) {
  529. final StringTokenizer tok = new StringTokenizer(src, ",");
  530. while (tok.hasMoreTokens()) {
  531. final String f = tok.nextToken();
  532. final SourceFile sf = new SourceFile();
  533. sf.setFile(getProject().resolveFile(f.trim()));
  534. addSource(sf);
  535. }
  536. }
  537. /**
  538. * Add a single source file.
  539. *
  540. * @param sf the source file to be processed.
  541. */
  542. public void addSource(final SourceFile sf) {
  543. sourceFiles.add(sf);
  544. }
  545. /**
  546. * Set the package names to be processed.
  547. *
  548. * @param packages a comma separated list of packages specs
  549. * (may be wildcarded).
  550. *
  551. * @see #addPackage for wildcard information.
  552. */
  553. public void setPackagenames(final String packages) {
  554. final StringTokenizer tok = new StringTokenizer(packages, ",");
  555. while (tok.hasMoreTokens()) {
  556. final String p = tok.nextToken();
  557. final PackageName pn = new PackageName();
  558. pn.setName(p);
  559. addPackage(pn);
  560. }
  561. }
  562. /**
  563. * Add a single package to be processed.
  564. *
  565. * If the package name ends with &quot;.*&quot; the Javadoc task
  566. * will find and process all subpackages.
  567. *
  568. * @param pn the package name, possibly wildcarded.
  569. */
  570. public void addPackage(final PackageName pn) {
  571. packageNames.add(pn);
  572. }
  573. /**
  574. * Set the list of packages to be excluded.
  575. *
  576. * @param packages a comma separated list of packages to be excluded.
  577. * This may not include wildcards.
  578. */
  579. public void setExcludePackageNames(final String packages) {
  580. final StringTokenizer tok = new StringTokenizer(packages, ",");
  581. while (tok.hasMoreTokens()) {
  582. final String p = tok.nextToken();
  583. final PackageName pn = new PackageName();
  584. pn.setName(p);
  585. addExcludePackage(pn);
  586. }
  587. }
  588. /**
  589. * Add a package to be excluded from the Javadoc run.
  590. *
  591. * @param pn the name of the package (wildcards are not permitted).
  592. */
  593. public void addExcludePackage(final PackageName pn) {
  594. excludePackageNames.add(pn);
  595. }
  596. /**
  597. * Specify the file containing the overview to be included in the generated
  598. * documentation.
  599. *
  600. * @param f the file containing the overview.
  601. */
  602. public void setOverview(final File f) {
  603. cmd.createArgument().setValue("-overview");
  604. cmd.createArgument().setFile(f);
  605. }
  606. /**
  607. * Indicate whether only public classes and members are to be included in
  608. * the scope processed
  609. *
  610. * @param b true if scope is to be public.
  611. */
  612. public void setPublic(final boolean b) {
  613. addArgIf(b, "-public");
  614. }
  615. /**
  616. * Indicate whether only protected and public classes and members are to
  617. * be included in the scope processed
  618. *
  619. * @param b true if scope is to be protected.
  620. */
  621. public void setProtected(final boolean b) {
  622. addArgIf(b, "-protected");
  623. }
  624. /**
  625. * Indicate whether only package, protected and public classes and
  626. * members are to be included in the scope processed
  627. *
  628. * @param b true if scope is to be package level.
  629. */
  630. public void setPackage(final boolean b) {
  631. addArgIf(b, "-package");
  632. }
  633. /**
  634. * Indicate whether all classes and
  635. * members are to be included in the scope processed
  636. *
  637. * @param b true if scope is to be private level.
  638. */
  639. public void setPrivate(final boolean b) {
  640. addArgIf(b, "-private");
  641. }
  642. /**
  643. * Set the scope to be processed. This is an alternative to the
  644. * use of the setPublic, setPrivate, etc methods. It gives better build
  645. * file control over what scope is processed.
  646. *
  647. * @param at the scope to be processed.
  648. */
  649. public void setAccess(final AccessType at) {
  650. cmd.createArgument().setValue("-" + at.getValue());
  651. }
  652. /**
  653. * Set the class that starts the doclet used in generating the
  654. * documentation.
  655. *
  656. * @param docletName the name of the doclet class.
  657. */
  658. public void setDoclet(final String docletName) {
  659. if (doclet == null) {
  660. doclet = new DocletInfo();
  661. doclet.setProject(getProject());
  662. }
  663. doclet.setName(docletName);
  664. }
  665. /**
  666. * Set the classpath used to find the doclet class.
  667. *
  668. * @param docletPath the doclet classpath.
  669. */
  670. public void setDocletPath(final Path docletPath) {
  671. if (doclet == null) {
  672. doclet = new DocletInfo();
  673. doclet.setProject(getProject());
  674. }
  675. doclet.setPath(docletPath);
  676. }
  677. /**
  678. * Set the classpath used to find the doclet class by reference.
  679. *
  680. * @param r the reference to the Path instance to use as the doclet
  681. * classpath.
  682. */
  683. public void setDocletPathRef(final Reference r) {
  684. if (doclet == null) {
  685. doclet = new DocletInfo();
  686. doclet.setProject(getProject());
  687. }
  688. doclet.createPath().setRefid(r);
  689. }
  690. /**
  691. * Create a doclet to be used in the documentation generation.
  692. *
  693. * @return a new DocletInfo instance to be configured.
  694. */
  695. public DocletInfo createDoclet() {
  696. if (doclet == null) {
  697. doclet = new DocletInfo();
  698. }
  699. return doclet;
  700. }
  701. /**
  702. * Add a taglet
  703. *
  704. * @param tagletInfo information about the taglet.
  705. */
  706. public void addTaglet(final ExtensionInfo tagletInfo) {
  707. tags.add(tagletInfo);
  708. }
  709. /**
  710. * Indicate whether Javadoc should produce old style (JDK 1.1)
  711. * documentation.
  712. *
  713. * This is not supported by JDK 1.1 and has been phased out in JDK 1.4
  714. *
  715. * @param b if true attempt to generate old style documentation.
  716. */
  717. public void setOld(final boolean b) {
  718. log("Javadoc 1.4 doesn't support the -1.1 switch anymore",
  719. Project.MSG_WARN);
  720. }
  721. /**
  722. * Set the classpath to be used for this Javadoc run.
  723. *
  724. * @param path an Ant Path object containing the compilation
  725. * classpath.
  726. */
  727. public void setClasspath(final Path path) {
  728. if (classpath == null) {
  729. classpath = path;
  730. } else {
  731. classpath.append(path);
  732. }
  733. }
  734. /**
  735. * Create a Path to be configured with the classpath to use
  736. *
  737. * @return a new Path instance to be configured with the classpath.
  738. */
  739. public Path createClasspath() {
  740. if (classpath == null) {
  741. classpath = new Path(getProject());
  742. }
  743. return classpath.createPath();
  744. }
  745. /**
  746. * Adds a reference to a CLASSPATH defined elsewhere.
  747. *
  748. * @param r the reference to an instance defining the classpath.
  749. */
  750. public void setClasspathRef(final Reference r) {
  751. createClasspath().setRefid(r);
  752. }
  753. /**
  754. * Set the boot classpath to use.
  755. *
  756. * @param path the boot classpath.
  757. */
  758. public void setBootclasspath(final Path path) {
  759. if (bootclasspath == null) {
  760. bootclasspath = path;
  761. } else {
  762. bootclasspath.append(path);
  763. }
  764. }
  765. /**
  766. * Create a Path to be configured with the boot classpath
  767. *
  768. * @return a new Path instance to be configured with the boot classpath.
  769. */
  770. public Path createBootclasspath() {
  771. if (bootclasspath == null) {
  772. bootclasspath = new Path(getProject());
  773. }
  774. return bootclasspath.createPath();
  775. }
  776. /**
  777. * Adds a reference to a CLASSPATH defined elsewhere.
  778. *
  779. * @param r the reference to an instance defining the bootclasspath.
  780. */
  781. public void setBootClasspathRef(final Reference r) {
  782. createBootclasspath().setRefid(r);
  783. }
  784. /**
  785. * Set the location of the extensions directories.
  786. *
  787. * @param path the string version of the path.
  788. * @deprecated since 1.5.x.
  789. * Use the {@link #setExtdirs(Path)} version.
  790. */
  791. @Deprecated
  792. public void setExtdirs(final String path) {
  793. cmd.createArgument().setValue("-extdirs");
  794. cmd.createArgument().setValue(path);
  795. }
  796. /**
  797. * Set the location of the extensions directories.
  798. *
  799. * @param path a path containing the extension directories.
  800. */
  801. public void setExtdirs(final Path path) {
  802. cmd.createArgument().setValue("-extdirs");
  803. cmd.createArgument().setPath(path);
  804. }
  805. /**
  806. * Run javadoc in verbose mode
  807. *
  808. * @param b true if operation is to be verbose.
  809. */
  810. public void setVerbose(final boolean b) {
  811. addArgIf(b, "-verbose");
  812. }
  813. /**
  814. * Set the local to use in documentation generation.
  815. *
  816. * @param locale the locale to use.
  817. */
  818. public void setLocale(final String locale) {
  819. // createArgument(true) is necessary to make sure -locale
  820. // is the first argument (required in 1.3+).
  821. cmd.createArgument(true).setValue(locale);
  822. cmd.createArgument(true).setValue("-locale");
  823. }
  824. /**
  825. * Set the encoding name of the source files,
  826. *
  827. * @param enc the name of the encoding for the source files.
  828. */
  829. public void setEncoding(final String enc) {
  830. cmd.createArgument().setValue("-encoding");
  831. cmd.createArgument().setValue(enc);
  832. }
  833. /**
  834. * Include the version tag in the generated documentation.
  835. *
  836. * @param b true if the version tag should be included.
  837. */
  838. public void setVersion(final boolean b) {
  839. this.version = b;
  840. }
  841. /**
  842. * Generate the &quot;use&quot; page for each package.
  843. *
  844. * @param b true if the use page should be generated.
  845. */
  846. public void setUse(final boolean b) {
  847. addArgIf(b, "-use");
  848. }
  849. /**
  850. * Include the author tag in the generated documentation.
  851. *
  852. * @param b true if the author tag should be included.
  853. */
  854. public void setAuthor(final boolean b) {
  855. author = b;
  856. }
  857. /**
  858. * Generate a split index
  859. *
  860. * @param b true if the index should be split into a file per letter.
  861. */
  862. public void setSplitindex(final boolean b) {
  863. addArgIf(b, "-splitindex");
  864. }
  865. /**
  866. * Set the title to be placed in the HTML &lt;title&gt; tag of the
  867. * generated documentation.
  868. *
  869. * @param title the window title to use.
  870. */
  871. public void setWindowtitle(final String title) {
  872. addArgIfNotEmpty("-windowtitle", title);
  873. }
  874. /**
  875. * Set the title of the generated overview page.
  876. *
  877. * @param doctitle the Document title.
  878. */
  879. public void setDoctitle(final String doctitle) {
  880. final Html h = new Html();
  881. h.addText(doctitle);
  882. addDoctitle(h);
  883. }
  884. /**
  885. * Add a document title to use for the overview page.
  886. *
  887. * @param text the HTML element containing the document title.
  888. */
  889. public void addDoctitle(final Html text) {
  890. doctitle = text;
  891. }
  892. /**
  893. * Set the header text to be placed at the top of each output file.
  894. *
  895. * @param header the header text
  896. */
  897. public void setHeader(final String header) {
  898. final Html h = new Html();
  899. h.addText(header);
  900. addHeader(h);
  901. }
  902. /**
  903. * Set the header text to be placed at the top of each output file.
  904. *
  905. * @param text the header text
  906. */
  907. public void addHeader(final Html text) {
  908. header = text;
  909. }
  910. /**
  911. * Set the footer text to be placed at the bottom of each output file.
  912. *
  913. * @param footer the footer text.
  914. */
  915. public void setFooter(final String footer) {
  916. final Html h = new Html();
  917. h.addText(footer);
  918. addFooter(h);
  919. }
  920. /**
  921. * Set the footer text to be placed at the bottom of each output file.
  922. *
  923. * @param text the footer text.
  924. */
  925. public void addFooter(final Html text) {
  926. footer = text;
  927. }
  928. /**
  929. * Set the text to be placed at the bottom of each output file.
  930. *
  931. * @param bottom the bottom text.
  932. */
  933. public void setBottom(final String bottom) {
  934. final Html h = new Html();
  935. h.addText(bottom);
  936. addBottom(h);
  937. }
  938. /**
  939. * Set the text to be placed at the bottom of each output file.
  940. *
  941. * @param text the bottom text.
  942. */
  943. public void addBottom(final Html text) {
  944. bottom = text;
  945. }
  946. /**
  947. * Link to docs at "url" using package list at "url2"
  948. * - separate the URLs by using a space character.
  949. *
  950. * @param src the offline link specification (url and package list)
  951. */
  952. public void setLinkoffline(final String src) {
  953. final LinkArgument le = createLink();
  954. le.setOffline(true);
  955. final String linkOfflineError = "The linkoffline attribute must include"
  956. + " a URL and a package-list file location separated by a"
  957. + " space";
  958. if (src.trim().isEmpty()) {
  959. throw new BuildException(linkOfflineError);
  960. }
  961. final StringTokenizer tok = new StringTokenizer(src, " ", false);
  962. le.setHref(tok.nextToken());
  963. if (!tok.hasMoreTokens()) {
  964. throw new BuildException(linkOfflineError);
  965. }
  966. le.setPackagelistLoc(getProject().resolveFile(tok.nextToken()));
  967. }
  968. /**
  969. * Group specified packages together in overview page.
  970. *
  971. * @param src the group packages - a command separated list of group specs,
  972. * each one being a group name and package specification separated
  973. * by a space.
  974. */
  975. public void setGroup(final String src) {
  976. group = src;
  977. }
  978. /**
  979. * Create links to Javadoc output at the given URL.
  980. * @param src the URL to link to
  981. */
  982. public void setLink(final String src) {
  983. createLink().setHref(src);
  984. }
  985. /**
  986. * Control deprecation information
  987. *
  988. * @param b If true, do not include deprecated information.
  989. */
  990. public void setNodeprecated(final boolean b) {
  991. addArgIf(b, "-nodeprecated");
  992. }
  993. /**
  994. * Control deprecated list generation
  995. *
  996. * @param b if true, do not generate deprecated list.
  997. */
  998. public void setNodeprecatedlist(final boolean b) {
  999. addArgIf(b, "-nodeprecatedlist");
  1000. }
  1001. /**
  1002. * Control class tree generation.
  1003. *
  1004. * @param b if true, do not generate class hierarchy.
  1005. */
  1006. public void setNotree(final boolean b) {
  1007. addArgIf(b, "-notree");
  1008. }
  1009. /**
  1010. * Control generation of index.
  1011. *
  1012. * @param b if true, do not generate index.
  1013. */
  1014. public void setNoindex(final boolean b) {
  1015. addArgIf(b, "-noindex");
  1016. }
  1017. /**
  1018. * Control generation of help link.
  1019. *
  1020. * @param b if true, do not generate help link
  1021. */
  1022. public void setNohelp(final boolean b) {
  1023. addArgIf(b, "-nohelp");
  1024. }
  1025. /**
  1026. * Control generation of the navigation bar.
  1027. *
  1028. * @param b if true, do not generate navigation bar.
  1029. */
  1030. public void setNonavbar(final boolean b) {
  1031. addArgIf(b, "-nonavbar");
  1032. }
  1033. /**
  1034. * Control warnings about serial tag.
  1035. *
  1036. * @param b if true, generate warning about the serial tag.
  1037. */
  1038. public void setSerialwarn(final boolean b) {
  1039. addArgIf(b, "-serialwarn");
  1040. }
  1041. /**
  1042. * Specifies the CSS stylesheet file to use.
  1043. *
  1044. * @param f the file with the CSS to use.
  1045. */
  1046. public void setStylesheetfile(final File f) {
  1047. cmd.createArgument().setValue("-stylesheetfile");
  1048. cmd.createArgument().setFile(f);
  1049. }
  1050. /**
  1051. * Specifies the HTML help file to use.
  1052. *
  1053. * @param f the file containing help content.
  1054. */
  1055. public void setHelpfile(final File f) {
  1056. cmd.createArgument().setValue("-helpfile");
  1057. cmd.createArgument().setFile(f);
  1058. }
  1059. /**
  1060. * Output file encoding name.
  1061. *
  1062. * @param enc name of the encoding to use.
  1063. */
  1064. public void setDocencoding(final String enc) {
  1065. cmd.createArgument().setValue("-docencoding");
  1066. cmd.createArgument().setValue(enc);
  1067. docEncoding = enc;
  1068. }
  1069. /**
  1070. * The name of a file containing the packages to process.
  1071. *
  1072. * @param src the file containing the package list.
  1073. */
  1074. public void setPackageList(final String src) {
  1075. packageList = src;
  1076. }
  1077. /**
  1078. * Create link to Javadoc output at the given URL.
  1079. *
  1080. * @return link argument to configure
  1081. */
  1082. public LinkArgument createLink() {
  1083. final LinkArgument la = new LinkArgument();
  1084. links.add(la);
  1085. return la;
  1086. }
  1087. /**
  1088. * Represents a link triplet (href, whether link is offline,
  1089. * location of the package list if off line)
  1090. */
  1091. public class LinkArgument {
  1092. private String href;
  1093. private boolean offline = false;
  1094. private File packagelistLoc;
  1095. private URL packagelistURL;
  1096. private boolean resolveLink = false;
  1097. /** Constructor for LinkArgument */
  1098. public LinkArgument() {
  1099. //empty
  1100. }
  1101. /**
  1102. * Set the href attribute.
  1103. * @param hr a <code>String</code> value
  1104. */
  1105. public void setHref(final String hr) {
  1106. href = hr;
  1107. }
  1108. /**
  1109. * Get the href attribute.
  1110. * @return the href attribute.
  1111. */
  1112. public String getHref() {
  1113. return href;
  1114. }
  1115. /**
  1116. * Set the packetlist location attribute.
  1117. * @param src a <code>File</code> value
  1118. */
  1119. public void setPackagelistLoc(final File src) {
  1120. packagelistLoc = src;
  1121. }
  1122. /**
  1123. * Get the packetList location attribute.
  1124. * @return the packetList location attribute.
  1125. */
  1126. public File getPackagelistLoc() {
  1127. return packagelistLoc;
  1128. }
  1129. /**
  1130. * Set the packetlist location attribute.
  1131. * @param src an <code>URL</code> value
  1132. */
  1133. public void setPackagelistURL(final URL src) {
  1134. packagelistURL = src;
  1135. }
  1136. /**
  1137. * Get the packetList location attribute.
  1138. * @return the packetList location attribute.
  1139. */
  1140. public URL getPackagelistURL() {
  1141. return packagelistURL;
  1142. }
  1143. /**
  1144. * Set the offline attribute.
  1145. * @param offline a <code>boolean</code> value
  1146. */
  1147. public void setOffline(final boolean offline) {
  1148. this.offline = offline;
  1149. }
  1150. /**
  1151. * Get the linkOffline attribute.
  1152. * @return the linkOffline attribute.
  1153. */
  1154. public boolean isLinkOffline() {
  1155. return offline;
  1156. }
  1157. /**
  1158. * Sets whether Ant should resolve the link attribute relative
  1159. * to the current basedir.
  1160. * @param resolve a <code>boolean</code> value
  1161. */
  1162. public void setResolveLink(final boolean resolve) {
  1163. this.resolveLink = resolve;
  1164. }
  1165. /**
  1166. * should Ant resolve the link attribute relative to the
  1167. * current basedir?
  1168. * @return the resolveLink attribute.
  1169. */
  1170. public boolean shouldResolveLink() {
  1171. return resolveLink;
  1172. }
  1173. }
  1174. /**
  1175. * Creates and adds a -tag argument. This is used to specify
  1176. * custom tags. This argument is only available for Javadoc 1.4,
  1177. * and will generate a verbose message (and then be ignored)
  1178. * when run on Java versions below 1.4.
  1179. * @return tag argument to be configured
  1180. */
  1181. public TagArgument createTag() {
  1182. final TagArgument ta = new TagArgument();
  1183. tags.add(ta);
  1184. return ta;
  1185. }
  1186. /**
  1187. * Scope element verbose names. (Defined here as fields
  1188. * cannot be static in inner classes.) The first letter
  1189. * from each element is used to build up the scope string.
  1190. */
  1191. static final String[] SCOPE_ELEMENTS = { //NOSONAR
  1192. "overview", "packages", "types", "constructors",
  1193. "methods", "fields"
  1194. };
  1195. /**
  1196. * Class representing a -tag argument.
  1197. */
  1198. public class TagArgument extends FileSet {
  1199. /** Name of the tag. */
  1200. private String name = null;
  1201. /** Whether or not the tag is enabled. */
  1202. private boolean enabled = true;
  1203. /**
  1204. * Scope string of the tag. This will form the middle
  1205. * argument of the -tag parameter when the tag is enabled
  1206. * (with an X prepended for and is parsed from human-readable form.
  1207. */
  1208. private String scope = "a";
  1209. /** Sole constructor. */
  1210. public TagArgument() {
  1211. //empty
  1212. }
  1213. /**
  1214. * Sets the name of the tag.
  1215. *
  1216. * @param name The name of the tag.
  1217. * Must not be <code>null</code> or empty.
  1218. */
  1219. public void setName(final String name) {
  1220. this.name = name;
  1221. }
  1222. /**
  1223. * Sets the scope of the tag. This is in comma-separated
  1224. * form, with each element being one of "all" (the default),
  1225. * "overview", "packages", "types", "constructors", "methods",
  1226. * "fields". The elements are treated in a case-insensitive
  1227. * manner.
  1228. *
  1229. * @param verboseScope The scope of the tag.
  1230. * Must not be <code>null</code>,
  1231. * should not be empty.
  1232. *
  1233. * @exception BuildException if all is specified along with
  1234. * other elements, if any elements are repeated, if no
  1235. * elements are specified, or if any unrecognised elements are
  1236. * specified.
  1237. */
  1238. public void setScope(String verboseScope) throws BuildException {
  1239. verboseScope = verboseScope.toLowerCase(Locale.ENGLISH);
  1240. final boolean[] elements = new boolean[SCOPE_ELEMENTS.length];
  1241. boolean gotAll = false;
  1242. boolean gotNotAll = false;
  1243. // Go through the tokens one at a time, updating the
  1244. // elements array and issuing warnings where appropriate.
  1245. final StringTokenizer tok = new StringTokenizer(verboseScope, ",");
  1246. while (tok.hasMoreTokens()) {
  1247. final String next = tok.nextToken().trim();
  1248. if ("all".equals(next)) {
  1249. if (gotAll) {
  1250. getProject().log("Repeated tag scope element: all",
  1251. Project.MSG_VERBOSE);
  1252. }
  1253. gotAll = true;
  1254. } else {
  1255. int i;
  1256. for (i = 0; i < SCOPE_ELEMENTS.length; i++) {
  1257. if (SCOPE_ELEMENTS[i].equals(next)) {
  1258. break;
  1259. }
  1260. }
  1261. if (i == SCOPE_ELEMENTS.length) {
  1262. throw new BuildException(
  1263. "Unrecognised scope element: %s", next);
  1264. }
  1265. if (elements[i]) {
  1266. getProject().log("Repeated tag scope element: " + next,
  1267. Project.MSG_VERBOSE);
  1268. }
  1269. elements[i] = true;
  1270. gotNotAll = true;
  1271. }
  1272. }
  1273. if (gotNotAll && gotAll) {
  1274. throw new BuildException(
  1275. "Mixture of \"all\" and other scope elements in tag parameter.");
  1276. }
  1277. if (!gotNotAll && !gotAll) {
  1278. throw new BuildException(
  1279. "No scope elements specified in tag parameter.");
  1280. }
  1281. if (gotAll) {
  1282. this.scope = "a";
  1283. } else {
  1284. final StringBuilder buff = new StringBuilder(elements.length);
  1285. for (int i = 0; i < elements.length; i++) {
  1286. if (elements[i]) {
  1287. buff.append(SCOPE_ELEMENTS[i].charAt(0));
  1288. }
  1289. }
  1290. this.scope = buff.toString();
  1291. }
  1292. }
  1293. /**
  1294. * Sets whether or not the tag is enabled.
  1295. *
  1296. * @param enabled Whether or not this tag is enabled.
  1297. */
  1298. public void setEnabled(final boolean enabled) {
  1299. this.enabled = enabled;
  1300. }
  1301. /**
  1302. * Returns the -tag parameter this argument represented.
  1303. * @return the -tag parameter as a string
  1304. * @exception BuildException if either the name or description
  1305. * is <code>null</code> or empty.
  1306. */
  1307. public String getParameter() throws BuildException {
  1308. if (name == null || name.isEmpty()) {
  1309. throw new BuildException("No name specified for custom tag.");
  1310. }
  1311. if (getDescription() != null) {
  1312. return name + ":" + (enabled ? "" : "X")
  1313. + scope + ":" + getDescription();
  1314. }
  1315. if (!enabled || !"a".equals(scope)) {
  1316. return name + ":" + (enabled ? "" : "X") + scope;
  1317. }
  1318. return name;
  1319. }
  1320. }
  1321. /**
  1322. * Separates packages on the overview page into whatever
  1323. * groups you specify, one group per table.
  1324. * @return a group argument to be configured
  1325. */
  1326. public GroupArgument createGroup() {
  1327. final GroupArgument ga = new GroupArgument();
  1328. groups.add(ga);
  1329. return ga;
  1330. }
  1331. /**
  1332. * A class corresponding to the group nested element.
  1333. */
  1334. public class GroupArgument {
  1335. private Html title;
  1336. private final List<PackageName> packages = new Vector<>();
  1337. /**
  1338. * Set the title attribute using a string.
  1339. * @param src a <code>String</code> value
  1340. */
  1341. public void setTitle(final String src) {
  1342. final Html h = new Html();
  1343. h.addText(src);
  1344. addTitle(h);
  1345. }
  1346. /**
  1347. * Set the title attribute using a nested Html value.
  1348. * @param text a <code>Html</code> value
  1349. */
  1350. public void addTitle(final Html text) {
  1351. title = text;
  1352. }
  1353. /**
  1354. * Get the title.
  1355. * @return the title
  1356. */
  1357. public String getTitle() {
  1358. return title != null ? title.getText() : null;
  1359. }
  1360. /**
  1361. * Set the packages to Javadoc on.
  1362. * @param src a comma separated list of packages
  1363. */
  1364. public void setPackages(final String src) {
  1365. final StringTokenizer tok = new StringTokenizer(src, ",");
  1366. while (tok.hasMoreTokens()) {
  1367. final String p = tok.nextToken();
  1368. final PackageName pn = new PackageName();
  1369. pn.setName(p);
  1370. addPackage(pn);
  1371. }
  1372. }
  1373. /**
  1374. * Add a package nested element.
  1375. * @param pn a nested element specifying the package.
  1376. */
  1377. public void addPackage(final PackageName pn) {
  1378. packages.add(pn);
  1379. }
  1380. /**
  1381. * Get the packages as a colon separated list.
  1382. * @return the packages as a string
  1383. */
  1384. public String getPackages() {
  1385. return packages.stream().map(Object::toString)
  1386. .collect(Collectors.joining(":"));
  1387. }
  1388. }
  1389. /**
  1390. * Charset for cross-platform viewing of generated documentation.
  1391. * @param src the name of the charset
  1392. */
  1393. public void setCharset(final String src) {
  1394. this.addArgIfNotEmpty("-charset", src);
  1395. }
  1396. /**
  1397. * Should the build process fail if Javadoc fails (as indicated by
  1398. * a non zero return code)?
  1399. *
  1400. * <p>Default is false.</p>
  1401. * @param b a <code>boolean</code> value
  1402. */
  1403. public void setFailonerror(final boolean b) {
  1404. failOnError = b;
  1405. }
  1406. /**
  1407. * Should the build process fail if Javadoc warns (as indicated by
  1408. * the word "warning" on stdout)?
  1409. *
  1410. * <p>Default is false.</p>
  1411. * @param b a <code>boolean</code> value
  1412. * @since Ant 1.9.4
  1413. */
  1414. public void setFailonwarning(final boolean b) {
  1415. failOnWarning = b;
  1416. }
  1417. /**
  1418. * Enables the -source switch, will be ignored if Javadoc is not
  1419. * the 1.4 version.
  1420. * @param source a <code>String</code> value
  1421. * @since Ant 1.5
  1422. */
  1423. public void setSource(final String source) {
  1424. this.source = source;
  1425. }
  1426. /**
  1427. * Sets the actual executable command to invoke, instead of the binary
  1428. * <code>javadoc</code> found in Ant's JDK.
  1429. * @param executable the command to invoke.
  1430. * @since Ant 1.6.3
  1431. */
  1432. public void setExecutable(final String executable) {
  1433. this.executable = executable;
  1434. }
  1435. /**
  1436. * Adds a packageset.
  1437. *
  1438. * <p>All included directories will be translated into package
  1439. * names be converting the directory separator into dots.</p>
  1440. * @param packageSet a directory set
  1441. * @since 1.5
  1442. */
  1443. public void addPackageset(final DirSet packageSet) {
  1444. packageSets.add(packageSet);
  1445. }
  1446. /**
  1447. * Adds a fileset.
  1448. *
  1449. * <p>All included files will be added as sourcefiles. The task
  1450. * will automatically add
  1451. * <code>includes=&quot;**&#47;*.java&quot;</code> to the
  1452. * fileset.</p>
  1453. * @param fs a file set
  1454. * @since 1.5
  1455. */
  1456. public void addFileset(final FileSet fs) {
  1457. createSourceFiles().add(fs);
  1458. }
  1459. /**
  1460. * Adds a container for resource collections.
  1461. *
  1462. * <p>All included files will be added as sourcefiles.</p>
  1463. * @return the source files to configure.
  1464. * @since 1.7
  1465. */
  1466. public ResourceCollectionContainer createSourceFiles() {
  1467. return nestedSourceFiles;
  1468. }
  1469. /**
  1470. * Enables the -linksource switch, will be ignored if Javadoc is not
  1471. * the 1.4 version. Default is false
  1472. * @param b a <code>String</code> value
  1473. * @since Ant 1.6
  1474. */
  1475. public void setLinksource(final boolean b) {
  1476. this.linksource = b;
  1477. }
  1478. /**
  1479. * Enables the -linksource switch, will be ignored if Javadoc is not
  1480. * the 1.4 version. Default is false
  1481. * @param b a <code>String</code> value
  1482. * @since Ant 1.6
  1483. */
  1484. public void setBreakiterator(final boolean b) {
  1485. this.breakiterator = b;
  1486. }
  1487. /**
  1488. * Enables the -noqualifier switch, will be ignored if Javadoc is not
  1489. * the 1.4 version.
  1490. * @param noqualifier the parameter to the -noqualifier switch
  1491. * @since Ant 1.6
  1492. */
  1493. public void setNoqualifier(final String noqualifier) {
  1494. this.noqualifier = noqualifier;
  1495. }
  1496. /**
  1497. * If set to true, Ant will also accept packages that only hold
  1498. * package.html files but no Java sources.
  1499. * @param b a <code>boolean</code> value.
  1500. * @since Ant 1.6.3
  1501. */
  1502. public void setIncludeNoSourcePackages(final boolean b) {
  1503. this.includeNoSourcePackages = b;
  1504. }
  1505. /**
  1506. * Enables deep-copying of <code>doc-files</code> directories.
  1507. *
  1508. * @param b boolean
  1509. * @since Ant 1.8.0
  1510. */
  1511. public void setDocFilesSubDirs(final boolean b) {
  1512. docFilesSubDirs = b;
  1513. }
  1514. /**
  1515. * Colon-separated list of <code>doc-files</code> subdirectories
  1516. * to skip if {@link #setDocFilesSubDirs docFilesSubDirs is true}.
  1517. *
  1518. * @param s String
  1519. * @since Ant 1.8.0
  1520. */
  1521. public void setExcludeDocFilesSubDir(final String s) {
  1522. excludeDocFilesSubDir = s;
  1523. }
  1524. /**
  1525. * Whether to post-process the generated javadocs in order to mitigate CVE-2013-1571.
  1526. *
  1527. * @param b boolean
  1528. * @since Ant 1.9.2
  1529. */
  1530. public void setPostProcessGeneratedJavadocs(final boolean b) {
  1531. postProcessGeneratedJavadocs = b;
  1532. }
  1533. /**
  1534. * Execute the task.
  1535. * @throws BuildException on error
  1536. */
  1537. @Override
  1538. public void execute() throws BuildException {
  1539. checkTaskName();
  1540. final List<String> packagesToDoc = new Vector<>();
  1541. final Path sourceDirs = new Path(getProject());
  1542. checkPackageAndSourcePath();
  1543. if (sourcePath != null) {
  1544. sourceDirs.addExisting(sourcePath);
  1545. }
  1546. parsePackages(packagesToDoc, sourceDirs);
  1547. checkPackages(packagesToDoc, sourceDirs);
  1548. final List<SourceFile> sourceFilesToDoc = new ArrayList<>(sourceFiles);
  1549. addSourceFiles(sourceFilesToDoc);
  1550. checkPackagesToDoc(packagesToDoc, sourceFilesToDoc);
  1551. log("Generating Javadoc", Project.MSG_INFO);
  1552. final Commandline toExecute = (Commandline) cmd.clone();
  1553. if (executable != null) {
  1554. toExecute.setExecutable(executable);
  1555. } else {
  1556. toExecute.setExecutable(JavaEnvUtils.getJdkExecutable("javadoc"));
  1557. }
  1558. // Javadoc arguments
  1559. generalJavadocArguments(toExecute); // general Javadoc arguments
  1560. doSourcePath(toExecute, sourceDirs); // sourcepath
  1561. doDoclet(toExecute); // arguments for default doclet
  1562. doBootPath(toExecute); // bootpath
  1563. doLinks(toExecute); // links arguments
  1564. doGroup(toExecute); // group attribute
  1565. doGroups(toExecute); // groups attribute
  1566. doDocFilesSubDirs(toExecute); // docfilessubdir attribute
  1567. doJava14(toExecute);
  1568. if (breakiterator && (doclet == null || JAVADOC_5)) {
  1569. toExecute.createArgument().setValue("-breakiterator");
  1570. }
  1571. // If using an external file, write the command line options to it
  1572. if (useExternalFile) {
  1573. writeExternalArgs(toExecute);
  1574. }
  1575. File tmpList = null;
  1576. FileWriter wr = null;
  1577. try {
  1578. /**
  1579. * Write sourcefiles and package names to a temporary file
  1580. * if requested.
  1581. */
  1582. BufferedWriter srcListWriter = null;
  1583. if (useExternalFile) {
  1584. tmpList = FILE_UTILS.createTempFile("javadoc", "", null, true, true);
  1585. toExecute.createArgument()
  1586. .setValue("@" + tmpList.getAbsolutePath());
  1587. wr = new FileWriter(tmpList.getAbsolutePath(), true);
  1588. srcListWriter = new BufferedWriter(wr);
  1589. }
  1590. doSourceAndPackageNames(
  1591. toExecute, packagesToDoc, sourceFilesToDoc,
  1592. useExternalFile, tmpList, srcListWriter);
  1593. if (useExternalFile) {
  1594. srcListWriter.flush(); //NOSONAR
  1595. }
  1596. } catch (final IOException e) {
  1597. if (tmpList != null) {
  1598. tmpList.delete();
  1599. }
  1600. throw new BuildException("Error creating temporary file",
  1601. e, getLocation());
  1602. } finally {
  1603. FileUtils.close(wr);
  1604. }
  1605. if (packageList != null) {
  1606. toExecute.createArgument().setValue("@" + packageList);
  1607. }
  1608. log(toExecute.describeCommand(), Project.MSG_VERBOSE);
  1609. log("Javadoc execution", Project.MSG_INFO);
  1610. final JavadocOutputStream out = new JavadocOutputStream(Project.MSG_INFO);
  1611. final JavadocOutputStream err = new JavadocOutputStream(Project.MSG_WARN);
  1612. final Execute exe = new Execute(new PumpStreamHandler(out, err));
  1613. exe.setAntRun(getProject());
  1614. /*
  1615. * No reason to change the working directory as all filenames and
  1616. * path components have been resolved already.
  1617. *
  1618. * Avoid problems with command line length in some environments.
  1619. */
  1620. exe.setWorkingDirectory(null);
  1621. try {
  1622. exe.setCommandline(toExecute.getCommandline());
  1623. final int ret = exe.execute();
  1624. if (ret != 0 && failOnError) {
  1625. throw new BuildException("Javadoc returned " + ret,
  1626. getLocation());
  1627. }
  1628. if (out.sawWarnings() && failOnWarning) {
  1629. throw new BuildException("Javadoc issued warnings.",
  1630. getLocation());
  1631. }
  1632. postProcessGeneratedJavadocs();
  1633. } catch (final IOException e) {
  1634. throw new BuildException("Javadoc failed: " + e, e, getLocation());
  1635. } finally {
  1636. if (tmpList != null) {
  1637. tmpList.delete();
  1638. tmpList = null;
  1639. }
  1640. out.logFlush();
  1641. err.logFlush();
  1642. FileUtils.close(out);
  1643. FileUtils.close(err);
  1644. }
  1645. }
  1646. private void checkTaskName() {
  1647. if ("javadoc2".equals(getTaskType())) {
  1648. log("Warning: the task name <javadoc2> is deprecated."
  1649. + " Use <javadoc> instead.",
  1650. Project.MSG_WARN);
  1651. }
  1652. }
  1653. private void checkPackageAndSourcePath() {
  1654. if (packageList != null && sourcePath == null) {
  1655. final String msg = "sourcePath attribute must be set when "
  1656. + "specifying packagelist.";
  1657. throw new BuildException(msg);
  1658. }
  1659. }
  1660. private void checkPackages(final List<String> packagesToDoc, final Path sourceDirs) {
  1661. if (!packagesToDoc.isEmpty() && sourceDirs.isEmpty()) {
  1662. throw new BuildException(
  1663. "sourcePath attribute must be set when specifying package names.");
  1664. }
  1665. }
  1666. private void checkPackagesToDoc(
  1667. final List<String> packagesToDoc, final List<SourceFile> sourceFilesToDoc) {
  1668. if (packageList == null && packagesToDoc.isEmpty()
  1669. && sourceFilesToDoc.isEmpty()) {
  1670. throw new BuildException(
  1671. "No source files and no packages have been specified.");
  1672. }
  1673. }
  1674. private void doSourcePath(final Commandline toExecute, final Path sourceDirs) {
  1675. if (!sourceDirs.isEmpty()) {
  1676. toExecute.createArgument().setValue("-sourcepath");
  1677. toExecute.createArgument().setPath(sourceDirs);
  1678. }
  1679. }
  1680. private void generalJavadocArguments(final Commandline toExecute) {
  1681. if (doctitle != null) {
  1682. toExecute.createArgument().setValue("-doctitle");
  1683. toExecute.createArgument().setValue(expand(doctitle.getText()));
  1684. }
  1685. if (header != null) {
  1686. toExecute.createArgument().setValue("-header");
  1687. toExecute.createArgument().setValue(expand(header.getText()));
  1688. }
  1689. if (footer != null) {
  1690. toExecute.createArgument().setValue("-footer");
  1691. toExecute.createArgument().setValue(expand(footer.getText()));
  1692. }
  1693. if (bottom != null) {
  1694. toExecute.createArgument().setValue("-bottom");
  1695. toExecute.createArgument().setValue(expand(bottom.getText()));
  1696. }
  1697. if (classpath == null) {
  1698. classpath = new Path(getProject()).concatSystemClasspath("last");
  1699. } else {
  1700. classpath = classpath.concatSystemClasspath("ignore");
  1701. }
  1702. if (classpath.size() > 0) {
  1703. toExecute.createArgument().setValue("-classpath");
  1704. toExecute.createArgument().setPath(classpath);
  1705. }
  1706. if (version && doclet == null) {
  1707. toExecute.createArgument().setValue("-version");
  1708. }
  1709. if (author && doclet == null) {
  1710. toExecute.createArgument().setValue("-author");
  1711. }
  1712. if (doclet == null && destDir == null) {
  1713. throw new BuildException("destdir attribute must be set!");
  1714. }
  1715. }
  1716. private void doDoclet(final Commandline toExecute) {
  1717. if (doclet != null) {
  1718. if (doclet.getName() == null) {
  1719. throw new BuildException("The doclet name must be specified.",
  1720. getLocation());
  1721. }
  1722. toExecute.createArgument().setValue("-doclet");
  1723. toExecute.createArgument().setValue(doclet.getName());
  1724. if (doclet.getPath() != null) {
  1725. final Path docletPath
  1726. = doclet.getPath().concatSystemClasspath("ignore");
  1727. if (docletPath.size() != 0) {
  1728. toExecute.createArgument().setValue("-docletpath");
  1729. toExecute.createArgument().setPath(docletPath);
  1730. }
  1731. }
  1732. for (final DocletParam param : Collections.list(doclet.getParams())) {
  1733. if (param.getName() == null) {
  1734. throw new BuildException("Doclet parameters must have a name");
  1735. }
  1736. toExecute.createArgument().setValue(param.getName());
  1737. if (param.getValue() != null) {
  1738. toExecute.createArgument().setValue(param.getValue());
  1739. }
  1740. }
  1741. }
  1742. }
  1743. private void writeExternalArgs(final Commandline toExecute) {
  1744. // If using an external file, write the command line options to it
  1745. File optionsTmpFile = null;
  1746. try {
  1747. optionsTmpFile = FILE_UTILS.createTempFile(
  1748. "javadocOptions", "", null, true, true);
  1749. final String[] listOpt = toExecute.getArguments();
  1750. toExecute.clearArgs();
  1751. toExecute.createArgument().setValue(
  1752. "@" + optionsTmpFile.getAbsolutePath());
  1753. try (BufferedWriter optionsListWriter = new BufferedWriter(
  1754. new FileWriter(optionsTmpFile.getAbsolutePath(), true))) {
  1755. for (final String opt : listOpt) {
  1756. if (opt.startsWith("-J-")) {
  1757. toExecute.createArgument().setValue(opt);
  1758. } else if (opt.startsWith("-")) {
  1759. optionsListWriter.write(opt);
  1760. optionsListWriter.write(" ");
  1761. } else {
  1762. optionsListWriter.write(quoteString(opt));
  1763. optionsListWriter.newLine();
  1764. }
  1765. }
  1766. }
  1767. } catch (final IOException ex) {
  1768. if (optionsTmpFile != null) {
  1769. optionsTmpFile.delete();
  1770. }
  1771. throw new BuildException(
  1772. "Error creating or writing temporary file for javadoc options",
  1773. ex, getLocation());
  1774. }
  1775. }
  1776. private void doBootPath(final Commandline toExecute) {
  1777. Path bcp = new Path(getProject());
  1778. if (bootclasspath != null) {
  1779. bcp.append(bootclasspath);
  1780. }
  1781. bcp = bcp.concatSystemBootClasspath("ignore");
  1782. if (bcp.size() > 0) {
  1783. toExecute.createArgument().setValue("-bootclasspath");
  1784. toExecute.createArgument().setPath(bcp);
  1785. }
  1786. }
  1787. private void doLinks(final Commandline toExecute) {
  1788. for (final LinkArgument la : links) {
  1789. if (la.getHref() == null || la.getHref().isEmpty()) {
  1790. log("No href was given for the link - skipping",
  1791. Project.MSG_VERBOSE);
  1792. continue;
  1793. }
  1794. String link = null;
  1795. if (la.shouldResolveLink()) {
  1796. final File hrefAsFile =
  1797. getProject().resolveFile(la.getHref());
  1798. if (hrefAsFile.exists()) {
  1799. try {
  1800. link = FILE_UTILS.getFileURL(hrefAsFile)
  1801. .toExternalForm();
  1802. } catch (final MalformedURLException ex) {
  1803. // should be impossible
  1804. log("Warning: link location was invalid "
  1805. + hrefAsFile, Project.MSG_WARN);
  1806. }
  1807. }
  1808. }
  1809. if (link == null) {
  1810. // is the href a valid URL
  1811. try {
  1812. final URL base = new URL("file://.");
  1813. // created for the side effect of throwing a MalformedURLException
  1814. new URL(base, la.getHref()); //NOSONAR
  1815. link = la.getHref();
  1816. } catch (final MalformedURLException mue) {
  1817. // ok - just skip
  1818. log("Link href \"" + la.getHref()
  1819. + "\" is not a valid url - skipping link",
  1820. Project.MSG_WARN);
  1821. continue;
  1822. }
  1823. }
  1824. if (la.isLinkOffline()) {
  1825. final File packageListLocation = la.getPackagelistLoc();
  1826. URL packageListURL = la.getPackagelistURL();
  1827. if (packageListLocation == null
  1828. && packageListURL == null) {
  1829. throw new BuildException(
  1830. "The package list location for link " + la.getHref()
  1831. + " must be provided because the link is offline");
  1832. }
  1833. if (packageListLocation != null) {
  1834. final File packageListFile =
  1835. new File(packageListLocation, "package-list");
  1836. if (packageListFile.exists()) {
  1837. try {
  1838. packageListURL =
  1839. FILE_UTILS.getFileURL(packageListLocation);
  1840. } catch (final MalformedURLException ex) {
  1841. log("Warning: Package list location was "
  1842. + "invalid " + packageListLocation,
  1843. Project.MSG_WARN);
  1844. }
  1845. } else {
  1846. log("Warning: No package list was found at "
  1847. + packageListLocation, Project.MSG_VERBOSE);
  1848. }
  1849. }
  1850. if (packageListURL != null) {
  1851. toExecute.createArgument().setValue("-linkoffline");
  1852. toExecute.createArgument().setValue(link);
  1853. toExecute.createArgument()
  1854. .setValue(packageListURL.toExternalForm());
  1855. }
  1856. } else {
  1857. toExecute.createArgument().setValue("-link");
  1858. toExecute.createArgument().setValue(link);
  1859. }
  1860. }
  1861. }
  1862. private void doGroup(final Commandline toExecute) {
  1863. // add the single group arguments
  1864. // Javadoc 1.2 rules:
  1865. // Multiple -group args allowed.
  1866. // Each arg includes 3 strings: -group [name] [packagelist].
  1867. // Elements in [packagelist] are colon-delimited.
  1868. // An element in [packagelist] may end with the * wildcard.
  1869. // Ant javadoc task rules for group attribute:
  1870. // Args are comma-delimited.
  1871. // Each arg is 2 space-delimited strings.
  1872. // E.g., group="XSLT_Packages org.apache.xalan.xslt*,
  1873. // XPath_Packages org.apache.xalan.xpath*"
  1874. if (group != null) {
  1875. final StringTokenizer tok = new StringTokenizer(group, ",", false);
  1876. while (tok.hasMoreTokens()) {
  1877. final String grp = tok.nextToken().trim();
  1878. final int space = grp.indexOf(' ');
  1879. if (space > 0) {
  1880. final String name = grp.substring(0, space);
  1881. final String pkgList = grp.substring(space + 1);
  1882. toExecute.createArgument().setValue("-group");
  1883. toExecute.createArgument().setValue(name);
  1884. toExecute.createArgument().setValue(pkgList);
  1885. }
  1886. }
  1887. }
  1888. }
  1889. // add the group arguments
  1890. private void doGroups(final Commandline toExecute) {
  1891. for (final GroupArgument ga : groups) {
  1892. final String title = ga.getTitle();
  1893. final String packages = ga.getPackages();
  1894. if (title == null || packages == null) {
  1895. throw new BuildException(
  1896. "The title and packages must be specified for group elements.");
  1897. }
  1898. toExecute.createArgument().setValue("-group");
  1899. toExecute.createArgument().setValue(expand(title));
  1900. toExecute.createArgument().setValue(packages);
  1901. }
  1902. }
  1903. // Do java1.4 arguments
  1904. private void doJava14(final Commandline toExecute) {
  1905. for (final Object element : tags) {
  1906. if (element instanceof TagArgument) {
  1907. final TagArgument ta = (TagArgument) element;
  1908. final File tagDir = ta.getDir(getProject());
  1909. if (tagDir == null) {
  1910. // The tag element is not used as a fileset,
  1911. // but specifies the tag directly.
  1912. toExecute.createArgument().setValue("-tag");
  1913. toExecute.createArgument().setValue(ta.getParameter());
  1914. } else {
  1915. // The tag element is used as a
  1916. // fileset. Parse all the files and create
  1917. // -tag arguments.
  1918. final DirectoryScanner tagDefScanner =
  1919. ta.getDirectoryScanner(getProject());
  1920. for (String file : tagDefScanner.getIncludedFiles()) {
  1921. final File tagDefFile = new File(tagDir, file);
  1922. try (final BufferedReader in =
  1923. new BufferedReader(new FileReader(tagDefFile))) {
  1924. String line;
  1925. while ((line = in.readLine()) != null) {
  1926. toExecute.createArgument()
  1927. .setValue("-tag");
  1928. toExecute.createArgument()
  1929. .setValue(line);
  1930. }
  1931. } catch (final IOException ioe) {
  1932. throw new BuildException(
  1933. "Couldn't read tag file from "
  1934. + tagDefFile.getAbsolutePath(),
  1935. ioe);
  1936. }
  1937. }
  1938. }
  1939. } else {
  1940. final ExtensionInfo tagletInfo = (ExtensionInfo) element;
  1941. toExecute.createArgument().setValue("-taglet");
  1942. toExecute.createArgument().setValue(tagletInfo
  1943. .getName());
  1944. if (tagletInfo.getPath() != null) {
  1945. final Path tagletPath = tagletInfo.getPath()
  1946. .concatSystemClasspath("ignore");
  1947. if (!tagletPath.isEmpty()) {
  1948. toExecute.createArgument()
  1949. .setValue("-tagletpath");
  1950. toExecute.createArgument().setPath(tagletPath);
  1951. }
  1952. }
  1953. }
  1954. }
  1955. final String sourceArg = source != null ? source
  1956. : getProject().getProperty(MagicNames.BUILD_JAVAC_SOURCE);
  1957. if (sourceArg != null) {
  1958. toExecute.createArgument().setValue("-source");
  1959. toExecute.createArgument().setValue(sourceArg);
  1960. }
  1961. if (linksource && doclet == null) {
  1962. toExecute.createArgument().setValue("-linksource");
  1963. }
  1964. if (noqualifier != null && doclet == null) {
  1965. toExecute.createArgument().setValue("-noqualifier");
  1966. toExecute.createArgument().setValue(noqualifier);
  1967. }
  1968. }
  1969. private void doDocFilesSubDirs(final Commandline toExecute) {
  1970. if (docFilesSubDirs) {
  1971. toExecute.createArgument().setValue("-docfilessubdirs");
  1972. if (excludeDocFilesSubDir != null && !excludeDocFilesSubDir.trim().isEmpty()) {
  1973. toExecute.createArgument().setValue("-excludedocfilessubdir");
  1974. toExecute.createArgument().setValue(excludeDocFilesSubDir);
  1975. }
  1976. }
  1977. }
  1978. private void doSourceAndPackageNames(
  1979. final Commandline toExecute,
  1980. final List<String> packagesToDoc,
  1981. final List<SourceFile> sourceFilesToDoc,
  1982. final boolean useExternalFile,
  1983. final File tmpList,
  1984. final BufferedWriter srcListWriter)
  1985. throws IOException {
  1986. for (final String packageName : packagesToDoc) {
  1987. if (useExternalFile) {
  1988. srcListWriter.write(packageName);
  1989. srcListWriter.newLine();
  1990. } else {
  1991. toExecute.createArgument().setValue(packageName);
  1992. }
  1993. }
  1994. for (final SourceFile sf : sourceFilesToDoc) {
  1995. final String sourceFileName = sf.getFile().getAbsolutePath();
  1996. if (useExternalFile) {
  1997. // TODO what is the following doing?
  1998. // should it run if !javadoc4 && executable != null?
  1999. if (sourceFileName.contains(" ")) {
  2000. String name = sourceFileName;
  2001. if (File.separatorChar == '\\') {
  2002. name = sourceFileName.replace(File.separatorChar, '/');
  2003. }
  2004. srcListWriter.write("\"" + name + "\"");
  2005. } else {
  2006. srcListWriter.write(sourceFileName);
  2007. }
  2008. srcListWriter.newLine();
  2009. } else {
  2010. toExecute.createArgument().setValue(sourceFileName);
  2011. }
  2012. }
  2013. }
  2014. /**
  2015. * Quote a string to place in a @ file.
  2016. * @param str the string to quote
  2017. * @return the quoted string, if there is no need to quote the string,
  2018. * return the original string.
  2019. */
  2020. private String quoteString(final String str) {
  2021. if (!containsWhitespace(str)
  2022. && !str.contains("'") && !str.contains("\"")) {
  2023. return str;
  2024. }
  2025. if (!str.contains("'")) {
  2026. return quoteString(str, '\'');
  2027. }
  2028. return quoteString(str, '"');
  2029. }
  2030. private boolean containsWhitespace(final String s) {
  2031. for (char c : s.toCharArray()) {
  2032. if (Character.isWhitespace(c)) {
  2033. return true;
  2034. }
  2035. }
  2036. return false;
  2037. }
  2038. private String quoteString(final String str, final char delim) {
  2039. final StringBuilder buf = new StringBuilder(str.length() * 2);
  2040. buf.append(delim);
  2041. boolean lastCharWasCR = false;
  2042. for (final char c : str.toCharArray()) {
  2043. if (c == delim) { // can't put the non-constant delim into a case
  2044. buf.append('\\').append(c);
  2045. lastCharWasCR = false;
  2046. } else {
  2047. switch (c) {
  2048. case '\\':
  2049. buf.append("\\\\");
  2050. lastCharWasCR = false;
  2051. break;
  2052. case '\r':
  2053. // insert a line continuation marker
  2054. buf.append("\\\r");
  2055. lastCharWasCR = true;
  2056. break;
  2057. case '\n':
  2058. // insert a line continuation marker unless this
  2059. // is a \r\n sequence in which case \r already has
  2060. // created the marker
  2061. if (!lastCharWasCR) {
  2062. buf.append("\\\n");
  2063. } else {
  2064. buf.append("\n");
  2065. }
  2066. lastCharWasCR = false;
  2067. break;
  2068. default:
  2069. buf.append(c);
  2070. lastCharWasCR = false;
  2071. break;
  2072. }
  2073. }
  2074. }
  2075. buf.append(delim);
  2076. return buf.toString();
  2077. }
  2078. /**
  2079. * Add the files matched by the nested source files to the Vector
  2080. * as SourceFile instances.
  2081. *
  2082. * @since 1.7
  2083. */
  2084. private void addSourceFiles(final List<SourceFile> sf) {
  2085. for (ResourceCollection rc : nestedSourceFiles) {
  2086. if (!rc.isFilesystemOnly()) {
  2087. throw new BuildException(
  2088. "only file system based resources are supported by javadoc");
  2089. }
  2090. if (rc instanceof FileSet) {
  2091. final FileSet fs = (FileSet) rc;
  2092. if (!fs.hasPatterns() && !fs.hasSelectors()) {
  2093. final FileSet fs2 = (FileSet) fs.clone();
  2094. fs2.createInclude().setName("**/*.java");
  2095. if (includeNoSourcePackages) {
  2096. fs2.createInclude().setName("**/package.html");
  2097. }
  2098. rc = fs2;
  2099. }
  2100. }
  2101. for (final Resource r : rc) {
  2102. sf.add(new SourceFile(r.as(FileProvider.class).getFile()));
  2103. }
  2104. }
  2105. }
  2106. /**
  2107. * Add the directories matched by the nested dirsets to the Vector
  2108. * and the base directories of the dirsets to the Path. It also
  2109. * handles the packages and excludepackages attributes and
  2110. * elements.
  2111. *
  2112. * @since 1.5
  2113. */
  2114. private void parsePackages(final List<String> pn, final Path sp) {
  2115. final Set<String> addedPackages = new HashSet<>();
  2116. final List<DirSet> dirSets = new ArrayList<>(packageSets);
  2117. // for each sourcePath entry, add a directoryset with includes
  2118. // taken from packagenames attribute and nested package
  2119. // elements and excludes taken from excludepackages attribute
  2120. // and nested excludepackage elements
  2121. if (sourcePath != null) {
  2122. final PatternSet ps = new PatternSet();
  2123. ps.setProject(getProject());
  2124. if (packageNames.isEmpty()) {
  2125. ps.createInclude().setName("**");
  2126. } else {
  2127. packageNames.stream().map(PackageName::getName)
  2128. .map(s -> s.replace('.', '/').replaceFirst("\\*$", "**"))
  2129. .forEach(pkg -> ps.createInclude().setName(pkg));
  2130. }
  2131. excludePackageNames.stream().map(PackageName::getName)
  2132. .map(s -> s.replace('.', '/').replaceFirst("\\*$", "**"))
  2133. .forEach(pkg -> ps.createExclude().setName(pkg));
  2134. for (String pathElement : sourcePath.list()) {
  2135. final File dir = new File(pathElement);
  2136. if (dir.isDirectory()) {
  2137. final DirSet ds = new DirSet();
  2138. ds.setProject(getProject());
  2139. ds.setDefaultexcludes(useDefaultExcludes);
  2140. ds.setDir(dir);
  2141. ds.createPatternSet().addConfiguredPatternset(ps);
  2142. dirSets.add(ds);
  2143. } else {
  2144. log("Skipping " + pathElement
  2145. + " since it is no directory.", Project.MSG_WARN);
  2146. }
  2147. }
  2148. }
  2149. for (DirSet ds : dirSets) {
  2150. final File baseDir = ds.getDir(getProject());
  2151. log("scanning " + baseDir + " for packages.", Project.MSG_DEBUG);
  2152. final DirectoryScanner dsc = ds.getDirectoryScanner(getProject());
  2153. boolean containsPackages = false;
  2154. for (String dir : dsc.getIncludedDirectories()) {
  2155. // are there any java files in this directory?
  2156. final File pd = new File(baseDir, dir);
  2157. final String[] files = pd.list((directory,
  2158. name) -> name.endsWith(".java") || (includeNoSourcePackages
  2159. && name.equals("package.html")));
  2160. if (files.length > 0) {
  2161. if (dir.isEmpty()) {
  2162. log(baseDir
  2163. + " contains source files in the default package, you must specify them as source files not packages.",
  2164. Project.MSG_WARN);
  2165. } else {
  2166. containsPackages = true;
  2167. final String packageName =
  2168. dir.replace(File.separatorChar, '.');
  2169. if (!addedPackages.contains(packageName)) {
  2170. addedPackages.add(packageName);
  2171. pn.add(packageName);
  2172. }
  2173. }
  2174. }
  2175. }
  2176. if (containsPackages) {
  2177. // We don't need to care for duplicates here,
  2178. // Path.list does it for us.
  2179. sp.createPathElement().setLocation(baseDir);
  2180. } else {
  2181. log(baseDir + " doesn\'t contain any packages, dropping it.",
  2182. Project.MSG_VERBOSE);
  2183. }
  2184. }
  2185. }
  2186. private void postProcessGeneratedJavadocs() throws IOException {
  2187. if (!postProcessGeneratedJavadocs) {
  2188. return;
  2189. }
  2190. if (destDir != null && !destDir.isDirectory()) {
  2191. log("No javadoc created, no need to post-process anything",
  2192. Project.MSG_VERBOSE);
  2193. return;
  2194. }
  2195. final InputStream in = Javadoc.class
  2196. .getResourceAsStream("javadoc-frame-injections-fix.txt");
  2197. if (in == null) {
  2198. throw new FileNotFoundException(
  2199. "Missing resource 'javadoc-frame-injections-fix.txt' in classpath.");
  2200. }
  2201. final String fixData;
  2202. try {
  2203. fixData =
  2204. fixLineFeeds(FileUtils
  2205. .readFully(new InputStreamReader(in, "US-ASCII")))
  2206. .trim();
  2207. } finally {
  2208. FileUtils.close(in);
  2209. }
  2210. final DirectoryScanner ds = new DirectoryScanner();
  2211. ds.setBasedir(destDir);
  2212. ds.setCaseSensitive(false);
  2213. ds.setIncludes(new String[] {
  2214. "**/index.html", "**/index.htm", "**/toc.html", "**/toc.htm"
  2215. });
  2216. ds.addDefaultExcludes();
  2217. ds.scan();
  2218. int patched = 0;
  2219. for (final String f : ds.getIncludedFiles()) {
  2220. patched += postProcess(new File(destDir, f), fixData);
  2221. }
  2222. if (patched > 0) {
  2223. log("Patched " + patched + " link injection vulnerable javadocs",
  2224. Project.MSG_INFO);
  2225. }
  2226. }
  2227. private int postProcess(final File file, final String fixData) throws IOException {
  2228. final String enc = docEncoding != null ? docEncoding
  2229. : FILE_UTILS.getDefaultEncoding();
  2230. // we load the whole file as one String (toc/index files are
  2231. // generally small, because they only contain frameset declaration):
  2232. String fileContents;
  2233. try (InputStreamReader reader =
  2234. new InputStreamReader(Files.newInputStream(file.toPath()), enc)) {
  2235. fileContents = fixLineFeeds(FileUtils.safeReadFully(reader));
  2236. }
  2237. // check if file may be vulnerable because it was not
  2238. // patched with "validURL(url)":
  2239. if (!fileContents.contains("function validURL(url) {")) {
  2240. // we need to patch the file!
  2241. final String patchedFileContents = patchContent(fileContents, fixData);
  2242. if (!patchedFileContents.equals(fileContents)) {
  2243. try (final OutputStreamWriter w =
  2244. new OutputStreamWriter(Files.newOutputStream(file.toPath()), enc)) {
  2245. w.write(patchedFileContents);
  2246. w.close();
  2247. return 1;
  2248. }
  2249. }
  2250. }
  2251. return 0;
  2252. }
  2253. private String fixLineFeeds(final String orig) {
  2254. return orig.replace("\r\n", "\n")
  2255. .replace("\n", System.lineSeparator());
  2256. }
  2257. private String patchContent(final String fileContents, final String fixData) {
  2258. // using regexes here looks like overkill
  2259. final int start = fileContents.indexOf(LOAD_FRAME);
  2260. if (start >= 0) {
  2261. return fileContents.substring(0, start) + fixData
  2262. + fileContents.substring(start + LOAD_FRAME_LEN);
  2263. }
  2264. return fileContents;
  2265. }
  2266. private class JavadocOutputStream extends LogOutputStream {
  2267. JavadocOutputStream(final int level) {
  2268. super(Javadoc.this, level);
  2269. }
  2270. //
  2271. // Override the logging of output in order to filter out Generating
  2272. // messages. Generating messages are set to a priority of VERBOSE
  2273. // unless they appear after what could be an informational message.
  2274. //
  2275. private String queuedLine = null;
  2276. private boolean sawWarnings = false;
  2277. @Override
  2278. protected void processLine(final String line, final int messageLevel) {
  2279. if (line.contains("warning")) {
  2280. sawWarnings = true;
  2281. }
  2282. if (messageLevel == Project.MSG_INFO
  2283. && line.startsWith("Generating ")) {
  2284. if (queuedLine != null) {
  2285. super.processLine(queuedLine, Project.MSG_VERBOSE);
  2286. }
  2287. queuedLine = line;
  2288. } else {
  2289. if (queuedLine != null) {
  2290. if (line.startsWith("Building ")) {
  2291. super.processLine(queuedLine, Project.MSG_VERBOSE);
  2292. } else {
  2293. super.processLine(queuedLine, Project.MSG_INFO);
  2294. }
  2295. queuedLine = null;
  2296. }
  2297. super.processLine(line, messageLevel);
  2298. }
  2299. }
  2300. protected void logFlush() {
  2301. if (queuedLine != null) {
  2302. super.processLine(queuedLine, Project.MSG_VERBOSE);
  2303. queuedLine = null;
  2304. }
  2305. }
  2306. public boolean sawWarnings() {
  2307. return sawWarnings;
  2308. }
  2309. }
  2310. /**
  2311. * Convenience method to expand properties.
  2312. * @param content the string to expand
  2313. * @return the converted string
  2314. */
  2315. protected String expand(final String content) {
  2316. return getProject().replaceProperties(content);
  2317. }
  2318. }