1 /*
   2  * Copyright (c) 1998, 2016, 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 java.io.*;
  29 import java.util.*;
  30 
  31 import javax.lang.model.element.PackageElement;
  32 import javax.lang.model.element.TypeElement;
  33 
  34 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
  35 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
  36 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
  37 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
  38 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
  39 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
  40 import jdk.javadoc.internal.doclets.toolkit.Content;
  41 import jdk.javadoc.internal.doclets.toolkit.util.ClassUseMapper;
  42 import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
  43 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
  44 import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException;
  45 
  46 /**
  47  * Generate package usage information.
  48  *
  49  *  <p><b>This is NOT part of any supported API.
  50  *  If you write code that depends on this, you do so at your own risk.
  51  *  This code and its internal interfaces are subject to change or
  52  *  deletion without notice.</b>
  53  *
  54  * @author Robert G. Field
  55  * @author Bhavesh Patel (Modified)
  56  */
  57 public class PackageUseWriter extends SubWriterHolderWriter {
  58 
  59     final PackageElement packageElement;
  60     final SortedMap<String, Set<TypeElement>> usingPackageToUsedClasses = new TreeMap<>();
  61     protected HtmlTree mainTree = HtmlTree.MAIN();
  62 
  63     /**
  64      * Constructor.
  65      *
  66      * @param filename the file to be generated.
  67      * @throws IOException
  68      * @throws DocletAbortException
  69      */
  70     public PackageUseWriter(ConfigurationImpl configuration,
  71                             ClassUseMapper mapper, DocPath filename,
  72                             PackageElement pkgElement) throws IOException {
  73         super(configuration, DocPath.forPackage(pkgElement).resolve(filename));
  74         this.packageElement = pkgElement;
  75 
  76         // by examining all classes in this package, find what packages
  77         // use these classes - produce a map between using package and
  78         // used classes.
  79         for (TypeElement usedClass : utils.getEnclosedTypeElements(pkgElement)) {
  80             Set<TypeElement> usingClasses = mapper.classToClass.get(usedClass);
  81             if (usingClasses != null) {
  82                 for (TypeElement usingClass : usingClasses) {
  83                     PackageElement usingPackage = utils.containingPackage(usingClass);
  84                     Set<TypeElement> usedClasses = usingPackageToUsedClasses
  85                             .get(utils.getPackageName(usingPackage));
  86                     if (usedClasses == null) {
  87                         usedClasses = new TreeSet<>(utils.makeGeneralPurposeComparator());
  88                         usingPackageToUsedClasses.put(utils.getPackageName(usingPackage),
  89                                                       usedClasses);
  90                     }
  91                     usedClasses.add(usedClass);
  92                 }
  93             }
  94         }
  95     }
  96 
  97     /**
  98      * Generate a class page.
  99      *
 100      * @param configuration the current configuration of the doclet.
 101      * @param mapper        the mapping of the class usage.
 102      * @param pkgElement    the package being documented.
 103      */
 104     public static void generate(ConfigurationImpl configuration,
 105                                 ClassUseMapper mapper, PackageElement pkgElement) {
 106         PackageUseWriter pkgusegen;
 107         DocPath filename = DocPaths.PACKAGE_USE;
 108         try {
 109             pkgusegen = new PackageUseWriter(configuration, mapper, filename, pkgElement);
 110             pkgusegen.generatePackageUseFile();
 111             pkgusegen.close();
 112         } catch (IOException exc) {
 113             configuration.standardmessage.error(
 114                 "doclet.exception_encountered",
 115                 exc.toString(), filename);
 116             throw new DocletAbortException(exc);
 117         }
 118     }
 119 
 120     /**
 121      * Generate the package use list.
 122      */
 123     protected void generatePackageUseFile() throws IOException {
 124         HtmlTree body = getPackageUseHeader();
 125         HtmlTree div = new HtmlTree(HtmlTag.DIV);
 126         div.addStyle(HtmlStyle.contentContainer);
 127         if (usingPackageToUsedClasses.isEmpty()) {
 128             div.addContent(getResource("doclet.ClassUse_No.usage.of.0", utils.getPackageName(packageElement)));
 129         } else {
 130             addPackageUse(div);
 131         }
 132         if (configuration.allowTag(HtmlTag.MAIN)) {
 133             mainTree.addContent(div);
 134             body.addContent(mainTree);
 135         } else {
 136             body.addContent(div);
 137         }
 138         HtmlTree tree = (configuration.allowTag(HtmlTag.FOOTER))
 139                 ? HtmlTree.FOOTER()
 140                 : body;
 141         addNavLinks(false, tree);
 142         addBottom(tree);
 143         if (configuration.allowTag(HtmlTag.FOOTER)) {
 144             body.addContent(tree);
 145         }
 146         printHtmlDocument(null, true, body);
 147     }
 148 
 149     /**
 150      * Add the package use information.
 151      *
 152      * @param contentTree the content tree to which the package use information will be added
 153      */
 154     protected void addPackageUse(Content contentTree) throws IOException {
 155         HtmlTree ul = new HtmlTree(HtmlTag.UL);
 156         ul.addStyle(HtmlStyle.blockList);
 157         if (configuration.packages.size() > 1) {
 158             addPackageList(ul);
 159         }
 160         addClassList(ul);
 161         contentTree.addContent(ul);
 162     }
 163 
 164     /**
 165      * Add the list of packages that use the given package.
 166      *
 167      * @param contentTree the content tree to which the package list will be added
 168      */
 169     protected void addPackageList(Content contentTree) throws IOException {
 170         Content caption = getTableCaption(configuration.getResource(
 171                 "doclet.ClassUse_Packages.that.use.0",
 172                 getPackageLink(packageElement, utils.getPackageName(packageElement))));
 173         Content table = (configuration.isOutputHtml5())
 174                 ? HtmlTree.TABLE(HtmlStyle.useSummary, caption)
 175                 : HtmlTree.TABLE(HtmlStyle.useSummary, useTableSummary, caption);
 176         table.addContent(getSummaryTableHeader(packageTableHeader, "col"));
 177         Content tbody = new HtmlTree(HtmlTag.TBODY);
 178         boolean altColor = true;
 179         for (String pkgname: usingPackageToUsedClasses.keySet()) {
 180             PackageElement pkg = utils.elementUtils.getPackageElement(pkgname);
 181             HtmlTree tr = new HtmlTree(HtmlTag.TR);
 182             tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
 183             altColor = !altColor;
 184             addPackageUse(pkg, tr);
 185             tbody.addContent(tr);
 186         }
 187         table.addContent(tbody);
 188         Content li = HtmlTree.LI(HtmlStyle.blockList, table);
 189         contentTree.addContent(li);
 190     }
 191 
 192     /**
 193      * Add the list of classes that use the given package.
 194      *
 195      * @param contentTree the content tree to which the class list will be added
 196      */
 197     protected void addClassList(Content contentTree) throws IOException {
 198         List<String> classTableHeader = Arrays.asList(
 199             configuration.getText("doclet.0_and_1",
 200                     configuration.getText("doclet.Class"),
 201                     configuration.getText("doclet.Description")));
 202         for (String packageName : usingPackageToUsedClasses.keySet()) {
 203             PackageElement usingPackage = utils.elementUtils.getPackageElement(packageName);
 204             HtmlTree li = new HtmlTree(HtmlTag.LI);
 205             li.addStyle(HtmlStyle.blockList);
 206             if (usingPackage != null) {
 207                 li.addContent(getMarkerAnchor(utils.getPackageName(usingPackage)));
 208             }
 209             String tableSummary = configuration.getText("doclet.Use_Table_Summary",
 210                                                         configuration.getText("doclet.classes"));
 211             Content caption = getTableCaption(configuration.getResource(
 212                     "doclet.ClassUse_Classes.in.0.used.by.1",
 213                     getPackageLink(packageElement, utils.getPackageName(packageElement)),
 214                     getPackageLink(usingPackage, utils.getPackageName(usingPackage))));
 215             Content table = (configuration.isOutputHtml5())
 216                     ? HtmlTree.TABLE(HtmlStyle.useSummary, caption)
 217                     : HtmlTree.TABLE(HtmlStyle.useSummary, tableSummary, caption);
 218             table.addContent(getSummaryTableHeader(classTableHeader, "col"));
 219             Content tbody = new HtmlTree(HtmlTag.TBODY);
 220             boolean altColor = true;
 221             for (TypeElement te : usingPackageToUsedClasses.get(packageName)) {
 222                 HtmlTree tr = new HtmlTree(HtmlTag.TR);
 223                 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
 224                 altColor = !altColor;
 225                 addClassRow(te, usingPackage, tr);
 226                 tbody.addContent(tr);
 227             }
 228             table.addContent(tbody);
 229             li.addContent(table);
 230             contentTree.addContent(li);
 231         }
 232     }
 233 
 234     /**
 235      * Add a row for the class that uses the given package.
 236      *
 237      * @param usedClass the class that uses the given package
 238      * @param pkg  the package to which the class belongs
 239      * @param contentTree the content tree to which the row will be added
 240      */
 241     protected void addClassRow(TypeElement usedClass, PackageElement pkg,
 242             Content contentTree) {
 243         DocPath dp = pathString(usedClass,
 244                 DocPaths.CLASS_USE.resolve(DocPath.forName(utils, usedClass)));
 245         StringContent stringContent = new StringContent(utils.getSimpleName(usedClass));
 246         Content td = HtmlTree.TD(HtmlStyle.colOne,
 247                 getHyperLink(dp.fragment(getPackageAnchorName(pkg)), stringContent));
 248         addIndexComment(usedClass, td);
 249         contentTree.addContent(td);
 250     }
 251 
 252     /**
 253      * Add the package use information.
 254      *
 255      * @param pkg the package that used the given package
 256      * @param contentTree the content tree to which the information will be added
 257      */
 258     protected void addPackageUse(PackageElement pkg, Content contentTree) throws IOException {
 259         Content tdFirst = HtmlTree.TD(HtmlStyle.colFirst,
 260                 getHyperLink(utils.getPackageName(pkg),
 261                 new StringContent(utils.getPackageName(pkg))));
 262         contentTree.addContent(tdFirst);
 263         HtmlTree tdLast = new HtmlTree(HtmlTag.TD);
 264         tdLast.addStyle(HtmlStyle.colLast);
 265         if (pkg != null && !pkg.isUnnamed()) {
 266             addSummaryComment(pkg, tdLast);
 267         } else {
 268             tdLast.addContent(getSpace());
 269         }
 270         contentTree.addContent(tdLast);
 271     }
 272 
 273     /**
 274      * Get the header for the package use listing.
 275      *
 276      * @return a content tree representing the package use header
 277      */
 278     protected HtmlTree getPackageUseHeader() {
 279         String packageText = configuration.getText("doclet.Package");
 280         String name = packageElement.isUnnamed() ? "" : utils.getPackageName(packageElement);
 281         String title = configuration.getText("doclet.Window_ClassUse_Header", packageText, name);
 282         HtmlTree bodyTree = getBody(true, getWindowTitle(title));
 283         HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER))
 284                 ? HtmlTree.HEADER()
 285                 : bodyTree;
 286         addTop(htmlTree);
 287         addNavLinks(true, htmlTree);
 288         if (configuration.allowTag(HtmlTag.HEADER)) {
 289             bodyTree.addContent(htmlTree);
 290         }
 291         ContentBuilder headContent = new ContentBuilder();
 292         headContent.addContent(getResource("doclet.ClassUse_Title", packageText));
 293         headContent.addContent(new HtmlTree(HtmlTag.BR));
 294         headContent.addContent(name);
 295         Content heading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, true,
 296                 HtmlStyle.title, headContent);
 297         Content div = HtmlTree.DIV(HtmlStyle.header, heading);
 298         if (configuration.allowTag(HtmlTag.MAIN)) {
 299             mainTree.addContent(div);
 300         } else {
 301             bodyTree.addContent(div);
 302         }
 303         return bodyTree;
 304     }
 305 
 306     /**
 307      * Get this package link.
 308      *
 309      * @return a content tree for the package link
 310      */
 311     protected Content getNavLinkPackage() {
 312         Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY,
 313                 packageLabel);
 314         Content li = HtmlTree.LI(linkContent);
 315         return li;
 316     }
 317 
 318     /**
 319      * Get the use link.
 320      *
 321      * @return a content tree for the use link
 322      */
 323     protected Content getNavLinkClassUse() {
 324         Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, useLabel);
 325         return li;
 326     }
 327 
 328     /**
 329      * Get the tree link.
 330      *
 331      * @return a content tree for the tree link
 332      */
 333     protected Content getNavLinkTree() {
 334         Content linkContent = getHyperLink(DocPaths.PACKAGE_TREE,
 335                 treeLabel);
 336         Content li = HtmlTree.LI(linkContent);
 337         return li;
 338     }
 339 }