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