1/* 2 * Copyright (c) 2003, 2015, 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 */ 25 26package com.sun.tools.doclets.internal.toolkit.builders; 27 28import java.util.*; 29import java.text.MessageFormat; 30 31import com.sun.javadoc.*; 32import com.sun.tools.doclets.internal.toolkit.*; 33import com.sun.tools.doclets.internal.toolkit.util.*; 34 35/** 36 * Builds the member summary. 37 * 38 * <p><b>This is NOT part of any supported API. 39 * If you write code that depends on this, you do so at your own risk. 40 * This code and its internal interfaces are subject to change or 41 * deletion without notice.</b> 42 * 43 * @author Jamie Ho 44 * @author Bhavesh Patel (Modified) 45 * @since 1.5 46 */ 47@Deprecated 48public class MemberSummaryBuilder extends AbstractMemberBuilder { 49 50 /** 51 * The XML root for this builder. 52 */ 53 public static final String NAME = "MemberSummary"; 54 55 /** 56 * The visible members for the given class. 57 */ 58 private final VisibleMemberMap[] visibleMemberMaps; 59 60 /** 61 * The member summary writers for the given class. 62 */ 63 private MemberSummaryWriter[] memberSummaryWriters; 64 65 /** 66 * The type being documented. 67 */ 68 private final ClassDoc classDoc; 69 70 /** 71 * Construct a new MemberSummaryBuilder. 72 * 73 * @param classWriter the writer for the class whose members are being 74 * summarized. 75 * @param context the build context. 76 */ 77 private MemberSummaryBuilder(Context context, ClassDoc classDoc) { 78 super(context); 79 this.classDoc = classDoc; 80 visibleMemberMaps = 81 new VisibleMemberMap[VisibleMemberMap.NUM_MEMBER_TYPES]; 82 for (int i = 0; i < VisibleMemberMap.NUM_MEMBER_TYPES; i++) { 83 visibleMemberMaps[i] = 84 new VisibleMemberMap( 85 classDoc, 86 i, 87 configuration); 88 } 89 } 90 91 /** 92 * Construct a new MemberSummaryBuilder. 93 * 94 * @param classWriter the writer for the class whose members are being 95 * summarized. 96 * @param context the build context. 97 */ 98 public static MemberSummaryBuilder getInstance( 99 ClassWriter classWriter, Context context) 100 throws Exception { 101 MemberSummaryBuilder builder = new MemberSummaryBuilder(context, 102 classWriter.getClassDoc()); 103 builder.memberSummaryWriters = 104 new MemberSummaryWriter[VisibleMemberMap.NUM_MEMBER_TYPES]; 105 WriterFactory wf = context.configuration.getWriterFactory(); 106 for (int i = 0; i < VisibleMemberMap.NUM_MEMBER_TYPES; i++) { 107 builder.memberSummaryWriters[i] = 108 builder.visibleMemberMaps[i].noVisibleMembers() ? 109 null : 110 wf.getMemberSummaryWriter(classWriter, i); 111 } 112 return builder; 113 } 114 115 /** 116 * Construct a new MemberSummaryBuilder. 117 * 118 * @param annotationTypeWriter the writer for the class whose members are 119 * being summarized. 120 * @param configuration the current configuration of the doclet. 121 */ 122 public static MemberSummaryBuilder getInstance( 123 AnnotationTypeWriter annotationTypeWriter, Context context) 124 throws Exception { 125 MemberSummaryBuilder builder = new MemberSummaryBuilder(context, 126 annotationTypeWriter.getAnnotationTypeDoc()); 127 builder.memberSummaryWriters = 128 new MemberSummaryWriter[VisibleMemberMap.NUM_MEMBER_TYPES]; 129 WriterFactory wf = context.configuration.getWriterFactory(); 130 for (int i = 0; i < VisibleMemberMap.NUM_MEMBER_TYPES; i++) { 131 builder.memberSummaryWriters[i] = 132 builder.visibleMemberMaps[i].noVisibleMembers()? 133 null : 134 wf.getMemberSummaryWriter( 135 annotationTypeWriter, i); 136 } 137 return builder; 138 } 139 140 /** 141 * {@inheritDoc} 142 */ 143 public String getName() { 144 return NAME; 145 } 146 147 /** 148 * Return the specified visible member map. 149 * 150 * @param type the type of visible member map to return. 151 * @return the specified visible member map. 152 * @throws ArrayIndexOutOfBoundsException when the type is invalid. 153 * @see VisibleMemberMap 154 */ 155 public VisibleMemberMap getVisibleMemberMap(int type) { 156 return visibleMemberMaps[type]; 157 } 158 159 /** 160 * Return the specified member summary writer. 161 * 162 * @param type the type of member summary writer to return. 163 * @return the specified member summary writer. 164 * @throws ArrayIndexOutOfBoundsException when the type is invalid. 165 * @see VisibleMemberMap 166 */ 167 public MemberSummaryWriter getMemberSummaryWriter(int type) { 168 return memberSummaryWriters[type]; 169 } 170 171 /** 172 * Returns a list of methods that will be documented for the given class. 173 * This information can be used for doclet specific documentation 174 * generation. 175 * 176 * @param type the type of members to return. 177 * @return a list of methods that will be documented. 178 * @see VisibleMemberMap 179 */ 180 public List<ProgramElementDoc> members(int type) { 181 return visibleMemberMaps[type].getLeafClassMembers(configuration); 182 } 183 184 /** 185 * Return true it there are any members to summarize. 186 * 187 * @return true if there are any members to summarize. 188 */ 189 public boolean hasMembersToDocument() { 190 if (classDoc instanceof AnnotationTypeDoc) { 191 return ((AnnotationTypeDoc) classDoc).elements().length > 0; 192 } 193 for (int i = 0; i < VisibleMemberMap.NUM_MEMBER_TYPES; i++) { 194 VisibleMemberMap members = visibleMemberMaps[i]; 195 if (!members.noVisibleMembers()) { 196 return true; 197 } 198 } 199 return false; 200 } 201 202 /** 203 * Build the summary for the enum constants. 204 * 205 * @param node the XML element that specifies which components to document 206 * @param memberSummaryTree the content tree to which the documentation will be added 207 */ 208 public void buildEnumConstantsSummary(XMLNode node, Content memberSummaryTree) { 209 MemberSummaryWriter writer = 210 memberSummaryWriters[VisibleMemberMap.ENUM_CONSTANTS]; 211 VisibleMemberMap visibleMemberMap = 212 visibleMemberMaps[VisibleMemberMap.ENUM_CONSTANTS]; 213 addSummary(writer, visibleMemberMap, false, memberSummaryTree); 214 } 215 216 /** 217 * Build the summary for fields. 218 * 219 * @param node the XML element that specifies which components to document 220 * @param memberSummaryTree the content tree to which the documentation will be added 221 */ 222 public void buildAnnotationTypeFieldsSummary(XMLNode node, Content memberSummaryTree) { 223 MemberSummaryWriter writer = 224 memberSummaryWriters[VisibleMemberMap.ANNOTATION_TYPE_FIELDS]; 225 VisibleMemberMap visibleMemberMap = 226 visibleMemberMaps[VisibleMemberMap.ANNOTATION_TYPE_FIELDS]; 227 addSummary(writer, visibleMemberMap, false, memberSummaryTree); 228 } 229 230 /** 231 * Build the summary for the optional members. 232 * 233 * @param node the XML element that specifies which components to document 234 * @param memberSummaryTree the content tree to which the documentation will be added 235 */ 236 public void buildAnnotationTypeOptionalMemberSummary(XMLNode node, Content memberSummaryTree) { 237 MemberSummaryWriter writer = 238 memberSummaryWriters[VisibleMemberMap.ANNOTATION_TYPE_MEMBER_OPTIONAL]; 239 VisibleMemberMap visibleMemberMap = 240 visibleMemberMaps[VisibleMemberMap.ANNOTATION_TYPE_MEMBER_OPTIONAL]; 241 addSummary(writer, visibleMemberMap, false, memberSummaryTree); 242 } 243 244 /** 245 * Build the summary for the optional members. 246 * 247 * @param node the XML element that specifies which components to document 248 * @param memberSummaryTree the content tree to which the documentation will be added 249 */ 250 public void buildAnnotationTypeRequiredMemberSummary(XMLNode node, Content memberSummaryTree) { 251 MemberSummaryWriter writer = 252 memberSummaryWriters[VisibleMemberMap.ANNOTATION_TYPE_MEMBER_REQUIRED]; 253 VisibleMemberMap visibleMemberMap = 254 visibleMemberMaps[VisibleMemberMap.ANNOTATION_TYPE_MEMBER_REQUIRED]; 255 addSummary(writer, visibleMemberMap, false, memberSummaryTree); 256 } 257 258 /** 259 * Build the summary for the fields. 260 * 261 * @param node the XML element that specifies which components to document 262 * @param memberSummaryTree the content tree to which the documentation will be added 263 */ 264 public void buildFieldsSummary(XMLNode node, Content memberSummaryTree) { 265 MemberSummaryWriter writer = 266 memberSummaryWriters[VisibleMemberMap.FIELDS]; 267 VisibleMemberMap visibleMemberMap = 268 visibleMemberMaps[VisibleMemberMap.FIELDS]; 269 addSummary(writer, visibleMemberMap, true, memberSummaryTree); 270 } 271 272 /** 273 * Build the summary for the fields. 274 */ 275 public void buildPropertiesSummary(XMLNode node, Content memberSummaryTree) { 276 MemberSummaryWriter writer = 277 memberSummaryWriters[VisibleMemberMap.PROPERTIES]; 278 VisibleMemberMap visibleMemberMap = 279 visibleMemberMaps[VisibleMemberMap.PROPERTIES]; 280 addSummary(writer, visibleMemberMap, true, memberSummaryTree); 281 } 282 283 /** 284 * Build the summary for the nested classes. 285 * 286 * @param node the XML element that specifies which components to document 287 * @param memberSummaryTree the content tree to which the documentation will be added 288 */ 289 public void buildNestedClassesSummary(XMLNode node, Content memberSummaryTree) { 290 MemberSummaryWriter writer = 291 memberSummaryWriters[VisibleMemberMap.INNERCLASSES]; 292 VisibleMemberMap visibleMemberMap = 293 visibleMemberMaps[VisibleMemberMap.INNERCLASSES]; 294 addSummary(writer, visibleMemberMap, true, memberSummaryTree); 295 } 296 297 /** 298 * Build the method summary. 299 * 300 * @param node the XML element that specifies which components to document 301 * @param memberSummaryTree the content tree to which the documentation will be added 302 */ 303 public void buildMethodsSummary(XMLNode node, Content memberSummaryTree) { 304 MemberSummaryWriter writer = 305 memberSummaryWriters[VisibleMemberMap.METHODS]; 306 VisibleMemberMap visibleMemberMap = 307 visibleMemberMaps[VisibleMemberMap.METHODS]; 308 addSummary(writer, visibleMemberMap, true, memberSummaryTree); 309 } 310 311 /** 312 * Build the constructor summary. 313 * 314 * @param node the XML element that specifies which components to document 315 * @param memberSummaryTree the content tree to which the documentation will be added 316 */ 317 public void buildConstructorsSummary(XMLNode node, Content memberSummaryTree) { 318 MemberSummaryWriter writer = 319 memberSummaryWriters[VisibleMemberMap.CONSTRUCTORS]; 320 VisibleMemberMap visibleMemberMap = 321 visibleMemberMaps[VisibleMemberMap.CONSTRUCTORS]; 322 addSummary(writer, visibleMemberMap, false, memberSummaryTree); 323 } 324 325 /** 326 * Build the member summary for the given members. 327 * 328 * @param writer the summary writer to write the output. 329 * @param visibleMemberMap the given members to summarize. 330 * @param summaryTreeList list of content trees to which the documentation will be added 331 */ 332 private void buildSummary(MemberSummaryWriter writer, 333 VisibleMemberMap visibleMemberMap, LinkedList<Content> summaryTreeList) { 334 List<ProgramElementDoc> members = new ArrayList<>(visibleMemberMap.getLeafClassMembers( 335 configuration)); 336 if (members.size() > 0) { 337 Collections.sort(members); 338 List<Content> tableContents = new LinkedList<>(); 339 for (int i = 0; i < members.size(); i++) { 340 ProgramElementDoc member = members.get(i); 341 final ProgramElementDoc propertyDoc = 342 visibleMemberMap.getPropertyMemberDoc(member); 343 if (propertyDoc != null) { 344 processProperty(visibleMemberMap, member, propertyDoc); 345 } 346 Tag[] firstSentenceTags = member.firstSentenceTags(); 347 if (member instanceof MethodDoc && firstSentenceTags.length == 0) { 348 //Inherit comments from overriden or implemented method if 349 //necessary. 350 DocFinder.Output inheritedDoc = 351 DocFinder.search(configuration, new DocFinder.Input((MethodDoc) member)); 352 if (inheritedDoc.holder != null 353 && inheritedDoc.holder.firstSentenceTags().length > 0) { 354 firstSentenceTags = inheritedDoc.holder.firstSentenceTags(); 355 } 356 } 357 writer.addMemberSummary(classDoc, member, firstSentenceTags, 358 tableContents, i); 359 } 360 summaryTreeList.add(writer.getSummaryTableTree(classDoc, tableContents)); 361 } 362 } 363 364 /** 365 * Process the property method, property setter and/or property getter 366 * comment text so that it contains the documentation from 367 * the property field. The method adds the leading sentence, 368 * copied documentation including the defaultValue tag and 369 * the see tags if the appropriate property getter and setter are 370 * available. 371 * 372 * @param visibleMemberMap the members information. 373 * @param member the member which is to be augmented. 374 * @param propertyDoc the original property documentation. 375 */ 376 private void processProperty(VisibleMemberMap visibleMemberMap, 377 ProgramElementDoc member, 378 ProgramElementDoc propertyDoc) { 379 StringBuilder commentTextBuilder = new StringBuilder(); 380 final boolean isSetter = isSetter(member); 381 final boolean isGetter = isGetter(member); 382 if (isGetter || isSetter) { 383 //add "[GS]ets the value of the property PROPERTY_NAME." 384 if (isSetter) { 385 commentTextBuilder.append( 386 MessageFormat.format( 387 configuration.getText("doclet.PropertySetterWithName"), 388 utils.propertyNameFromMethodName(configuration, member.name()))); 389 } 390 if (isGetter) { 391 commentTextBuilder.append( 392 MessageFormat.format( 393 configuration.getText("doclet.PropertyGetterWithName"), 394 utils.propertyNameFromMethodName(configuration, member.name()))); 395 } 396 if (propertyDoc.commentText() != null 397 && !propertyDoc.commentText().isEmpty()) { 398 commentTextBuilder.append(" \n @propertyDescription "); 399 } 400 } 401 commentTextBuilder.append(propertyDoc.commentText()); 402 403 // copy certain tags 404 List<Tag> allTags = new LinkedList<>(); 405 String[] tagNames = {"@defaultValue", "@since"}; 406 for (String tagName: tagNames) { 407 Tag[] tags = propertyDoc.tags(tagName); 408 if (tags != null) { 409 allTags.addAll(Arrays.asList(tags)); 410 } 411 } 412 for (Tag tag: allTags) { 413 commentTextBuilder.append("\n") 414 .append(tag.name()) 415 .append(" ") 416 .append(tag.text()); 417 } 418 419 //add @see tags 420 if (!isGetter && !isSetter) { 421 MethodDoc getter = (MethodDoc) visibleMemberMap.getGetterForProperty(member); 422 MethodDoc setter = (MethodDoc) visibleMemberMap.getSetterForProperty(member); 423 424 if ((null != getter) 425 && (commentTextBuilder.indexOf("@see #" + getter.name()) == -1)) { 426 commentTextBuilder.append("\n @see #") 427 .append(getter.name()) 428 .append("() "); 429 } 430 431 if ((null != setter) 432 && (commentTextBuilder.indexOf("@see #" + setter.name()) == -1)) { 433 String typeName = setter.parameters()[0].typeName(); 434 // Removal of type parameters and package information. 435 typeName = typeName.split("<")[0]; 436 if (typeName.contains(".")) { 437 typeName = typeName.substring(typeName.lastIndexOf(".") + 1); 438 } 439 commentTextBuilder.append("\n @see #").append(setter.name()); 440 441 if (setter.parameters()[0].type().asTypeVariable() == null) { 442 commentTextBuilder.append("(").append(typeName).append(")"); 443 } 444 commentTextBuilder.append(" \n"); 445 } 446 } 447 member.setRawCommentText(commentTextBuilder.toString()); 448 } 449 /** 450 * Test whether the method is a getter. 451 * @param ped property method documentation. Needs to be either property 452 * method, property getter, or property setter. 453 * @return true if the given documentation belongs to a getter. 454 */ 455 private boolean isGetter(ProgramElementDoc ped) { 456 final String pedName = ped.name(); 457 return pedName.startsWith("get") || pedName.startsWith("is"); 458 } 459 460 /** 461 * Test whether the method is a setter. 462 * @param ped property method documentation. Needs to be either property 463 * method, property getter, or property setter. 464 * @return true if the given documentation belongs to a setter. 465 */ 466 private boolean isSetter(ProgramElementDoc ped) { 467 return ped.name().startsWith("set"); 468 } 469 470 /** 471 * Build the inherited member summary for the given methods. 472 * 473 * @param writer the writer for this member summary. 474 * @param visibleMemberMap the map for the members to document. 475 * @param summaryTreeList list of content trees to which the documentation will be added 476 */ 477 private void buildInheritedSummary(MemberSummaryWriter writer, 478 VisibleMemberMap visibleMemberMap, LinkedList<Content> summaryTreeList) { 479 for (ClassDoc inhclass : visibleMemberMap.getVisibleClassesList()) { 480 if (!(inhclass.isPublic() || 481 utils.isLinkable(inhclass, configuration))) { 482 continue; 483 } 484 if (inhclass == classDoc) { 485 continue; 486 } 487 List<ProgramElementDoc> inhmembers = visibleMemberMap.getMembersFor(inhclass); 488 if (inhmembers.size() > 0) { 489 Collections.sort(inhmembers); 490 Content inheritedTree = writer.getInheritedSummaryHeader(inhclass); 491 Content linksTree = writer.getInheritedSummaryLinksTree(); 492 for (int j = 0; j < inhmembers.size(); ++j) { 493 writer.addInheritedMemberSummary( 494 inhclass.isPackagePrivate() && 495 !utils.isLinkable(inhclass, configuration) ? 496 classDoc : inhclass, 497 inhmembers.get(j), 498 j == 0, 499 j == inhmembers.size() - 1, linksTree); 500 } 501 inheritedTree.addContent(linksTree); 502 summaryTreeList.add(writer.getMemberTree(inheritedTree)); 503 } 504 } 505 } 506 507 /** 508 * Add the summary for the documentation. 509 * 510 * @param writer the writer for this member summary. 511 * @param visibleMemberMap the map for the members to document. 512 * @param showInheritedSummary true if inherited summary should be documented 513 * @param memberSummaryTree the content tree to which the documentation will be added 514 */ 515 private void addSummary(MemberSummaryWriter writer, 516 VisibleMemberMap visibleMemberMap, boolean showInheritedSummary, 517 Content memberSummaryTree) { 518 LinkedList<Content> summaryTreeList = new LinkedList<>(); 519 buildSummary(writer, visibleMemberMap, summaryTreeList); 520 if (showInheritedSummary) 521 buildInheritedSummary(writer, visibleMemberMap, summaryTreeList); 522 if (!summaryTreeList.isEmpty()) { 523 Content memberTree = writer.getMemberSummaryHeader( 524 classDoc, memberSummaryTree); 525 for (Content aSummaryTreeList : summaryTreeList) { 526 memberTree.addContent(aSummaryTreeList); 527 } 528 writer.addMemberTree(memberSummaryTree, memberTree); 529 } 530 } 531} 532