1 /*
   2  * Copyright (c) 1997, 2017, 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.util.EnumMap;
  29 import java.util.List;
  30 import java.util.SortedSet;
  31 
  32 import javax.lang.model.element.Element;
  33 import javax.lang.model.element.ModuleElement;
  34 import javax.lang.model.element.PackageElement;
  35 
  36 import com.sun.source.doctree.DocTree;
  37 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
  38 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
  39 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
  40 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
  41 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
  42 import jdk.javadoc.internal.doclets.toolkit.Content;
  43 import jdk.javadoc.internal.doclets.toolkit.util.DeprecatedAPIListBuilder;
  44 import jdk.javadoc.internal.doclets.toolkit.util.DeprecatedAPIListBuilder.DeprElementKind;
  45 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
  46 import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
  47 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
  48 
  49 /**
  50  * Generate File to list all the deprecated classes and class members with the
  51  * appropriate links.
  52  *
  53  *  <p><b>This is NOT part of any supported API.
  54  *  If you write code that depends on this, you do so at your own risk.
  55  *  This code and its internal interfaces are subject to change or
  56  *  deletion without notice.</b>
  57  *
  58  * @see java.util.List
  59  * @author Atul M Dambalkar
  60  * @author Bhavesh Patel (Modified)
  61  */
  62 public class DeprecatedListWriter extends SubWriterHolderWriter {
  63 
  64     private String getAnchorName(DeprElementKind kind) {
  65         switch (kind) {
  66             case REMOVAL:
  67                 return "forRemoval";
  68             case MODULE:
  69                 return "module";
  70             case PACKAGE:
  71                 return "package";
  72             case INTERFACE:
  73                 return "interface";
  74             case CLASS:
  75                 return "class";
  76             case ENUM:
  77                 return "enum";
  78             case EXCEPTION:
  79                 return "exception";
  80             case ERROR:
  81                 return "error";
  82             case ANNOTATION_TYPE:
  83                 return "annotation.type";
  84             case FIELD:
  85                 return "field";
  86             case METHOD:
  87                 return "method";
  88             case CONSTRUCTOR:
  89                 return "constructor";
  90             case ENUM_CONSTANT:
  91                 return "enum.constant";
  92             case ANNOTATION_TYPE_MEMBER:
  93                 return "annotation.type.member";
  94             default:
  95                 throw new AssertionError("unknown kind: " + kind);
  96         }
  97     }
  98 
  99     private String getHeadingKey(DeprElementKind kind) {
 100         switch (kind) {
 101             case REMOVAL:
 102                 return "doclet.For_Removal";
 103             case MODULE:
 104                 return "doclet.Modules";
 105             case PACKAGE:
 106                 return "doclet.Packages";
 107             case INTERFACE:
 108                 return "doclet.Interfaces";
 109             case CLASS:
 110                 return "doclet.Classes";
 111             case ENUM:
 112                 return "doclet.Enums";
 113             case EXCEPTION:
 114                 return "doclet.Exceptions";
 115             case ERROR:
 116                 return "doclet.Errors";
 117             case ANNOTATION_TYPE:
 118                 return "doclet.Annotation_Types";
 119             case FIELD:
 120                 return "doclet.Fields";
 121             case METHOD:
 122                 return "doclet.Methods";
 123             case CONSTRUCTOR:
 124                 return "doclet.Constructors";
 125             case ENUM_CONSTANT:
 126                 return "doclet.Enum_Constants";
 127             case ANNOTATION_TYPE_MEMBER:
 128                 return "doclet.Annotation_Type_Members";
 129             default:
 130                 throw new AssertionError("unknown kind: " + kind);
 131         }
 132     }
 133 
 134     private String getSummaryKey(DeprElementKind kind) {
 135         switch (kind) {
 136             case REMOVAL:
 137                 return "doclet.for_removal";
 138             case MODULE:
 139                 return "doclet.modules";
 140             case PACKAGE:
 141                 return "doclet.packages";
 142             case INTERFACE:
 143                 return "doclet.interfaces";
 144             case CLASS:
 145                 return "doclet.classes";
 146             case ENUM:
 147                 return "doclet.enums";
 148             case EXCEPTION:
 149                 return "doclet.exceptions";
 150             case ERROR:
 151                 return "doclet.errors";
 152             case ANNOTATION_TYPE:
 153                 return "doclet.annotation_types";
 154             case FIELD:
 155                 return "doclet.fields";
 156             case METHOD:
 157                 return "doclet.methods";
 158             case CONSTRUCTOR:
 159                 return "doclet.constructors";
 160             case ENUM_CONSTANT:
 161                 return "doclet.enum_constants";
 162             case ANNOTATION_TYPE_MEMBER:
 163                 return "doclet.annotation_type_members";
 164             default:
 165                 throw new AssertionError("unknown kind: " + kind);
 166         }
 167     }
 168 
 169     private String getHeaderKey(DeprElementKind kind) {
 170         switch (kind) {
 171             case REMOVAL:
 172                 return "doclet.Element";
 173             case MODULE:
 174                 return "doclet.Module";
 175             case PACKAGE:
 176                 return "doclet.Package";
 177             case INTERFACE:
 178                 return "doclet.Interface";
 179             case CLASS:
 180                 return "doclet.Class";
 181             case ENUM:
 182                 return "doclet.Enum";
 183             case EXCEPTION:
 184                 return "doclet.Exceptions";
 185             case ERROR:
 186                 return "doclet.Errors";
 187             case ANNOTATION_TYPE:
 188                 return "doclet.AnnotationType";
 189             case FIELD:
 190                 return "doclet.Field";
 191             case METHOD:
 192                 return "doclet.Method";
 193             case CONSTRUCTOR:
 194                 return "doclet.Constructor";
 195             case ENUM_CONSTANT:
 196                 return "doclet.Enum_Constant";
 197             case ANNOTATION_TYPE_MEMBER:
 198                 return "doclet.Annotation_Type_Member";
 199             default:
 200                 throw new AssertionError("unknown kind: " + kind);
 201         }
 202     }
 203 
 204     private EnumMap<DeprElementKind, AbstractMemberWriter> writerMap;
 205 
 206     private HtmlConfiguration configuration;
 207 
 208     /**
 209      * Constructor.
 210      *
 211      * @param configuration the configuration for this doclet
 212      * @param filename the file to be generated
 213      */
 214 
 215     public DeprecatedListWriter(HtmlConfiguration configuration, DocPath filename) {
 216         super(configuration, filename);
 217         this.configuration = configuration;
 218         NestedClassWriterImpl classW = new NestedClassWriterImpl(this);
 219         writerMap = new EnumMap<>(DeprElementKind.class);
 220         for (DeprElementKind kind : DeprElementKind.values()) {
 221             switch (kind) {
 222                 case REMOVAL:
 223                 case MODULE:
 224                 case PACKAGE:
 225                 case INTERFACE:
 226                 case CLASS:
 227                 case ENUM:
 228                 case EXCEPTION:
 229                 case ERROR:
 230                 case ANNOTATION_TYPE:
 231                     writerMap.put(kind, classW);
 232                     break;
 233                 case FIELD:
 234                     writerMap.put(kind, new FieldWriterImpl(this));
 235                     break;
 236                 case METHOD:
 237                     writerMap.put(kind, new MethodWriterImpl(this));
 238                     break;
 239                 case CONSTRUCTOR:
 240                     writerMap.put(kind, new ConstructorWriterImpl(this));
 241                     break;
 242                 case ENUM_CONSTANT:
 243                     writerMap.put(kind, new EnumConstantWriterImpl(this));
 244                     break;
 245                 case ANNOTATION_TYPE_MEMBER:
 246                     writerMap.put(kind, new AnnotationTypeOptionalMemberWriterImpl(this, null));
 247                     break;
 248                 default:
 249                    throw new AssertionError("unknown kind: " + kind);
 250             }
 251         }
 252     }
 253 
 254     /**
 255      * Get list of all the deprecated classes and members in all the Packages
 256      * specified on the Command Line.
 257      * Then instantiate DeprecatedListWriter and generate File.
 258      *
 259      * @param configuration the current configuration of the doclet.
 260      * @throws DocFileIOException if there is a problem writing the deprecated list
 261      */
 262     public static void generate(HtmlConfiguration configuration) throws DocFileIOException {
 263         DocPath filename = DocPaths.DEPRECATED_LIST;
 264         DeprecatedListWriter depr = new DeprecatedListWriter(configuration, filename);
 265         depr.generateDeprecatedListFile(
 266                new DeprecatedAPIListBuilder(configuration));
 267     }
 268 
 269     /**
 270      * Generate the deprecated API list.
 271      *
 272      * @param deprapi list of deprecated API built already.
 273      * @throws DocFileIOException if there is a problem writing the deprecated list
 274      */
 275     protected void generateDeprecatedListFile(DeprecatedAPIListBuilder deprapi)
 276             throws DocFileIOException {
 277         HtmlTree body = getHeader();
 278         HtmlTree htmlTree = (configuration.allowTag(HtmlTag.MAIN))
 279                 ? HtmlTree.MAIN()
 280                 : body;
 281         htmlTree.addContent(getContentsList(deprapi));
 282         String memberTableSummary;
 283         HtmlTree div = new HtmlTree(HtmlTag.DIV);
 284         div.addStyle(HtmlStyle.contentContainer);
 285         for (DeprElementKind kind : DeprElementKind.values()) {
 286             if (deprapi.hasDocumentation(kind)) {
 287                 addAnchor(deprapi, kind, div);
 288                 memberTableSummary = resources.getText("doclet.Member_Table_Summary",
 289                         resources.getText(getHeadingKey(kind)),
 290                         resources.getText(getSummaryKey(kind)));
 291                 TableHeader memberTableHeader = new TableHeader(
 292                         contents.getContent(getHeaderKey(kind)), contents.descriptionLabel);
 293                 addDeprecatedAPI(deprapi.getSet(kind),
 294                             getHeadingKey(kind), memberTableSummary, memberTableHeader, div);
 295             }
 296         }
 297         if (configuration.allowTag(HtmlTag.MAIN)) {
 298             htmlTree.addContent(div);
 299             body.addContent(htmlTree);
 300         } else {
 301             body.addContent(div);
 302         }
 303         htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
 304                 ? HtmlTree.FOOTER()
 305                 : body;
 306         addNavLinks(false, htmlTree);
 307         addBottom(htmlTree);
 308         if (configuration.allowTag(HtmlTag.FOOTER)) {
 309             body.addContent(htmlTree);
 310         }
 311         printHtmlDocument(null, true, body);
 312     }
 313 
 314     /**
 315      * Add the index link.
 316      *
 317      * @param builder the deprecated list builder
 318      * @param type the type of list being documented
 319      * @param contentTree the content tree to which the index link will be added
 320      */
 321     private void addIndexLink(DeprecatedAPIListBuilder builder,
 322             DeprElementKind kind, Content contentTree) {
 323         if (builder.hasDocumentation(kind)) {
 324             Content li = HtmlTree.LI(getHyperLink(getAnchorName(kind),
 325                     contents.getContent(getHeadingKey(kind))));
 326             contentTree.addContent(li);
 327         }
 328     }
 329 
 330     /**
 331      * Get the contents list.
 332      *
 333      * @param deprapi the deprecated list builder
 334      * @return a content tree for the contents list
 335      */
 336     public Content getContentsList(DeprecatedAPIListBuilder deprapi) {
 337         Content headContent = contents.deprecatedAPI;
 338         Content heading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, true,
 339                 HtmlStyle.title, headContent);
 340         Content div = HtmlTree.DIV(HtmlStyle.header, heading);
 341         Content headingContent = contents.contentsHeading;
 342         div.addContent(HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, true,
 343                 headingContent));
 344         Content ul = new HtmlTree(HtmlTag.UL);
 345         for (DeprElementKind kind : DeprElementKind.values()) {
 346             addIndexLink(deprapi, kind, ul);
 347         }
 348         div.addContent(ul);
 349         return div;
 350     }
 351 
 352     /**
 353      * Add the anchor.
 354      *
 355      * @param builder the deprecated list builder
 356      * @param type the type of list being documented
 357      * @param htmlTree the content tree to which the anchor will be added
 358      */
 359     private void addAnchor(DeprecatedAPIListBuilder builder, DeprElementKind kind, Content htmlTree) {
 360         if (builder.hasDocumentation(kind)) {
 361             htmlTree.addContent(getMarkerAnchor(getAnchorName(kind)));
 362         }
 363     }
 364 
 365     /**
 366      * Get the header for the deprecated API Listing.
 367      *
 368      * @return a content tree for the header
 369      */
 370     public HtmlTree getHeader() {
 371         String title = configuration.getText("doclet.Window_Deprecated_List");
 372         HtmlTree bodyTree = getBody(true, getWindowTitle(title));
 373         HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER))
 374                 ? HtmlTree.HEADER()
 375                 : bodyTree;
 376         addTop(htmlTree);
 377         addNavLinks(true, htmlTree);
 378         if (configuration.allowTag(HtmlTag.HEADER)) {
 379             bodyTree.addContent(htmlTree);
 380         }
 381         return bodyTree;
 382     }
 383 
 384     /**
 385      * Get the deprecated label.
 386      *
 387      * @return a content tree for the deprecated label
 388      */
 389     @Override
 390     protected Content getNavLinkDeprecated() {
 391         Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.deprecatedLabel);
 392         return li;
 393     }
 394 
 395     /**
 396      * Add deprecated information to the documentation tree
 397      *
 398      * @param deprList list of deprecated API elements
 399      * @param headingKey the caption for the deprecated table
 400      * @param tableSummary the summary for the deprecated table
 401      * @param tableHeader table headers for the deprecated table
 402      * @param contentTree the content tree to which the deprecated table will be added
 403      */
 404     protected void addDeprecatedAPI(SortedSet<Element> deprList, String headingKey,
 405             String tableSummary, TableHeader tableHeader, Content contentTree) {
 406         if (deprList.size() > 0) {
 407             Content caption = getTableCaption(configuration.getContent(headingKey));
 408             Content table = (configuration.isOutputHtml5())
 409                     ? HtmlTree.TABLE(HtmlStyle.deprecatedSummary, caption)
 410                     : HtmlTree.TABLE(HtmlStyle.deprecatedSummary, tableSummary, caption);
 411             table.addContent(tableHeader.toContent());
 412             Content tbody = new HtmlTree(HtmlTag.TBODY);
 413             boolean altColor = true;
 414             for (Element e : deprList) {
 415                 HtmlTree thRow;
 416                 switch (e.getKind()) {
 417                     case MODULE:
 418                         ModuleElement m = (ModuleElement)e;
 419                         thRow = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst,
 420                         getModuleLink(m, new StringContent(m.getQualifiedName())));
 421                         break;
 422                     case PACKAGE:
 423                         PackageElement pkg = (PackageElement)e;
 424                         thRow = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst,
 425                         getPackageLink(pkg, getPackageName(pkg)));
 426                         break;
 427                     default:
 428                         thRow = getDeprecatedLink(e);
 429                 }
 430                 HtmlTree tr = HtmlTree.TR(thRow);
 431                 HtmlTree tdDesc = new HtmlTree(HtmlTag.TD);
 432                 tdDesc.addStyle(HtmlStyle.colLast);
 433                 List<? extends DocTree> tags = utils.getDeprecatedTrees(e);
 434                 if (!tags.isEmpty()) {
 435                     addInlineDeprecatedComment(e, tags.get(0), tdDesc);
 436                 }
 437                 tr.addContent(tdDesc);
 438                 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
 439                 altColor = !altColor;
 440                 tbody.addContent(tr);
 441             }
 442             table.addContent(tbody);
 443             Content li = HtmlTree.LI(HtmlStyle.blockList, table);
 444             Content ul = HtmlTree.UL(HtmlStyle.blockList, li);
 445             contentTree.addContent(ul);
 446         }
 447     }
 448 
 449     protected HtmlTree getDeprecatedLink(Element e) {
 450         AbstractMemberWriter writer;
 451         switch (e.getKind()) {
 452             case INTERFACE:
 453             case CLASS:
 454             case ENUM:
 455             case ANNOTATION_TYPE:
 456                 writer = new NestedClassWriterImpl(this);
 457                 break;
 458             case FIELD:
 459                 writer = new FieldWriterImpl(this);
 460                 break;
 461             case METHOD:
 462                 writer = new MethodWriterImpl(this);
 463                 break;
 464             case CONSTRUCTOR:
 465                 writer = new ConstructorWriterImpl(this);
 466                 break;
 467             case ENUM_CONSTANT:
 468                 writer = new EnumConstantWriterImpl(this);
 469                 break;
 470             default:
 471                 writer = new AnnotationTypeOptionalMemberWriterImpl(this, null);
 472         }
 473         return HtmlTree.TH_ROW_SCOPE(HtmlStyle.colDeprecatedItemName, writer.getDeprecatedLink(e));
 474     }
 475 }