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