Thu, 13 Jan 2011 21:28:38 -0800
7010528: javadoc performance regression
Reviewed-by: jjg
1 /*
2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.tools.doclets.formats.html;
28 import java.util.*;
30 import com.sun.javadoc.*;
31 import com.sun.tools.doclets.internal.toolkit.*;
32 import com.sun.tools.doclets.internal.toolkit.util.*;
33 import com.sun.tools.doclets.internal.toolkit.builders.*;
34 import com.sun.tools.doclets.internal.toolkit.taglets.*;
35 import com.sun.tools.doclets.formats.html.markup.*;
37 /**
38 * Generate the Class Information Page.
39 * @see com.sun.javadoc.ClassDoc
40 * @see java.util.Collections
41 * @see java.util.List
42 * @see java.util.ArrayList
43 * @see java.util.HashMap
44 *
45 * @author Atul M Dambalkar
46 * @author Robert Field
47 * @author Bhavesh Patel (Modified)
48 */
49 public class ClassWriterImpl extends SubWriterHolderWriter
50 implements ClassWriter {
52 protected ClassDoc classDoc;
54 protected ClassTree classtree;
56 protected ClassDoc prev;
58 protected ClassDoc next;
60 /**
61 * @param classDoc the class being documented.
62 * @param prevClass the previous class that was documented.
63 * @param nextClass the next class being documented.
64 * @param classTree the class tree for the given class.
65 */
66 public ClassWriterImpl (ClassDoc classDoc,
67 ClassDoc prevClass, ClassDoc nextClass, ClassTree classTree)
68 throws Exception {
69 super(ConfigurationImpl.getInstance(),
70 DirectoryManager.getDirectoryPath(classDoc.containingPackage()),
71 classDoc.name() + ".html",
72 DirectoryManager.getRelativePath(classDoc.containingPackage().name()));
73 this.classDoc = classDoc;
74 configuration.currentcd = classDoc;
75 this.classtree = classTree;
76 this.prev = prevClass;
77 this.next = nextClass;
78 }
80 /**
81 * Get this package link.
82 *
83 * @return a content tree for the package link
84 */
85 protected Content getNavLinkPackage() {
86 Content linkContent = getHyperLink("package-summary.html", "",
87 packageLabel);
88 Content li = HtmlTree.LI(linkContent);
89 return li;
90 }
92 /**
93 * Get the class link.
94 *
95 * @return a content tree for the class link
96 */
97 protected Content getNavLinkClass() {
98 Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, classLabel);
99 return li;
100 }
102 /**
103 * Get the class use link.
104 *
105 * @return a content tree for the class use link
106 */
107 protected Content getNavLinkClassUse() {
108 Content linkContent = getHyperLink("class-use/" + filename, "", useLabel);
109 Content li = HtmlTree.LI(linkContent);
110 return li;
111 }
113 /**
114 * Get link to previous class.
115 *
116 * @return a content tree for the previous class link
117 */
118 public Content getNavLinkPrevious() {
119 Content li;
120 if (prev != null) {
121 Content prevLink = new RawHtml(getLink(new LinkInfoImpl(
122 LinkInfoImpl.CONTEXT_CLASS, prev, "",
123 configuration.getText("doclet.Prev_Class"), true)));
124 li = HtmlTree.LI(prevLink);
125 }
126 else
127 li = HtmlTree.LI(prevclassLabel);
128 return li;
129 }
131 /**
132 * Get link to next class.
133 *
134 * @return a content tree for the next class link
135 */
136 public Content getNavLinkNext() {
137 Content li;
138 if (next != null) {
139 Content nextLink = new RawHtml(getLink(new LinkInfoImpl(
140 LinkInfoImpl.CONTEXT_CLASS, next, "",
141 configuration.getText("doclet.Next_Class"), true)));
142 li = HtmlTree.LI(nextLink);
143 }
144 else
145 li = HtmlTree.LI(nextclassLabel);
146 return li;
147 }
149 /**
150 * {@inheritDoc}
151 */
152 public Content getHeader(String header) {
153 String pkgname = (classDoc.containingPackage() != null)?
154 classDoc.containingPackage().name(): "";
155 String clname = classDoc.name();
156 Content bodyTree = getBody(true, getWindowTitle(clname));
157 addTop(bodyTree);
158 addNavLinks(true, bodyTree);
159 bodyTree.addContent(HtmlConstants.START_OF_CLASS_DATA);
160 HtmlTree div = new HtmlTree(HtmlTag.DIV);
161 div.addStyle(HtmlStyle.header);
162 if (pkgname.length() > 0) {
163 Content pkgNameContent = new StringContent(pkgname);
164 Content pkgNamePara = HtmlTree.P(HtmlStyle.subTitle, pkgNameContent);
165 div.addContent(pkgNamePara);
166 }
167 LinkInfoImpl linkInfo = new LinkInfoImpl( LinkInfoImpl.CONTEXT_CLASS_HEADER,
168 classDoc, false);
169 //Let's not link to ourselves in the header.
170 linkInfo.linkToSelf = false;
171 Content headerContent = new StringContent(header);
172 Content heading = HtmlTree.HEADING(HtmlConstants.CLASS_PAGE_HEADING, true,
173 HtmlStyle.title, headerContent);
174 heading.addContent(new RawHtml(getTypeParameterLinks(linkInfo)));
175 div.addContent(heading);
176 bodyTree.addContent(div);
177 return bodyTree;
178 }
180 /**
181 * {@inheritDoc}
182 */
183 public Content getClassContentHeader() {
184 return getContentHeader();
185 }
187 /**
188 * {@inheritDoc}
189 */
190 public void addFooter(Content contentTree) {
191 contentTree.addContent(HtmlConstants.END_OF_CLASS_DATA);
192 addNavLinks(false, contentTree);
193 addBottom(contentTree);
194 }
196 /**
197 * {@inheritDoc}
198 */
199 public void printDocument(Content contentTree) {
200 printHtmlDocument(configuration.metakeywords.getMetaKeywords(classDoc),
201 true, contentTree);
202 }
204 /**
205 * {@inheritDoc}
206 */
207 public Content getClassInfoTreeHeader() {
208 return getMemberTreeHeader();
209 }
211 /**
212 * {@inheritDoc}
213 */
214 public Content getClassInfo(Content classInfoTree) {
215 return getMemberTree(HtmlStyle.description, classInfoTree);
216 }
218 /**
219 * {@inheritDoc}
220 */
221 public void addClassSignature(String modifiers, Content classInfoTree) {
222 boolean isInterface = classDoc.isInterface();
223 classInfoTree.addContent(new HtmlTree(HtmlTag.BR));
224 Content pre = new HtmlTree(HtmlTag.PRE);
225 addAnnotationInfo(classDoc, pre);
226 pre.addContent(modifiers);
227 LinkInfoImpl linkInfo = new LinkInfoImpl(
228 LinkInfoImpl.CONTEXT_CLASS_SIGNATURE, classDoc, false);
229 //Let's not link to ourselves in the signature.
230 linkInfo.linkToSelf = false;
231 Content name = new RawHtml (classDoc.name() +
232 getTypeParameterLinks(linkInfo));
233 if (configuration().linksource) {
234 addSrcLink(classDoc, name, pre);
235 } else {
236 pre.addContent(HtmlTree.STRONG(name));
237 }
238 if (!isInterface) {
239 Type superclass = Util.getFirstVisibleSuperClass(classDoc,
240 configuration());
241 if (superclass != null) {
242 pre.addContent(DocletConstants.NL);
243 pre.addContent("extends ");
244 Content link = new RawHtml(getLink(new LinkInfoImpl(
245 LinkInfoImpl.CONTEXT_CLASS_SIGNATURE_PARENT_NAME,
246 superclass)));
247 pre.addContent(link);
248 }
249 }
250 Type[] implIntfacs = classDoc.interfaceTypes();
251 if (implIntfacs != null && implIntfacs.length > 0) {
252 int counter = 0;
253 for (int i = 0; i < implIntfacs.length; i++) {
254 ClassDoc classDoc = implIntfacs[i].asClassDoc();
255 if (! (classDoc.isPublic() ||
256 Util.isLinkable(classDoc, configuration()))) {
257 continue;
258 }
259 if (counter == 0) {
260 pre.addContent(DocletConstants.NL);
261 pre.addContent(isInterface? "extends " : "implements ");
262 } else {
263 pre.addContent(", ");
264 }
265 Content link = new RawHtml(getLink(new LinkInfoImpl(
266 LinkInfoImpl.CONTEXT_CLASS_SIGNATURE_PARENT_NAME,
267 implIntfacs[i])));
268 pre.addContent(link);
269 counter++;
270 }
271 }
272 classInfoTree.addContent(pre);
273 }
275 /**
276 * {@inheritDoc}
277 */
278 public void addClassDescription(Content classInfoTree) {
279 if(!configuration.nocomment) {
280 // generate documentation for the class.
281 if (classDoc.inlineTags().length > 0) {
282 addInlineComment(classDoc, classInfoTree);
283 }
284 }
285 }
287 /**
288 * {@inheritDoc}
289 */
290 public void addClassTagInfo(Content classInfoTree) {
291 if(!configuration.nocomment) {
292 // Print Information about all the tags here
293 addTagsInfo(classDoc, classInfoTree);
294 }
295 }
297 /**
298 * Get the class hierarchy tree for the given class.
299 *
300 * @param type the class to print the hierarchy for
301 * @return a content tree for class inheritence
302 */
303 private Content getClassInheritenceTree(Type type) {
304 Type sup;
305 HtmlTree classTreeUl = new HtmlTree(HtmlTag.UL);
306 classTreeUl.addStyle(HtmlStyle.inheritance);
307 Content liTree = null;
308 do {
309 sup = Util.getFirstVisibleSuperClass(
310 type instanceof ClassDoc ? (ClassDoc) type : type.asClassDoc(),
311 configuration());
312 if (sup != null) {
313 HtmlTree ul = new HtmlTree(HtmlTag.UL);
314 ul.addStyle(HtmlStyle.inheritance);
315 ul.addContent(getTreeForClassHelper(type));
316 if (liTree != null)
317 ul.addContent(liTree);
318 Content li = HtmlTree.LI(ul);
319 liTree = li;
320 type = sup;
321 }
322 else
323 classTreeUl.addContent(getTreeForClassHelper(type));
324 }
325 while (sup != null);
326 if (liTree != null)
327 classTreeUl.addContent(liTree);
328 return classTreeUl;
329 }
331 /**
332 * Get the class helper tree for the given class.
333 *
334 * @param type the class to print the helper for
335 * @return a content tree for class helper
336 */
337 private Content getTreeForClassHelper(Type type) {
338 Content li = new HtmlTree(HtmlTag.LI);
339 if (type.equals(classDoc)) {
340 String typeParameters = getTypeParameterLinks(
341 new LinkInfoImpl(LinkInfoImpl.CONTEXT_TREE,
342 classDoc, false));
343 if (configuration.shouldExcludeQualifier(
344 classDoc.containingPackage().name())) {
345 li.addContent(type.asClassDoc().name());
346 li.addContent(new RawHtml(typeParameters));
347 } else {
348 li.addContent(type.asClassDoc().qualifiedName());
349 li.addContent(new RawHtml(typeParameters));
350 }
351 } else {
352 Content link = new RawHtml(getLink(new LinkInfoImpl(
353 LinkInfoImpl.CONTEXT_CLASS_TREE_PARENT,
354 type instanceof ClassDoc ? (ClassDoc) type : type,
355 configuration.getClassName(type.asClassDoc()), false)));
356 li.addContent(link);
357 }
358 return li;
359 }
361 /**
362 * {@inheritDoc}
363 */
364 public void addClassTree(Content classContentTree) {
365 if (!classDoc.isClass()) {
366 return;
367 }
368 classContentTree.addContent(getClassInheritenceTree(classDoc));
369 }
371 /**
372 * {@inheritDoc}
373 */
374 public void addTypeParamInfo(Content classInfoTree) {
375 if (classDoc.typeParamTags().length > 0) {
376 TagletOutput output = (new ParamTaglet()).getTagletOutput(classDoc,
377 getTagletWriterInstance(false));
378 Content typeParam = new RawHtml(output.toString());
379 Content dl = HtmlTree.DL(typeParam);
380 classInfoTree.addContent(dl);
381 }
382 }
384 /**
385 * {@inheritDoc}
386 */
387 public void addSubClassInfo(Content classInfoTree) {
388 if (classDoc.isClass()) {
389 if (classDoc.qualifiedName().equals("java.lang.Object") ||
390 classDoc.qualifiedName().equals("org.omg.CORBA.Object")) {
391 return; // Don't generate the list, too huge
392 }
393 List<ClassDoc> subclasses = classtree.subs(classDoc, false);
394 if (subclasses.size() > 0) {
395 Content label = getResource(
396 "doclet.Subclasses");
397 Content dt = HtmlTree.DT(label);
398 Content dl = HtmlTree.DL(dt);
399 dl.addContent(getClassLinks(LinkInfoImpl.CONTEXT_SUBCLASSES,
400 subclasses));
401 classInfoTree.addContent(dl);
402 }
403 }
404 }
406 /**
407 * {@inheritDoc}
408 */
409 public void addSubInterfacesInfo(Content classInfoTree) {
410 if (classDoc.isInterface()) {
411 List<ClassDoc> subInterfaces = classtree.allSubs(classDoc, false);
412 if (subInterfaces.size() > 0) {
413 Content label = getResource(
414 "doclet.Subinterfaces");
415 Content dt = HtmlTree.DT(label);
416 Content dl = HtmlTree.DL(dt);
417 dl.addContent(getClassLinks(LinkInfoImpl.CONTEXT_SUBINTERFACES,
418 subInterfaces));
419 classInfoTree.addContent(dl);
420 }
421 }
422 }
424 /**
425 * {@inheritDoc}
426 */
427 public void addInterfaceUsageInfo (Content classInfoTree) {
428 if (! classDoc.isInterface()) {
429 return;
430 }
431 if (classDoc.qualifiedName().equals("java.lang.Cloneable") ||
432 classDoc.qualifiedName().equals("java.io.Serializable")) {
433 return; // Don't generate the list, too big
434 }
435 List<ClassDoc> implcl = classtree.implementingclasses(classDoc);
436 if (implcl.size() > 0) {
437 Content label = getResource(
438 "doclet.Implementing_Classes");
439 Content dt = HtmlTree.DT(label);
440 Content dl = HtmlTree.DL(dt);
441 dl.addContent(getClassLinks(LinkInfoImpl.CONTEXT_IMPLEMENTED_CLASSES,
442 implcl));
443 classInfoTree.addContent(dl);
444 }
445 }
447 /**
448 * {@inheritDoc}
449 */
450 public void addImplementedInterfacesInfo(Content classInfoTree) {
451 //NOTE: we really should be using ClassDoc.interfaceTypes() here, but
452 // it doesn't walk up the tree like we want it to.
453 List<Type> interfaceArray = Util.getAllInterfaces(classDoc, configuration);
454 if (classDoc.isClass() && interfaceArray.size() > 0) {
455 Content label = getResource(
456 "doclet.All_Implemented_Interfaces");
457 Content dt = HtmlTree.DT(label);
458 Content dl = HtmlTree.DL(dt);
459 dl.addContent(getClassLinks(LinkInfoImpl.CONTEXT_IMPLEMENTED_INTERFACES,
460 interfaceArray));
461 classInfoTree.addContent(dl);
462 }
463 }
465 /**
466 * {@inheritDoc}
467 */
468 public void addSuperInterfacesInfo(Content classInfoTree) {
469 //NOTE: we really should be using ClassDoc.interfaceTypes() here, but
470 // it doesn't walk up the tree like we want it to.
471 List<Type> interfaceArray = Util.getAllInterfaces(classDoc, configuration);
472 if (classDoc.isInterface() && interfaceArray.size() > 0) {
473 Content label = getResource(
474 "doclet.All_Superinterfaces");
475 Content dt = HtmlTree.DT(label);
476 Content dl = HtmlTree.DL(dt);
477 dl.addContent(getClassLinks(LinkInfoImpl.CONTEXT_SUPER_INTERFACES,
478 interfaceArray));
479 classInfoTree.addContent(dl);
480 }
481 }
483 /**
484 * {@inheritDoc}
485 */
486 public void addNestedClassInfo(Content classInfoTree) {
487 ClassDoc outerClass = classDoc.containingClass();
488 if (outerClass != null) {
489 Content label;
490 if (outerClass.isInterface()) {
491 label = getResource(
492 "doclet.Enclosing_Interface");
493 } else {
494 label = getResource(
495 "doclet.Enclosing_Class");
496 }
497 Content dt = HtmlTree.DT(label);
498 Content dl = HtmlTree.DL(dt);
499 Content dd = new HtmlTree(HtmlTag.DD);
500 dd.addContent(new RawHtml(getLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS, outerClass,
501 false))));
502 dl.addContent(dd);
503 classInfoTree.addContent(dl);
504 }
505 }
507 /**
508 * {@inheritDoc}
509 */
510 public void addClassDeprecationInfo(Content classInfoTree) {
511 Content hr = new HtmlTree(HtmlTag.HR);
512 classInfoTree.addContent(hr);
513 Tag[] deprs = classDoc.tags("deprecated");
514 if (Util.isDeprecated(classDoc)) {
515 Content strong = HtmlTree.STRONG(deprecatedPhrase);
516 Content div = HtmlTree.DIV(HtmlStyle.block, strong);
517 if (deprs.length > 0) {
518 Tag[] commentTags = deprs[0].inlineTags();
519 if (commentTags.length > 0) {
520 div.addContent(getSpace());
521 addInlineDeprecatedComment(classDoc, deprs[0], div);
522 }
523 }
524 classInfoTree.addContent(div);
525 }
526 }
528 /**
529 * Get links to the given classes.
530 *
531 * @param context the id of the context where the link will be printed
532 * @param list the list of classes
533 * @return a content tree for the class list
534 */
535 private Content getClassLinks(int context, List<?> list) {
536 Object[] typeList = list.toArray();
537 Content dd = new HtmlTree(HtmlTag.DD);
538 for (int i = 0; i < list.size(); i++) {
539 if (i > 0) {
540 Content separator = new StringContent(", ");
541 dd.addContent(separator);
542 }
543 if (typeList[i] instanceof ClassDoc) {
544 Content link = new RawHtml(getLink(
545 new LinkInfoImpl(context, (ClassDoc)(typeList[i]))));
546 dd.addContent(link);
547 } else {
548 Content link = new RawHtml(getLink(
549 new LinkInfoImpl(context, (Type)(typeList[i]))));
550 dd.addContent(link);
551 }
552 }
553 return dd;
554 }
556 /**
557 * {@inheritDoc}
558 */
559 protected Content getNavLinkTree() {
560 Content treeLinkContent = getHyperLink("package-tree.html",
561 "", treeLabel, "", "");
562 Content li = HtmlTree.LI(treeLinkContent);
563 return li;
564 }
566 /**
567 * Add summary details to the navigation bar.
568 *
569 * @param subDiv the content tree to which the summary detail links will be added
570 */
571 protected void addSummaryDetailLinks(Content subDiv) {
572 try {
573 Content div = HtmlTree.DIV(getNavSummaryLinks());
574 div.addContent(getNavDetailLinks());
575 subDiv.addContent(div);
576 } catch (Exception e) {
577 e.printStackTrace();
578 throw new DocletAbortException();
579 }
580 }
582 /**
583 * Get summary links for navigation bar.
584 *
585 * @return the content tree for the navigation summary links
586 */
587 protected Content getNavSummaryLinks() throws Exception {
588 Content li = HtmlTree.LI(summaryLabel);
589 li.addContent(getSpace());
590 Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
591 MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder)
592 configuration.getBuilderFactory().getMemberSummaryBuilder(this);
593 String[] navLinkLabels = new String[] {
594 "doclet.navNested", "doclet.navEnum", "doclet.navField", "doclet.navConstructor",
595 "doclet.navMethod"
596 };
597 for (int i = 0; i < navLinkLabels.length; i++ ) {
598 Content liNav = new HtmlTree(HtmlTag.LI);
599 if (i == VisibleMemberMap.ENUM_CONSTANTS && ! classDoc.isEnum()) {
600 continue;
601 }
602 if (i == VisibleMemberMap.CONSTRUCTORS && classDoc.isEnum()) {
603 continue;
604 }
605 AbstractMemberWriter writer =
606 ((AbstractMemberWriter) memberSummaryBuilder.
607 getMemberSummaryWriter(i));
608 if (writer == null) {
609 liNav.addContent(getResource(navLinkLabels[i]));
610 } else {
611 writer.addNavSummaryLink(
612 memberSummaryBuilder.members(i),
613 memberSummaryBuilder.getVisibleMemberMap(i), liNav);
614 }
615 if (i < navLinkLabels.length-1) {
616 addNavGap(liNav);
617 }
618 ulNav.addContent(liNav);
619 }
620 return ulNav;
621 }
623 /**
624 * Get detail links for the navigation bar.
625 *
626 * @return the content tree for the detail links
627 */
628 protected Content getNavDetailLinks() throws Exception {
629 Content li = HtmlTree.LI(detailLabel);
630 li.addContent(getSpace());
631 Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
632 MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder)
633 configuration.getBuilderFactory().getMemberSummaryBuilder(this);
634 String[] navLinkLabels = new String[] {
635 "doclet.navNested", "doclet.navEnum", "doclet.navField", "doclet.navConstructor",
636 "doclet.navMethod"
637 };
638 for (int i = 1; i < navLinkLabels.length; i++ ) {
639 Content liNav = new HtmlTree(HtmlTag.LI);
640 AbstractMemberWriter writer =
641 ((AbstractMemberWriter) memberSummaryBuilder.
642 getMemberSummaryWriter(i));
643 if (i == VisibleMemberMap.ENUM_CONSTANTS && ! classDoc.isEnum()) {
644 continue;
645 }
646 if (i == VisibleMemberMap.CONSTRUCTORS && classDoc.isEnum()) {
647 continue;
648 }
649 if (writer == null) {
650 liNav.addContent(getResource(navLinkLabels[i]));
651 } else {
652 writer.addNavDetailLink(memberSummaryBuilder.members(i), liNav);
653 }
654 if (i < navLinkLabels.length - 1) {
655 addNavGap(liNav);
656 }
657 ulNav.addContent(liNav);
658 }
659 return ulNav;
660 }
662 /**
663 * Add gap between navigation bar elements.
664 *
665 * @param liNav the content tree to which the gap will be added
666 */
667 protected void addNavGap(Content liNav) {
668 liNav.addContent(getSpace());
669 liNav.addContent("|");
670 liNav.addContent(getSpace());
671 }
673 /**
674 * Return the classDoc being documented.
675 *
676 * @return the classDoc being documented.
677 */
678 public ClassDoc getClassDoc() {
679 return classDoc;
680 }
681 }