1 /* 2 * Copyright (c) 1998, 2019, 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 26 package jdk.javadoc.internal.doclets.formats.html; 27 28 import jdk.javadoc.internal.doclets.formats.html.markup.Table; 29 30 import java.util.ArrayList; 31 import java.util.Collections; 32 import java.util.HashMap; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.Set; 36 import java.util.SortedSet; 37 import java.util.TreeSet; 38 39 import javax.lang.model.element.Element; 40 import javax.lang.model.element.PackageElement; 41 import javax.lang.model.element.TypeElement; 42 import javax.tools.Diagnostic; 43 44 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; 45 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; 46 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; 47 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; 48 import jdk.javadoc.internal.doclets.formats.html.markup.Navigation; 49 import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode; 50 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; 51 import jdk.javadoc.internal.doclets.toolkit.Content; 52 import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; 53 import jdk.javadoc.internal.doclets.toolkit.util.ClassUseMapper; 54 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; 55 import jdk.javadoc.internal.doclets.toolkit.util.DocPath; 56 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; 57 58 59 /** 60 * Generate class usage information. 61 * 62 * <p><b>This is NOT part of any supported API. 63 * If you write code that depends on this, you do so at your own risk. 64 * This code and its internal interfaces are subject to change or 65 * deletion without notice.</b> 66 */ 67 public class ClassUseWriter extends SubWriterHolderWriter { 68 69 final TypeElement typeElement; 70 Set<PackageElement> pkgToPackageAnnotations = null; 71 final Map<PackageElement, List<Element>> pkgToClassTypeParameter; 72 final Map<PackageElement, List<Element>> pkgToClassAnnotations; 73 final Map<PackageElement, List<Element>> pkgToMethodTypeParameter; 74 final Map<PackageElement, List<Element>> pkgToMethodArgTypeParameter; 75 final Map<PackageElement, List<Element>> pkgToMethodReturnTypeParameter; 76 final Map<PackageElement, List<Element>> pkgToMethodAnnotations; 77 final Map<PackageElement, List<Element>> pkgToMethodParameterAnnotations; 78 final Map<PackageElement, List<Element>> pkgToFieldTypeParameter; 79 final Map<PackageElement, List<Element>> pkgToFieldAnnotations; 80 final Map<PackageElement, List<Element>> pkgToSubclass; 81 final Map<PackageElement, List<Element>> pkgToSubinterface; 82 final Map<PackageElement, List<Element>> pkgToImplementingClass; 83 final Map<PackageElement, List<Element>> pkgToField; 84 final Map<PackageElement, List<Element>> pkgToMethodReturn; 85 final Map<PackageElement, List<Element>> pkgToMethodArgs; 86 final Map<PackageElement, List<Element>> pkgToMethodThrows; 87 final Map<PackageElement, List<Element>> pkgToConstructorAnnotations; 88 final Map<PackageElement, List<Element>> pkgToConstructorParameterAnnotations; 89 final Map<PackageElement, List<Element>> pkgToConstructorArgs; 90 final Map<PackageElement, List<Element>> pkgToConstructorArgTypeParameter; 91 final Map<PackageElement, List<Element>> pkgToConstructorThrows; 92 final SortedSet<PackageElement> pkgSet; 93 final MethodWriterImpl methodSubWriter; 94 final ConstructorWriterImpl constrSubWriter; 95 final FieldWriterImpl fieldSubWriter; 96 final NestedClassWriterImpl classSubWriter; 97 private final Navigation navBar; 98 99 /** 100 * Constructor. 101 * 102 * @param filename the file to be generated. 103 */ 104 public ClassUseWriter(HtmlConfiguration configuration, 105 ClassUseMapper mapper, DocPath filename, 106 TypeElement typeElement) { 107 super(configuration, filename); 108 this.typeElement = typeElement; 109 if (mapper.classToPackageAnnotations.containsKey(typeElement)) { 110 pkgToPackageAnnotations = new TreeSet<>(utils.makeClassUseComparator()); 111 pkgToPackageAnnotations.addAll(mapper.classToPackageAnnotations.get(typeElement)); 112 } 113 configuration.currentTypeElement = typeElement; 114 this.pkgSet = new TreeSet<>(utils.makePackageComparator()); 115 this.pkgToClassTypeParameter = pkgDivide(mapper.classToClassTypeParam); 116 this.pkgToClassAnnotations = pkgDivide(mapper.classToClassAnnotations); 117 this.pkgToMethodTypeParameter = pkgDivide(mapper.classToMethodTypeParam); 118 this.pkgToMethodArgTypeParameter = pkgDivide(mapper.classToMethodArgTypeParam); 119 this.pkgToFieldTypeParameter = pkgDivide(mapper.classToFieldTypeParam); 120 this.pkgToFieldAnnotations = pkgDivide(mapper.annotationToField); 121 this.pkgToMethodReturnTypeParameter = pkgDivide(mapper.classToMethodReturnTypeParam); 122 this.pkgToMethodAnnotations = pkgDivide(mapper.classToMethodAnnotations); 123 this.pkgToMethodParameterAnnotations = pkgDivide(mapper.classToMethodParamAnnotation); 124 this.pkgToSubclass = pkgDivide(mapper.classToSubclass); 125 this.pkgToSubinterface = pkgDivide(mapper.classToSubinterface); 126 this.pkgToImplementingClass = pkgDivide(mapper.classToImplementingClass); 127 this.pkgToField = pkgDivide(mapper.classToField); 128 this.pkgToMethodReturn = pkgDivide(mapper.classToMethodReturn); 129 this.pkgToMethodArgs = pkgDivide(mapper.classToMethodArgs); 130 this.pkgToMethodThrows = pkgDivide(mapper.classToMethodThrows); 131 this.pkgToConstructorAnnotations = pkgDivide(mapper.classToConstructorAnnotations); 132 this.pkgToConstructorParameterAnnotations = pkgDivide(mapper.classToConstructorParamAnnotation); 133 this.pkgToConstructorArgs = pkgDivide(mapper.classToConstructorArgs); 134 this.pkgToConstructorArgTypeParameter = pkgDivide(mapper.classToConstructorArgTypeParam); 135 this.pkgToConstructorThrows = pkgDivide(mapper.classToConstructorThrows); 136 //tmp test 137 if (pkgSet.size() > 0 && 138 mapper.classToPackage.containsKey(this.typeElement) && 139 !pkgSet.equals(mapper.classToPackage.get(this.typeElement))) { 140 configuration.reporter.print(Diagnostic.Kind.WARNING, 141 "Internal error: package sets don't match: " 142 + pkgSet + " with: " + mapper.classToPackage.get(this.typeElement)); 143 } 144 145 methodSubWriter = new MethodWriterImpl(this); 146 constrSubWriter = new ConstructorWriterImpl(this); 147 fieldSubWriter = new FieldWriterImpl(this); 148 classSubWriter = new NestedClassWriterImpl(this); 149 this.navBar = new Navigation(typeElement, configuration, PageMode.USE, path); 150 } 151 152 /** 153 * Write out class use pages. 154 * 155 * @param configuration the configuration for this doclet 156 * @param classtree the class tree hierarchy 157 * @throws DocFileIOException if there is an error while generating the documentation 158 */ 159 public static void generate(HtmlConfiguration configuration, ClassTree classtree) throws DocFileIOException { 160 ClassUseMapper mapper = new ClassUseMapper(configuration, classtree); 161 for (TypeElement aClass : configuration.getIncludedTypeElements()) { 162 // If -nodeprecated option is set and the containing package is marked 163 // as deprecated, do not generate the class-use page. We will still generate 164 // the class-use page if the class is marked as deprecated but the containing 165 // package is not since it could still be linked from that package-use page. 166 if (!(configuration.nodeprecated && 167 configuration.utils.isDeprecated(configuration.utils.containingPackage(aClass)))) 168 ClassUseWriter.generate(configuration, mapper, aClass); 169 } 170 for (PackageElement pkg : configuration.packages) { 171 // If -nodeprecated option is set and the package is marked 172 // as deprecated, do not generate the package-use page. 173 if (!(configuration.nodeprecated && configuration.utils.isDeprecated(pkg))) 174 PackageUseWriter.generate(configuration, mapper, pkg); 175 } 176 } 177 178 private Map<PackageElement, List<Element>> pkgDivide(Map<TypeElement, ? extends List<? extends Element>> classMap) { 179 Map<PackageElement, List<Element>> map = new HashMap<>(); 180 List<? extends Element> elements = (List<? extends Element>) classMap.get(typeElement); 181 if (elements != null) { 182 Collections.sort(elements, utils.makeClassUseComparator()); 183 for (Element e : elements) { 184 PackageElement pkg = utils.containingPackage(e); 185 pkgSet.add(pkg); 186 List<Element> inPkg = map.get(pkg); 187 if (inPkg == null) { 188 inPkg = new ArrayList<>(); 189 map.put(pkg, inPkg); 190 } 191 inPkg.add(e); 192 } 193 } 194 return map; 195 } 196 197 /** 198 * Generate a class page. 199 * 200 * @throws DocFileIOException if there is a problem while generating the documentation 201 */ 202 public static void generate(HtmlConfiguration configuration, ClassUseMapper mapper, 203 TypeElement typeElement) throws DocFileIOException { 204 ClassUseWriter clsgen; 205 DocPath path = configuration.docPaths.forPackage(typeElement) 206 .resolve(DocPaths.CLASS_USE) 207 .resolve(configuration.docPaths.forName( typeElement)); 208 clsgen = new ClassUseWriter(configuration, mapper, path, typeElement); 209 clsgen.generateClassUseFile(); 210 } 211 212 /** 213 * Generate the class use elements. 214 * 215 * @throws DocFileIOException if there is a problem while generating the documentation 216 */ 217 protected void generateClassUseFile() throws DocFileIOException { 218 HtmlTree body = getClassUseHeader(); 219 HtmlTree div = new HtmlTree(HtmlTag.DIV); 220 div.setStyle(HtmlStyle.classUseContainer); 221 if (pkgSet.size() > 0) { 222 addClassUse(div); 223 } else { 224 div.add(contents.getContent("doclet.ClassUse_No.usage.of.0", 225 utils.getFullyQualifiedName(typeElement))); 226 } 227 bodyContents.addMainContent(div); 228 HtmlTree footer = HtmlTree.FOOTER(); 229 navBar.setUserFooter(getUserHeaderFooter(false)); 230 footer.add(navBar.getContent(false)); 231 addBottom(footer); 232 bodyContents.setFooter(footer); 233 body.add(bodyContents.toContent()); 234 String description = getDescription("use", typeElement); 235 printHtmlDocument(null, description, body); 236 } 237 238 /** 239 * Add the class use documentation. 240 * 241 * @param contentTree the content tree to which the class use information will be added 242 */ 243 protected void addClassUse(Content contentTree) { 244 Content content = new ContentBuilder(); 245 if (configuration.packages.size() > 1) { 246 addPackageList(content); 247 addPackageAnnotationList(content); 248 } 249 addClassList(content); 250 contentTree.add(content); 251 } 252 253 /** 254 * Add the packages elements that use the given class. 255 * 256 * @param contentTree the content tree to which the packages elements will be added 257 */ 258 protected void addPackageList(Content contentTree) { 259 Content caption = getTableCaption(contents.getContent( 260 "doclet.ClassUse_Packages.that.use.0", 261 getLink(new LinkInfoImpl(configuration, 262 LinkInfoImpl.Kind.CLASS_USE_HEADER, typeElement)))); 263 Table table = new Table(HtmlStyle.useSummary) 264 .setCaption(caption) 265 .setHeader(getPackageTableHeader()) 266 .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); 267 for (PackageElement pkg : pkgSet) { 268 addPackageUse(pkg, table); 269 } 270 contentTree.add(table.toContent()); 271 } 272 273 /** 274 * Add the package annotation elements. 275 * 276 * @param contentTree the content tree to which the package annotation elements will be added 277 */ 278 protected void addPackageAnnotationList(Content contentTree) { 279 if (!utils.isAnnotationType(typeElement) || 280 pkgToPackageAnnotations == null || 281 pkgToPackageAnnotations.isEmpty()) { 282 return; 283 } 284 Content caption = getTableCaption(contents.getContent( 285 "doclet.ClassUse_PackageAnnotation", 286 getLink(new LinkInfoImpl(configuration, 287 LinkInfoImpl.Kind.CLASS_USE_HEADER, typeElement)))); 288 289 Table table = new Table(HtmlStyle.useSummary) 290 .setCaption(caption) 291 .setHeader(getPackageTableHeader()) 292 .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); 293 for (PackageElement pkg : pkgToPackageAnnotations) { 294 Content summary = new ContentBuilder(); 295 addSummaryComment(pkg, summary); 296 table.addRow(getPackageLink(pkg), summary); 297 } 298 contentTree.add(table.toContent()); 299 } 300 301 /** 302 * Add the class elements that use the given class. 303 * 304 * @param contentTree the content tree to which the class elements will be added 305 */ 306 protected void addClassList(Content contentTree) { 307 HtmlTree ul = new HtmlTree(HtmlTag.UL); 308 ul.setStyle(HtmlStyle.blockList); 309 for (PackageElement pkg : pkgSet) { 310 Content markerAnchor = links.createAnchor(getPackageAnchorName(pkg)); 311 HtmlTree htmlTree = HtmlTree.SECTION(HtmlStyle.detail, markerAnchor); 312 Content link = contents.getContent("doclet.ClassUse_Uses.of.0.in.1", 313 getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.CLASS_USE_HEADER, 314 typeElement)), 315 getPackageLink(pkg, utils.getPackageName(pkg))); 316 Content heading = HtmlTree.HEADING(Headings.TypeUse.SUMMARY_HEADING, link); 317 htmlTree.add(heading); 318 addClassUse(pkg, htmlTree); 319 ul.add(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); 320 } 321 Content li = HtmlTree.SECTION(HtmlStyle.classUses, ul); 322 contentTree.add(li); 323 } 324 325 /** 326 * Add the package use information. 327 * 328 * @param pkg the package that uses the given class 329 * @param table the table to which the package use information will be added 330 */ 331 protected void addPackageUse(PackageElement pkg, Table table) { 332 Content pkgLink = 333 links.createLink(getPackageAnchorName(pkg), new StringContent(utils.getPackageName(pkg))); 334 Content summary = new ContentBuilder(); 335 addSummaryComment(pkg, summary); 336 table.addRow(pkgLink, summary); 337 } 338 339 /** 340 * Add the class use information. 341 * 342 * @param pkg the package that uses the given class 343 * @param contentTree the content tree to which the class use information will be added 344 */ 345 protected void addClassUse(PackageElement pkg, Content contentTree) { 346 Content classLink = getLink(new LinkInfoImpl(configuration, 347 LinkInfoImpl.Kind.CLASS_USE_HEADER, typeElement)); 348 Content pkgLink = getPackageLink(pkg, utils.getPackageName(pkg)); 349 classSubWriter.addUseInfo(pkgToClassAnnotations.get(pkg), 350 contents.getContent("doclet.ClassUse_Annotation", classLink, 351 pkgLink), contentTree); 352 classSubWriter.addUseInfo(pkgToClassTypeParameter.get(pkg), 353 contents.getContent("doclet.ClassUse_TypeParameter", classLink, 354 pkgLink), contentTree); 355 classSubWriter.addUseInfo(pkgToSubclass.get(pkg), 356 contents.getContent("doclet.ClassUse_Subclass", classLink, 357 pkgLink), contentTree); 358 classSubWriter.addUseInfo(pkgToSubinterface.get(pkg), 359 contents.getContent("doclet.ClassUse_Subinterface", classLink, 360 pkgLink), contentTree); 361 classSubWriter.addUseInfo(pkgToImplementingClass.get(pkg), 362 contents.getContent("doclet.ClassUse_ImplementingClass", classLink, 363 pkgLink), contentTree); 364 fieldSubWriter.addUseInfo(pkgToField.get(pkg), 365 contents.getContent("doclet.ClassUse_Field", classLink, 366 pkgLink), contentTree); 367 fieldSubWriter.addUseInfo(pkgToFieldAnnotations.get(pkg), 368 contents.getContent("doclet.ClassUse_FieldAnnotations", classLink, 369 pkgLink), contentTree); 370 fieldSubWriter.addUseInfo(pkgToFieldTypeParameter.get(pkg), 371 contents.getContent("doclet.ClassUse_FieldTypeParameter", classLink, 372 pkgLink), contentTree); 373 methodSubWriter.addUseInfo(pkgToMethodAnnotations.get(pkg), 374 contents.getContent("doclet.ClassUse_MethodAnnotations", classLink, 375 pkgLink), contentTree); 376 methodSubWriter.addUseInfo(pkgToMethodParameterAnnotations.get(pkg), 377 contents.getContent("doclet.ClassUse_MethodParameterAnnotations", classLink, 378 pkgLink), contentTree); 379 methodSubWriter.addUseInfo(pkgToMethodTypeParameter.get(pkg), 380 contents.getContent("doclet.ClassUse_MethodTypeParameter", classLink, 381 pkgLink), contentTree); 382 methodSubWriter.addUseInfo(pkgToMethodReturn.get(pkg), 383 contents.getContent("doclet.ClassUse_MethodReturn", classLink, 384 pkgLink), contentTree); 385 methodSubWriter.addUseInfo(pkgToMethodReturnTypeParameter.get(pkg), 386 contents.getContent("doclet.ClassUse_MethodReturnTypeParameter", classLink, 387 pkgLink), contentTree); 388 methodSubWriter.addUseInfo(pkgToMethodArgs.get(pkg), 389 contents.getContent("doclet.ClassUse_MethodArgs", classLink, 390 pkgLink), contentTree); 391 methodSubWriter.addUseInfo(pkgToMethodArgTypeParameter.get(pkg), 392 contents.getContent("doclet.ClassUse_MethodArgsTypeParameters", classLink, 393 pkgLink), contentTree); 394 methodSubWriter.addUseInfo(pkgToMethodThrows.get(pkg), 395 contents.getContent("doclet.ClassUse_MethodThrows", classLink, 396 pkgLink), contentTree); 397 constrSubWriter.addUseInfo(pkgToConstructorAnnotations.get(pkg), 398 contents.getContent("doclet.ClassUse_ConstructorAnnotations", classLink, 399 pkgLink), contentTree); 400 constrSubWriter.addUseInfo(pkgToConstructorParameterAnnotations.get(pkg), 401 contents.getContent("doclet.ClassUse_ConstructorParameterAnnotations", classLink, 402 pkgLink), contentTree); 403 constrSubWriter.addUseInfo(pkgToConstructorArgs.get(pkg), 404 contents.getContent("doclet.ClassUse_ConstructorArgs", classLink, 405 pkgLink), contentTree); 406 constrSubWriter.addUseInfo(pkgToConstructorArgTypeParameter.get(pkg), 407 contents.getContent("doclet.ClassUse_ConstructorArgsTypeParameters", classLink, 408 pkgLink), contentTree); 409 constrSubWriter.addUseInfo(pkgToConstructorThrows.get(pkg), 410 contents.getContent("doclet.ClassUse_ConstructorThrows", classLink, 411 pkgLink), contentTree); 412 } 413 414 /** 415 * Get the header for the class use Listing. 416 * 417 * @return a content tree representing the class use header 418 */ 419 protected HtmlTree getClassUseHeader() { 420 String cltype = resources.getText(utils.isInterface(typeElement) 421 ? "doclet.Interface" 422 : "doclet.Class"); 423 String clname = utils.getFullyQualifiedName(typeElement); 424 String title = resources.getText("doclet.Window_ClassUse_Header", 425 cltype, clname); 426 HtmlTree bodyTree = getBody(getWindowTitle(title)); 427 Content headerContent = new ContentBuilder(); 428 addTop(headerContent); 429 Content mdleLinkContent = getModuleLink(utils.elementUtils.getModuleOf(typeElement), 430 contents.moduleLabel); 431 navBar.setNavLinkModule(mdleLinkContent); 432 Content classLinkContent = getLink(new LinkInfoImpl( 433 configuration, LinkInfoImpl.Kind.CLASS_USE_HEADER, typeElement) 434 .label(resources.getText("doclet.Class"))); 435 navBar.setNavLinkClass(classLinkContent); 436 navBar.setUserHeader(getUserHeaderFooter(true)); 437 headerContent.add(navBar.getContent(true)); 438 ContentBuilder headingContent = new ContentBuilder(); 439 headingContent.add(contents.getContent("doclet.ClassUse_Title", cltype)); 440 headingContent.add(new HtmlTree(HtmlTag.BR)); 441 headingContent.add(clname); 442 Content heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, 443 true, HtmlStyle.title, headingContent); 444 Content div = HtmlTree.DIV(HtmlStyle.header, heading); 445 bodyContents.setHeader(headerContent).addMainContent(div); 446 return bodyTree; 447 } 448 }