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

AbstractStandard.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /* -*- Mode: JDE; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. *
  3. * This file is part of the debugger and core tools for the AspectJ(tm)
  4. * programming language; see http://aspectj.org
  5. *
  6. * The contents of this file are subject to the Mozilla Public License
  7. * Version 1.1 (the "License"); you may not use this file except in
  8. * compliance with the License. You may obtain a copy of the License at
  9. * either http://www.mozilla.org/MPL/ or http://aspectj.org/MPL/.
  10. *
  11. * Software distributed under the License is distributed on an "AS IS" basis,
  12. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13. * for the specific language governing rights and limitations under the
  14. * License.
  15. *
  16. * The Original Code is AspectJ.
  17. *
  18. * The Initial Developer of the Original Code is Xerox Corporation. Portions
  19. * created by Xerox Corporation are Copyright (C) 1999-2002 Xerox Corporation.
  20. * All Rights Reserved.
  21. */
  22. package org.aspectj.tools.doclets.standard;
  23. import org.aspectj.ajdoc.AspectDoc;
  24. import com.sun.javadoc.ClassDoc;
  25. import com.sun.javadoc.DocErrorReporter;
  26. import com.sun.javadoc.PackageDoc;
  27. import com.sun.javadoc.RootDoc;
  28. import com.sun.tools.doclets.ClassTree;
  29. import com.sun.tools.doclets.DocletAbortException;
  30. import com.sun.tools.doclets.HtmlDocWriter;
  31. import com.sun.tools.doclets.IndexBuilder;
  32. import java.io.IOException;
  33. import java.lang.reflect.Constructor;
  34. import java.util.Arrays;
  35. /**
  36. * An abstract allowing one to customize the writers
  37. * used in ajdoc. Subclasses should define the three
  38. * generate methods to specify the documentation made.
  39. *
  40. * @see #preGenerationClasses()
  41. * @see #postGenerationClasses()
  42. * @see #checkClasses()
  43. * @author Jeff Palm
  44. */
  45. public abstract class AbstractStandard
  46. extends com.sun.tools.doclets.standard.Standard {
  47. // todo wes removed restriction, but implemented Standard as singleton via proxy
  48. private static int refCount = 0;
  49. {
  50. if (refCount > 0) {
  51. System.err.println("Warning: " + refCount + " AbstractStandard already ");
  52. }
  53. refCount++;
  54. }
  55. /**
  56. * The ClassTree that is available to subclasses and it gaurateed
  57. * to be created before pre-generating classes.
  58. */
  59. protected ClassTree classtree;
  60. protected static boolean start(AbstractStandard as,
  61. RootDoc root) throws IOException {
  62. try {
  63. as.getConfiguration().setOptions(root);
  64. as.startGeneration(root);
  65. } catch (DocletAbortException exc) {
  66. return false;
  67. }
  68. return true;
  69. }
  70. /**
  71. * Returns the types of {@link Pass}es that will
  72. * run before generating classes.
  73. *
  74. * @return an array of Class, where each entry
  75. * is a subclass of {@link Pass}, ordered
  76. * to run directly before generating the
  77. * classes.
  78. */
  79. protected abstract Class[] preGenerationClasses();
  80. /**
  81. * Returns the types of {@link Pass}es that will
  82. * run after generating classes.
  83. *
  84. * @return an array of Class, where each entry
  85. * is a subclass of {@link Pass}, ordered
  86. * to run directly after generating the
  87. * classes.
  88. */
  89. protected abstract Class[] postGenerationClasses();
  90. /**
  91. * Returns the types of {@link CheckPass}es that will
  92. * run to check the classes.
  93. *
  94. * @return an array of Class, where each entry
  95. * is a subclass of {@link CheckPass}, ordered
  96. * to run in order to check the classes passed
  97. * into the class generation phase.
  98. */
  99. protected abstract Class[] checkClasses();
  100. /**
  101. * Return the configuration used by a subclass. This
  102. * allows the subclass to specify it's own kind.
  103. *
  104. * @return a customized configuration.
  105. */
  106. public abstract ConfigurationStandard getConfiguration();
  107. protected ConfigurationStandard makeConfiguration() {
  108. return new ConfigurationStandard();
  109. }
  110. /**
  111. * Returns the configuration, and ensures that
  112. * HtmlDocWriter.configuration is of the type used by
  113. * this class.
  114. *
  115. * @return the current instanceof ConfigurationStandard being
  116. * used and creates one if needed. This will <b>not</b>
  117. * be null.
  118. */
  119. // todo these are the heinous globals that impose one process per classloader
  120. public static com.sun.tools.doclets.standard.ConfigurationStandard
  121. configuration() {
  122. if (HtmlDocWriter.configuration == null ||
  123. !(HtmlDocWriter.configuration instanceof ConfigurationStandard)) {
  124. HtmlDocWriter.configuration = new ConfigurationStandard();
  125. //TODO: change to makeConfiguration()
  126. }
  127. return (ConfigurationStandard)HtmlDocWriter.configuration;
  128. }
  129. /**
  130. * Creates and returns an IndexBuilder that includes aspects.
  131. *
  132. * @param root RootDoc to pass the new IndexBuilder.
  133. * @param classesOnly <code>true</code> if only classes
  134. * should be included.
  135. * @return an IndexBuilder that includes aspects.
  136. */
  137. protected IndexBuilder indexBuilder(RootDoc root, boolean classesOnly) {
  138. class MyIndexBuilder extends IndexBuilder {
  139. public MyIndexBuilder(RootDoc r, boolean n) {
  140. super(r, n);
  141. }
  142. public MyIndexBuilder(RootDoc r, boolean n, boolean b) {
  143. super(r, n, b);
  144. }
  145. protected void putMembersInIndexMap(ClassDoc classdoc) {
  146. super.putMembersInIndexMap(classdoc);
  147. if (classdoc instanceof org.aspectj.ajdoc.ClassDoc) {
  148. org.aspectj.ajdoc.ClassDoc cd =
  149. (org.aspectj.ajdoc.ClassDoc)classdoc;
  150. adjustIndexMap(cd.pointcuts());
  151. if (cd instanceof AspectDoc) {
  152. adjustIndexMap(((AspectDoc)cd).advice());
  153. }
  154. }
  155. }
  156. }
  157. return new MyIndexBuilder(root, configuration().nodeprecated, classesOnly);
  158. }
  159. /**
  160. * Does the work in generating the documentation.
  161. * First, call all the passes return from {@link #generateCheckPasses}
  162. * them perform some copying. Second build the classtree, run the
  163. * pre-classgeneration passes, generate the packages, generate the
  164. * classes, then call all the postGenerationClasses.
  165. *
  166. * @param root the root of the documentation.
  167. */
  168. protected void startGeneration(RootDoc root) throws DocletAbortException {
  169. if (!generateCheckPasses(getConfiguration(), root)) return;
  170. performCopy(getConfiguration().destdirname,
  171. getConfiguration().helpfile);
  172. performCopy(getConfiguration().destdirname,
  173. getConfiguration().stylesheetfile);
  174. classtree = new ClassTree(root, getConfiguration().nodeprecated);
  175. generatePrePasses(getConfiguration(), root);
  176. generatePackageCycle(getConfiguration().packages,
  177. getConfiguration().createtree,
  178. getConfiguration().nodeprecated);
  179. generateClassFiles(root, classtree);
  180. generatePostPasses(getConfiguration(), root);
  181. }
  182. /**
  183. * A class representing a single pass in the generation cycles. It
  184. * does some of the dirty work for you.
  185. */
  186. public static abstract class Pass {
  187. /** The root available to this pass. */
  188. protected RootDoc root;
  189. /** The configuration available to this pass. */
  190. protected ConfigurationStandard cs;
  191. /** The doclet available to this pass. */
  192. protected AbstractStandard std;
  193. public Pass() {}
  194. /**
  195. * Returns the title of the pass for logging.
  196. *
  197. * @return the unique title of this pass. This can
  198. * be <code>null</code> to disable display.
  199. */
  200. public abstract String title();
  201. /**
  202. * Do the generation work. All instance variables
  203. * are guaranteed to be set.
  204. */
  205. protected abstract void gen() throws DocletAbortException;
  206. /**
  207. * Do the actual generation if {@link #cond} returns
  208. * <code>true</code>. Do some other logging, too.
  209. *
  210. * @param std the AbstractStandard to use.
  211. * @param cs the ConfigurationStandard to use.
  212. * @param root the RootDoc to use.
  213. */
  214. public final void generate(AbstractStandard std,
  215. ConfigurationStandard cs,
  216. RootDoc root)
  217. throws DocletAbortException {
  218. this.std = std;
  219. this.cs = cs;
  220. this.root = root;
  221. if (cond()) {
  222. String title = title();
  223. long start = System.currentTimeMillis();
  224. if (cs.log && title != null) {
  225. cs.standardmessage.notice("doclet.pass_msg", title);
  226. }
  227. gen();
  228. if (cs.log && title != null) {
  229. long stop = System.currentTimeMillis();
  230. cs.standardmessage.notice("doclet.done_msg",
  231. title, (stop-start)+"");
  232. }
  233. }
  234. }
  235. /**
  236. * Returns whether the generation should proceed. Override
  237. * this method for conditional passes.
  238. *
  239. * @return <code>true</code> is this pass shoulud proceed.
  240. */
  241. protected boolean cond() {
  242. return true;
  243. }
  244. }
  245. /**
  246. * A convenience class for doing checks.
  247. */
  248. public abstract static class Check extends Pass {
  249. /**
  250. * Returns the error message if check fails.
  251. *
  252. * @return error message if check fails.
  253. */
  254. protected abstract String message();
  255. /**
  256. * Returns whether check has failed or not.
  257. *
  258. * @return <code>true</code> is check fails.
  259. */
  260. protected abstract boolean cond();
  261. /**
  262. * Prints message, because we've failed and throws
  263. * a DocletAbortException to notify the doclet
  264. * that we've failed.
  265. */
  266. protected void gen() throws DocletAbortException {
  267. cs.standardmessage.error(message());
  268. throw new DocletAbortException();
  269. }
  270. /**
  271. * Returns null, because we don't want to be displayed.
  272. *
  273. * @return <code>null</code>.
  274. */
  275. public String title() { return null; }
  276. }
  277. /**
  278. * Generates the passes to run before generating the classes.
  279. */
  280. private final void generatePrePasses(ConfigurationStandard cs,
  281. RootDoc root)
  282. throws DocletAbortException {
  283. generatePasses(cs, root, preGenerationClasses());
  284. }
  285. /**
  286. * Generates the passes to run after generating the classes.
  287. */
  288. private final void generatePostPasses(ConfigurationStandard cs,
  289. RootDoc root)
  290. throws DocletAbortException {
  291. generatePasses(cs, root, postGenerationClasses());
  292. }
  293. /**
  294. * Generates the passes that run before doing anything. These
  295. * passes check that it's OK to do anything.
  296. */
  297. private final boolean generateCheckPasses(ConfigurationStandard cs,
  298. RootDoc root)
  299. throws DocletAbortException {
  300. try {
  301. generatePasses(cs, root, checkClasses());
  302. } catch (DocletAbortException e) {
  303. return false;
  304. }
  305. return true;
  306. }
  307. /**
  308. * Generates passes from <code>classes</code>. For each
  309. * class found in <code>classes</code> a constructor taking zero
  310. * or one-argument is called. Then the generate method is
  311. * called on that Pass passing it <code>this</code>, the
  312. * configuration, and root.
  313. *
  314. * @param cs configuration to use.
  315. * @param root root we're documenting.
  316. * @param classes list of subtypes of {@link Pass} that
  317. * will be run.
  318. */
  319. private final void generatePasses(ConfigurationStandard cs,
  320. RootDoc root,
  321. Class[] classes)
  322. throws DocletAbortException {
  323. if (classes == null) return;
  324. nextClass:
  325. for (int i = 0; i < classes.length; i++) {
  326. try {
  327. Constructor[] ctrs = classes[i].getConstructors();
  328. nextCtr:
  329. for (int j = 0; j < ctrs.length; j++) {
  330. Pass pass = null;
  331. if (ctrs[j].getParameterTypes().length == 0) {
  332. pass = (Pass)ctrs[j].newInstance(new Object[]{});
  333. } else if (ctrs[j].getParameterTypes().length == 1) {
  334. pass = (Pass)ctrs[j].newInstance(new Object[]{this});
  335. }
  336. if (pass != null) {
  337. pass.generate(this,cs,root);
  338. continue nextClass;
  339. }
  340. }
  341. throw new Exception("Can't create pass for class " + classes[i]);
  342. } catch (Exception e) {
  343. e.printStackTrace();
  344. Standard.configuration().standardmessage.
  345. error("doclet.exception", e+"");
  346. throw new DocletAbortException();
  347. }
  348. }
  349. }
  350. /**
  351. * Generates the packages.
  352. */
  353. protected void generatePackageCycle(PackageDoc[] pkgs,
  354. boolean createtree,
  355. boolean nodeprecated)
  356. throws DocletAbortException {
  357. Arrays.sort(pkgs);
  358. for (int i = 0; i < pkgs.length; i++) {
  359. PackageDoc prev = i == 0 ? null : pkgs[i-1];
  360. PackageDoc curr = pkgs[i];
  361. PackageDoc next = i == pkgs.length-1 ? null : pkgs[i+1];
  362. generatePackages(prev, curr, next,
  363. createtree, nodeprecated);
  364. }
  365. }
  366. /**
  367. * Generates a package doc for the three PackageDocs passed.
  368. */
  369. protected void generatePackages(PackageDoc prev,
  370. PackageDoc curr,
  371. PackageDoc next,
  372. boolean createtree,
  373. boolean nodeprecated)
  374. throws DocletAbortException {
  375. PackageWriter.generate(curr, prev, next);
  376. if (createtree) {
  377. PackageTreeWriter.generate(curr, prev,
  378. next, nodeprecated);
  379. }
  380. PackageFrameWriter.generate(curr);
  381. }
  382. /**
  383. * Generates all the classes.
  384. */
  385. protected void generateClassCycle(ClassDoc[] cs,
  386. ClassTree classtree,
  387. boolean nopackage)
  388. throws DocletAbortException {
  389. Arrays.sort(cs);
  390. for(int i = 0; i < cs.length; i++) {
  391. if (configuration().nodeprecated &&
  392. cs[i].tags("deprecated").length > 0) {
  393. continue;
  394. }
  395. ClassDoc prev = i == 0 ? null : cs[i-1];
  396. ClassDoc curr = cs[i];
  397. ClassDoc next = i == cs.length-1 ? null : cs[i+1];
  398. generateClasses(prev, curr, next,
  399. classtree, nopackage);
  400. }
  401. }
  402. /**
  403. * Generates class docs for the three ClassDocs passed.
  404. */
  405. protected void generateClasses(ClassDoc prev,
  406. ClassDoc curr,
  407. ClassDoc next,
  408. ClassTree classtree,
  409. boolean nopackage)
  410. throws DocletAbortException {
  411. ClassWriter.generate(curr, prev, next,
  412. classtree, nopackage);
  413. }
  414. /**
  415. * Returns the delegation to {@link #configuration()}.
  416. */
  417. public static int optionLength(String option) {
  418. return configuration().optionLength(option);
  419. }
  420. /**
  421. * Returns the delegation to {@link #configuration()}.
  422. */
  423. public static boolean validOptions(String options[][],
  424. DocErrorReporter reporter)
  425. throws IOException {
  426. return configuration().validOptions(options, reporter);
  427. }
  428. }