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.*;
29 import java.lang.reflect.Modifier;
30 import com.sun.javadoc.*;
31 import com.sun.tools.doclets.formats.html.markup.*;
32 import com.sun.tools.doclets.internal.toolkit.*;
33 import com.sun.tools.doclets.internal.toolkit.util.*;
34 import com.sun.tools.doclets.internal.toolkit.taglets.*;
36 /**
37 * The base class for member writers.
38 *
39 * @author Robert Field
40 * @author Atul M Dambalkar
41 * @author Jamie Ho (Re-write)
42 * @author Bhavesh Patel (Modified)
43 */
44 public abstract class AbstractMemberWriter {
46 protected boolean printedSummaryHeader = false;
47 protected final SubWriterHolderWriter writer;
48 protected final ClassDoc classdoc;
49 public final boolean nodepr;
51 public AbstractMemberWriter(SubWriterHolderWriter writer,
52 ClassDoc classdoc) {
53 this.writer = writer;
54 this.nodepr = configuration().nodeprecated;
55 this.classdoc = classdoc;
56 }
58 public AbstractMemberWriter(SubWriterHolderWriter writer) {
59 this(writer, null);
60 }
62 /*** abstracts ***/
64 /**
65 * Add the summary label for the member.
66 *
67 * @param memberTree the content tree to which the label will be added
68 */
69 public abstract void addSummaryLabel(Content memberTree);
71 /**
72 * Get the summary for the member summary table.
73 *
74 * @return a string for the table summary
75 */
76 public abstract String getTableSummary();
78 /**
79 * Get the caption for the member summary table.
80 *
81 * @return a string for the table caption
82 */
83 public abstract String getCaption();
85 /**
86 * Get the summary table header for the member.
87 *
88 * @param member the member to be documented
89 * @return the summary table header
90 */
91 public abstract String[] getSummaryTableHeader(ProgramElementDoc member);
93 /**
94 * Add inherited summary lable for the member.
95 *
96 * @param cd the class doc to which to link to
97 * @param inheritedTree the content tree to which the inherited summary label will be added
98 */
99 public abstract void addInheritedSummaryLabel(ClassDoc cd, Content inheritedTree);
101 /**
102 * Add the anchor for the summary section of the member.
103 *
104 * @param cd the class doc to be documented
105 * @param memberTree the content tree to which the summary anchor will be added
106 */
107 public abstract void addSummaryAnchor(ClassDoc cd, Content memberTree);
109 /**
110 * Add the anchor for the inherited summary section of the member.
111 *
112 * @param cd the class doc to be documented
113 * @param inheritedTree the content tree to which the inherited summary anchor will be added
114 */
115 public abstract void addInheritedSummaryAnchor(ClassDoc cd, Content inheritedTree);
117 /**
118 * Add the summary type for the member.
119 *
120 * @param member the member to be documented
121 * @param tdSummaryType the content tree to which the type will be added
122 */
123 protected abstract void addSummaryType(ProgramElementDoc member,
124 Content tdSummaryType);
126 /**
127 * Add the summary link for the member.
128 *
129 * @param cd the class doc to be documented
130 * @param member the member to be documented
131 * @param tdSummary the content tree to which the link will be added
132 */
133 protected void addSummaryLink(ClassDoc cd, ProgramElementDoc member,
134 Content tdSummary) {
135 addSummaryLink(LinkInfoImpl.CONTEXT_MEMBER, cd, member, tdSummary);
136 }
138 /**
139 * Add the summary link for the member.
140 *
141 * @param context the id of the context where the link will be printed
142 * @param cd the class doc to be documented
143 * @param member the member to be documented
144 * @param tdSummary the content tree to which the summary link will be added
145 */
146 protected abstract void addSummaryLink(int context,
147 ClassDoc cd, ProgramElementDoc member, Content tdSummary);
149 /**
150 * Add the inherited summary link for the member.
151 *
152 * @param cd the class doc to be documented
153 * @param member the member to be documented
154 * @param linksTree the content tree to which the inherited summary link will be added
155 */
156 protected abstract void addInheritedSummaryLink(ClassDoc cd,
157 ProgramElementDoc member, Content linksTree);
159 /**
160 * Get the deprecated link.
161 *
162 * @param member the member being linked to
163 * @return a content tree representing the link
164 */
165 protected abstract Content getDeprecatedLink(ProgramElementDoc member);
167 /**
168 * Get the navigation summary link.
169 *
170 * @param cd the class doc to be documented
171 * @param link true if its a link else the label to be printed
172 * @return a content tree for the navigation summary link.
173 */
174 protected abstract Content getNavSummaryLink(ClassDoc cd, boolean link);
176 /**
177 * Add the navigation detail link.
178 *
179 * @param link true if its a link else the label to be printed
180 * @param liNav the content tree to which the navigation detail link will be added
181 */
182 protected abstract void addNavDetailLink(boolean link, Content liNav);
184 /*** ***/
186 protected void print(String str) {
187 writer.print(str);
188 writer.displayLength += str.length();
189 }
191 protected void print(char ch) {
192 writer.print(ch);
193 writer.displayLength++;
194 }
196 protected void strong(String str) {
197 writer.strong(str);
198 writer.displayLength += str.length();
199 }
201 /**
202 * Add the member name to the content tree and modifies the display length.
203 *
204 * @param name the member name to be added to the content tree.
205 * @param htmltree the content tree to which the name will be added.
206 */
207 protected void addName(String name, Content htmltree) {
208 htmltree.addContent(name);
209 writer.displayLength += name.length();
210 }
212 /**
213 * Return a string describing the access modifier flags.
214 * Don't include native or synchronized.
215 *
216 * The modifier names are returned in canonical order, as
217 * specified by <em>The Java Language Specification</em>.
218 */
219 protected String modifierString(MemberDoc member) {
220 int ms = member.modifierSpecifier();
221 int no = Modifier.NATIVE | Modifier.SYNCHRONIZED;
222 return Modifier.toString(ms & ~no);
223 }
225 protected String typeString(MemberDoc member) {
226 String type = "";
227 if (member instanceof MethodDoc) {
228 type = ((MethodDoc)member).returnType().toString();
229 } else if (member instanceof FieldDoc) {
230 type = ((FieldDoc)member).type().toString();
231 }
232 return type;
233 }
235 /**
236 * Add the modifier for the member.
237 *
238 * @param member the member for which teh modifier will be added.
239 * @param htmltree the content tree to which the modifier information will be added.
240 */
241 protected void addModifiers(MemberDoc member, Content htmltree) {
242 String mod = modifierString(member);
243 // According to JLS, we should not be showing public modifier for
244 // interface methods.
245 if ((member.isField() || member.isMethod()) &&
246 writer instanceof ClassWriterImpl &&
247 ((ClassWriterImpl) writer).getClassDoc().isInterface()) {
248 mod = Util.replaceText(mod, "public", "").trim();
249 }
250 if(mod.length() > 0) {
251 htmltree.addContent(mod);
252 htmltree.addContent(writer.getSpace());
253 }
254 }
256 protected String makeSpace(int len) {
257 if (len <= 0) {
258 return "";
259 }
260 StringBuffer sb = new StringBuffer(len);
261 for(int i = 0; i < len; i++) {
262 sb.append(' ');
263 }
264 return sb.toString();
265 }
267 /**
268 * Add the modifier and type for the member in the member summary.
269 *
270 * @param member the member to add the type for
271 * @param type the type to add
272 * @param tdSummaryType the content tree to which the modified and type will be added
273 */
274 protected void addModifierAndType(ProgramElementDoc member, Type type,
275 Content tdSummaryType) {
276 HtmlTree code = new HtmlTree(HtmlTag.CODE);
277 addModifier(member, code);
278 if (type == null) {
279 if (member.isClass()) {
280 code.addContent("class");
281 } else {
282 code.addContent("interface");
283 }
284 code.addContent(writer.getSpace());
285 } else {
286 if (member instanceof ExecutableMemberDoc &&
287 ((ExecutableMemberDoc) member).typeParameters().length > 0) {
288 //Code to avoid ugly wrapping in member summary table.
289 int displayLength = ((AbstractExecutableMemberWriter) this).addTypeParameters(
290 (ExecutableMemberDoc) member, code);
291 if (displayLength > 10) {
292 code.addContent(new HtmlTree(HtmlTag.BR));
293 }
294 code.addContent(new RawHtml(
295 writer.getLink(new LinkInfoImpl(
296 LinkInfoImpl.CONTEXT_SUMMARY_RETURN_TYPE, type))));
297 } else {
298 code.addContent(new RawHtml(
299 writer.getLink(new LinkInfoImpl(
300 LinkInfoImpl.CONTEXT_SUMMARY_RETURN_TYPE, type))));
301 }
303 }
304 tdSummaryType.addContent(code);
305 }
307 private void printModifier(ProgramElementDoc member) {
308 if (member.isProtected()) {
309 print("protected ");
310 } else if (member.isPrivate()) {
311 print("private ");
312 } else if (!member.isPublic()) { // Package private
313 writer.printText("doclet.Package_private");
314 print(" ");
315 }
316 if (member.isMethod() && ((MethodDoc)member).isAbstract()) {
317 print("abstract ");
318 }
319 if (member.isStatic()) {
320 print("static");
321 }
322 }
324 /**
325 * Add the modifier for the member.
326 *
327 * @param member the member to add the type for
328 * @param code the content tree to which the modified will be added
329 */
330 private void addModifier(ProgramElementDoc member, Content code) {
331 if (member.isProtected()) {
332 code.addContent("protected ");
333 } else if (member.isPrivate()) {
334 code.addContent("private ");
335 } else if (!member.isPublic()) { // Package private
336 code.addContent(configuration().getText("doclet.Package_private"));
337 code.addContent(" ");
338 }
339 if (member.isMethod() && ((MethodDoc)member).isAbstract()) {
340 code.addContent("abstract ");
341 }
342 if (member.isStatic()) {
343 code.addContent("static ");
344 }
345 }
347 /**
348 * Add the deprecated information for the given member.
349 *
350 * @param member the member being documented.
351 * @param contentTree the content tree to which the deprecated information will be added.
352 */
353 protected void addDeprecatedInfo(ProgramElementDoc member, Content contentTree) {
354 String output = (new DeprecatedTaglet()).getTagletOutput(member,
355 writer.getTagletWriterInstance(false)).toString().trim();
356 if (!output.isEmpty()) {
357 Content deprecatedContent = new RawHtml(output);
358 Content div = HtmlTree.DIV(HtmlStyle.block, deprecatedContent);
359 contentTree.addContent(div);
360 }
361 }
363 /**
364 * Add the comment for the given member.
365 *
366 * @param member the member being documented.
367 * @param contentTree the content tree to which the comment will be added.
368 */
369 protected void addComment(ProgramElementDoc member, Content htmltree) {
370 if (member.inlineTags().length > 0) {
371 writer.addInlineComment(member, htmltree);
372 }
373 }
375 protected String name(ProgramElementDoc member) {
376 return member.name();
377 }
379 /**
380 * Get the header for the section.
381 *
382 * @param member the member being documented.
383 * @return a header content for the section.
384 */
385 protected Content getHead(MemberDoc member) {
386 Content memberContent = new RawHtml(member.name());
387 Content heading = HtmlTree.HEADING(HtmlConstants.MEMBER_HEADING, memberContent);
388 return heading;
389 }
391 /**
392 * Return true if the given <code>ProgramElement</code> is inherited
393 * by the class that is being documented.
394 *
395 * @param ped The <code>ProgramElement</code> being checked.
396 * return true if the <code>ProgramElement</code> is being inherited and
397 * false otherwise.
398 */
399 protected boolean isInherited(ProgramElementDoc ped){
400 if(ped.isPrivate() || (ped.isPackagePrivate() &&
401 ! ped.containingPackage().equals(classdoc.containingPackage()))){
402 return false;
403 }
404 return true;
405 }
407 /**
408 * Add deprecated information to the documentation tree
409 *
410 * @param deprmembers list of deprecated members
411 * @param headingKey the caption for the deprecated members table
412 * @param tableSummary the summary for the deprecated members table
413 * @param tableHeader table headers for the deprecated members table
414 * @param contentTree the content tree to which the deprecated members table will be added
415 */
416 protected void addDeprecatedAPI(List<Doc> deprmembers, String headingKey,
417 String tableSummary, String[] tableHeader, Content contentTree) {
418 if (deprmembers.size() > 0) {
419 Content table = HtmlTree.TABLE(0, 3, 0, tableSummary,
420 writer.getTableCaption(configuration().getText(headingKey)));
421 table.addContent(writer.getSummaryTableHeader(tableHeader, "col"));
422 Content tbody = new HtmlTree(HtmlTag.TBODY);
423 for (int i = 0; i < deprmembers.size(); i++) {
424 ProgramElementDoc member =(ProgramElementDoc)deprmembers.get(i);
425 HtmlTree td = HtmlTree.TD(HtmlStyle.colOne, getDeprecatedLink(member));
426 if (member.tags("deprecated").length > 0)
427 writer.addInlineDeprecatedComment(member,
428 member.tags("deprecated")[0], td);
429 HtmlTree tr = HtmlTree.TR(td);
430 if (i%2 == 0)
431 tr.addStyle(HtmlStyle.altColor);
432 else
433 tr.addStyle(HtmlStyle.rowColor);
434 tbody.addContent(tr);
435 }
436 table.addContent(tbody);
437 Content li = HtmlTree.LI(HtmlStyle.blockList, table);
438 Content ul = HtmlTree.UL(HtmlStyle.blockList, li);
439 contentTree.addContent(ul);
440 }
441 }
443 /**
444 * Add use information to the documentation tree.
445 *
446 * @param mems list of program elements for which the use information will be added
447 * @param heading the section heading
448 * @param tableSummary the summary for the use table
449 * @param contentTree the content tree to which the use information will be added
450 */
451 protected void addUseInfo(List<? extends ProgramElementDoc> mems,
452 String heading, String tableSummary, Content contentTree) {
453 if (mems == null) {
454 return;
455 }
456 List<? extends ProgramElementDoc> members = mems;
457 boolean printedUseTableHeader = false;
458 if (members.size() > 0) {
459 Content table = HtmlTree.TABLE(0, 3, 0, tableSummary,
460 writer.getTableCaption(heading));
461 Content tbody = new HtmlTree(HtmlTag.TBODY);
462 Iterator<? extends ProgramElementDoc> it = members.iterator();
463 for (int i = 0; it.hasNext(); i++) {
464 ProgramElementDoc pgmdoc = it.next();
465 ClassDoc cd = pgmdoc.containingClass();
466 if (!printedUseTableHeader) {
467 table.addContent(writer.getSummaryTableHeader(
468 this.getSummaryTableHeader(pgmdoc), "col"));
469 printedUseTableHeader = true;
470 }
471 HtmlTree tr = new HtmlTree(HtmlTag.TR);
472 if (i % 2 == 0) {
473 tr.addStyle(HtmlStyle.altColor);
474 } else {
475 tr.addStyle(HtmlStyle.rowColor);
476 }
477 HtmlTree tdFirst = new HtmlTree(HtmlTag.TD);
478 tdFirst.addStyle(HtmlStyle.colFirst);
479 writer.addSummaryType(this, pgmdoc, tdFirst);
480 tr.addContent(tdFirst);
481 HtmlTree tdLast = new HtmlTree(HtmlTag.TD);
482 tdLast.addStyle(HtmlStyle.colLast);
483 if (cd != null && !(pgmdoc instanceof ConstructorDoc)
484 && !(pgmdoc instanceof ClassDoc)) {
485 HtmlTree name = new HtmlTree(HtmlTag.SPAN);
486 name.addStyle(HtmlStyle.strong);
487 name.addContent(cd.name() + ".");
488 tdLast.addContent(name);
489 }
490 addSummaryLink(pgmdoc instanceof ClassDoc ?
491 LinkInfoImpl.CONTEXT_CLASS_USE : LinkInfoImpl.CONTEXT_MEMBER,
492 cd, pgmdoc, tdLast);
493 writer.addSummaryLinkComment(this, pgmdoc, tdLast);
494 tr.addContent(tdLast);
495 tbody.addContent(tr);
496 }
497 table.addContent(tbody);
498 contentTree.addContent(table);
499 }
500 }
502 /**
503 * Add the navigation detail link.
504 *
505 * @param members the members to be linked
506 * @param liNav the content tree to which the navigation detail link will be added
507 */
508 protected void addNavDetailLink(List<?> members, Content liNav) {
509 addNavDetailLink(members.size() > 0 ? true : false, liNav);
510 }
512 /**
513 * Add the navigation summary link.
514 *
515 * @param members members to be linked
516 * @param visibleMemberMap the visible inherited members map
517 * @param liNav the content tree to which the navigation summary link will be added
518 */
519 protected void addNavSummaryLink(List<?> members,
520 VisibleMemberMap visibleMemberMap, Content liNav) {
521 if (members.size() > 0) {
522 liNav.addContent(getNavSummaryLink(null, true));
523 return;
524 }
525 ClassDoc icd = classdoc.superclass();
526 while (icd != null) {
527 List<?> inhmembers = visibleMemberMap.getMembersFor(icd);
528 if (inhmembers.size() > 0) {
529 liNav.addContent(getNavSummaryLink(icd, true));
530 return;
531 }
532 icd = icd.superclass();
533 }
534 liNav.addContent(getNavSummaryLink(null, false));
535 }
537 protected void serialWarning(SourcePosition pos, String key, String a1, String a2) {
538 if (configuration().serialwarn) {
539 ConfigurationImpl.getInstance().getDocletSpecificMsg().warning(pos, key, a1, a2);
540 }
541 }
543 public ProgramElementDoc[] eligibleMembers(ProgramElementDoc[] members) {
544 return nodepr? Util.excludeDeprecatedMembers(members): members;
545 }
547 public ConfigurationImpl configuration() {
548 return writer.configuration;
549 }
551 /**
552 * Add the member summary for the given class.
553 *
554 * @param classDoc the class that is being documented
555 * @param member the member being documented
556 * @param firstSentenceTags the first sentence tags to be added to the summary
557 * @param tableTree the content tree to which the documentation will be added
558 * @param counter the counter for determing style for the table row
559 */
560 public void addMemberSummary(ClassDoc classDoc, ProgramElementDoc member,
561 Tag[] firstSentenceTags, Content tableTree, int counter) {
562 HtmlTree tdSummaryType = new HtmlTree(HtmlTag.TD);
563 tdSummaryType.addStyle(HtmlStyle.colFirst);
564 writer.addSummaryType(this, member, tdSummaryType);
565 HtmlTree tdSummary = new HtmlTree(HtmlTag.TD);
566 setSummaryColumnStyle(tdSummary);
567 addSummaryLink(classDoc, member, tdSummary);
568 writer.addSummaryLinkComment(this, member, firstSentenceTags, tdSummary);
569 HtmlTree tr = HtmlTree.TR(tdSummaryType);
570 tr.addContent(tdSummary);
571 if (counter%2 == 0)
572 tr.addStyle(HtmlStyle.altColor);
573 else
574 tr.addStyle(HtmlStyle.rowColor);
575 tableTree.addContent(tr);
576 }
578 /**
579 * Set the style for the summary column.
580 *
581 * @param tdTree the column for which the style will be set
582 */
583 public void setSummaryColumnStyle(HtmlTree tdTree) {
584 tdTree.addStyle(HtmlStyle.colLast);
585 }
587 /**
588 * Add inherited member summary for the given class and member.
589 *
590 * @param classDoc the class the inherited member belongs to
591 * @param nestedClass the inherited member that is summarized
592 * @param isFirst true if this is the first member in the list
593 * @param isLast true if this is the last member in the list
594 * @param linksTree the content tree to which the summary will be added
595 */
596 public void addInheritedMemberSummary(ClassDoc classDoc,
597 ProgramElementDoc nestedClass, boolean isFirst, boolean isLast,
598 Content linksTree) {
599 writer.addInheritedMemberSummary(this, classDoc, nestedClass, isFirst,
600 linksTree);
601 }
603 /**
604 * Get the inherited summary header for the given class.
605 *
606 * @param classDoc the class the inherited member belongs to
607 * @return a content tree for the inherited summary header
608 */
609 public Content getInheritedSummaryHeader(ClassDoc classDoc) {
610 Content inheritedTree = writer.getMemberTreeHeader();
611 writer.addInheritedSummaryHeader(this, classDoc, inheritedTree);
612 return inheritedTree;
613 }
615 /**
616 * Get the inherited summary links tree.
617 *
618 * @return a content tree for the inherited summary links
619 */
620 public Content getInheritedSummaryLinksTree() {
621 return new HtmlTree(HtmlTag.CODE);
622 }
624 /**
625 * Get the summary table tree for the given class.
626 *
627 * @param classDoc the class for which the summary table is generated
628 * @return a content tree for the summary table
629 */
630 public Content getSummaryTableTree(ClassDoc classDoc) {
631 return writer.getSummaryTableTree(this, classDoc);
632 }
634 /**
635 * Get the member tree to be documented.
636 *
637 * @param memberTree the content tree of member to be documented
638 * @return a content tree that will be added to the class documentation
639 */
640 public Content getMemberTree(Content memberTree) {
641 return writer.getMemberTree(memberTree);
642 }
644 /**
645 * Get the member tree to be documented.
646 *
647 * @param memberTree the content tree of member to be documented
648 * @param isLastContent true if the content to be added is the last content
649 * @return a content tree that will be added to the class documentation
650 */
651 public Content getMemberTree(Content memberTree, boolean isLastContent) {
652 if (isLastContent)
653 return HtmlTree.UL(HtmlStyle.blockListLast, memberTree);
654 else
655 return HtmlTree.UL(HtmlStyle.blockList, memberTree);
656 }
657 }