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