1 /* 2 * Copyright (c) 2019, 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 package jdk.javadoc.internal.doclets.formats.html; 26 27 import com.sun.source.doctree.DocTree; 28 import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; 29 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; 30 import jdk.javadoc.internal.doclets.formats.html.markup.FixedStringContent; 31 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; 32 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; 33 import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; 34 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; 35 import jdk.javadoc.internal.doclets.formats.html.markup.Table; 36 import jdk.javadoc.internal.doclets.formats.html.markup.TableHeader; 37 import jdk.javadoc.internal.doclets.toolkit.Content; 38 import jdk.javadoc.internal.doclets.toolkit.DocletElement; 39 import jdk.javadoc.internal.doclets.toolkit.OverviewElement; 40 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; 41 import jdk.javadoc.internal.doclets.toolkit.util.DocPath; 42 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; 43 import jdk.javadoc.internal.doclets.toolkit.util.IndexItem; 44 45 import javax.lang.model.element.Element; 46 import java.nio.file.Path; 47 import java.util.List; 48 import java.util.Map; 49 import java.util.Map.Entry; 50 import java.util.TreeMap; 51 import java.util.WeakHashMap; 52 53 import static java.util.stream.Collectors.groupingBy; 54 import static java.util.stream.Collectors.toList; 55 56 /** 57 * Generates the file with the summary of all the system properties. 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 public class SystemPropertiesWriter extends HtmlDocletWriter { 65 66 /** 67 * Cached contents of {@code <title>...</title>} tags of the HTML pages. 68 */ 69 final Map<Element, String> titles = new WeakHashMap<>(); 70 71 /** 72 * Constructs SystemPropertiesWriter object. 73 * 74 * @param configuration The current configuration 75 * @param filename Path to the file which is getting generated. 76 */ SystemPropertiesWriter(HtmlConfiguration configuration, DocPath filename)77 public SystemPropertiesWriter(HtmlConfiguration configuration, DocPath filename) { 78 super(configuration, filename); 79 } 80 generate(HtmlConfiguration configuration)81 public static void generate(HtmlConfiguration configuration) throws DocFileIOException { 82 generate(configuration, DocPaths.SYSTEM_PROPERTIES); 83 } 84 generate(HtmlConfiguration configuration, DocPath fileName)85 private static void generate(HtmlConfiguration configuration, DocPath fileName) throws DocFileIOException { 86 boolean hasSystemProperties = configuration.mainIndex != null 87 && !configuration.mainIndex.getItems(DocTree.Kind.SYSTEM_PROPERTY).isEmpty(); 88 if (!hasSystemProperties) { 89 // Cannot defer this check any further, because of the super() call 90 // that prints out notices on creating files, etc. 91 // 92 // There is probably a better place for this kind of checks (see how 93 // this is achieved in other "optional" pages, like Constant Values 94 // and Serialized Form). 95 return; 96 } 97 SystemPropertiesWriter systemPropertiesGen = new SystemPropertiesWriter(configuration, fileName); 98 systemPropertiesGen.buildSystemPropertiesPage(); 99 configuration.conditionalPages.add(HtmlConfiguration.ConditionalPage.SYSTEM_PROPERTIES); 100 } 101 102 /** 103 * Prints all the system properties to the file. 104 */ buildSystemPropertiesPage()105 protected void buildSystemPropertiesPage() throws DocFileIOException { 106 String title = resources.getText("doclet.systemProperties"); 107 HtmlTree body = getBody(getWindowTitle(title)); 108 Content mainContent = new ContentBuilder(); 109 addSystemProperties(mainContent); 110 body.add(new BodyContents() 111 .setHeader(getHeader(PageMode.SYSTEM_PROPERTIES)) 112 .addMainContent(HtmlTree.DIV(HtmlStyle.header, 113 HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, 114 contents.getContent("doclet.systemProperties")))) 115 .addMainContent(mainContent) 116 .setFooter(getFooter())); 117 printHtmlDocument(null, "system properties", body); 118 119 if (configuration.mainIndex != null) { 120 configuration.mainIndex.add(IndexItem.of(IndexItem.Category.TAGS, title, path)); 121 } 122 } 123 124 /** 125 * Adds all the system properties to the content tree. 126 * 127 * @param content HtmlTree content to which the links will be added 128 */ addSystemProperties(Content content)129 protected void addSystemProperties(Content content) { 130 Map<String, List<IndexItem>> searchIndexMap = groupSystemProperties(); 131 Content separator = new StringContent(", "); 132 Table table = new Table(HtmlStyle.summaryTable) 133 .setCaption(contents.systemPropertiesSummaryLabel) 134 .setHeader(new TableHeader(contents.propertyLabel, contents.referencedIn)) 135 .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); 136 for (Entry<String, List<IndexItem>> entry : searchIndexMap.entrySet()) { 137 Content propertyName = new StringContent(entry.getKey()); 138 List<IndexItem> searchIndexItems = entry.getValue(); 139 Content separatedReferenceLinks = new ContentBuilder(); 140 separatedReferenceLinks.add(createLink(searchIndexItems.get(0))); 141 for (int i = 1; i < searchIndexItems.size(); i++) { 142 separatedReferenceLinks.add(separator); 143 separatedReferenceLinks.add(createLink(searchIndexItems.get(i))); 144 } 145 table.addRow(propertyName, HtmlTree.DIV(HtmlStyle.block, separatedReferenceLinks)); 146 } 147 content.add(table); 148 } 149 groupSystemProperties()150 private Map<String, List<IndexItem>> groupSystemProperties() { 151 return configuration.mainIndex.getItems(DocTree.Kind.SYSTEM_PROPERTY).stream() 152 .collect(groupingBy(IndexItem::getLabel, TreeMap::new, toList())); 153 } 154 createLink(IndexItem i)155 private Content createLink(IndexItem i) { 156 assert i.getDocTree().getKind() == DocTree.Kind.SYSTEM_PROPERTY : i; 157 Element element = i.getElement(); 158 if (element instanceof OverviewElement) { 159 return links.createLink(pathToRoot.resolve(i.getUrl()), 160 resources.getText("doclet.Overview")); 161 } else if (element instanceof DocletElement) { 162 DocletElement e = (DocletElement) element; 163 // Implementations of DocletElement do not override equals and 164 // hashCode; putting instances of DocletElement in a map is not 165 // incorrect, but might well be inefficient 166 String t = titles.computeIfAbsent(element, utils::getHTMLTitle); 167 if (t.isBlank()) { 168 // The user should probably be notified (a warning?) that this 169 // file does not have a title 170 Path p = Path.of(e.getFileObject().toUri()); 171 t = p.getFileName().toString(); 172 } 173 ContentBuilder b = new ContentBuilder(); 174 b.add(HtmlTree.CODE(new FixedStringContent(i.getHolder() + ": "))); 175 // non-program elements should be displayed using a normal font 176 b.add(t); 177 return links.createLink(pathToRoot.resolve(i.getUrl()), b); 178 } else { 179 // program elements should be displayed using a code font 180 Content link = links.createLink(pathToRoot.resolve(i.getUrl()), i.getHolder()); 181 return HtmlTree.CODE(link); 182 } 183 } 184 } 185