001/* 002 * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package org.jdrupes.mdoclet.internal.doclets.formats.html; 027 028import com.sun.source.doctree.DocTree; 029 030import javax.lang.model.element.Element; 031 032import org.jdrupes.mdoclet.internal.doclets.formats.html.Navigation.PageMode; 033import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.BodyContents; 034import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.ContentBuilder; 035import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlStyle; 036import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlTree; 037import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Text; 038import org.jdrupes.mdoclet.internal.doclets.toolkit.Content; 039import org.jdrupes.mdoclet.internal.doclets.toolkit.DocletElement; 040import org.jdrupes.mdoclet.internal.doclets.toolkit.OverviewElement; 041import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocFileIOException; 042import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocPath; 043import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocPaths; 044import org.jdrupes.mdoclet.internal.doclets.toolkit.util.IndexItem; 045 046import java.nio.file.Path; 047import java.util.*; 048import java.util.Map.Entry; 049 050import static java.util.stream.Collectors.groupingBy; 051import java.util.stream.Collectors; 052import java.util.ArrayList; 053 054/** 055 * Generates the file with the summary of all the system properties. 056 */ 057public class SystemPropertiesWriter extends HtmlDocletWriter { 058 059 /** 060 * Cached contents of {@code <title>...</title>} tags of the HTML pages. 061 */ 062 final Map<Element, String> titles = new WeakHashMap<>(); 063 064 /** 065 * Constructs SystemPropertiesWriter object. 066 * 067 * @param configuration The current configuration 068 * @param filename Path to the file which is getting generated. 069 */ 070 public SystemPropertiesWriter(HtmlConfiguration configuration, 071 DocPath filename) { 072 super(configuration, filename); 073 } 074 075 public static void generate(HtmlConfiguration configuration) 076 throws DocFileIOException { 077 generate(configuration, DocPaths.SYSTEM_PROPERTIES); 078 } 079 080 private static void generate(HtmlConfiguration configuration, 081 DocPath fileName) throws DocFileIOException { 082 boolean hasSystemProperties = configuration.mainIndex != null 083 && !configuration.mainIndex.getItems(DocTree.Kind.SYSTEM_PROPERTY) 084 .isEmpty(); 085 if (!hasSystemProperties) { 086 // Cannot defer this check any further, because of the super() call 087 // that prints out notices on creating files, etc. 088 // 089 // There is probably a better place for this kind of checks (see how 090 // this is achieved in other "optional" pages, like Constant Values 091 // and Serialized Form). 092 return; 093 } 094 SystemPropertiesWriter systemPropertiesGen 095 = new SystemPropertiesWriter(configuration, fileName); 096 systemPropertiesGen.buildSystemPropertiesPage(); 097 configuration.conditionalPages 098 .add(HtmlConfiguration.ConditionalPage.SYSTEM_PROPERTIES); 099 } 100 101 /** 102 * Prints all the system properties to the file. 103 */ 104 protected void buildSystemPropertiesPage() throws DocFileIOException { 105 String title = resources.getText("doclet.systemProperties"); 106 HtmlTree body = getBody(getWindowTitle(title)); 107 Content mainContent = new ContentBuilder(); 108 addSystemProperties(mainContent); 109 body.add(new BodyContents() 110 .setHeader(getHeader(PageMode.SYSTEM_PROPERTIES)) 111 .addMainContent(HtmlTree.DIV(HtmlStyle.header, 112 HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, 113 contents.getContent("doclet.systemProperties")))) 114 .addMainContent(mainContent) 115 .setFooter(getFooter())); 116 printHtmlDocument(null, "system properties", body); 117 118 if (configuration.mainIndex != null) { 119 configuration.mainIndex 120 .add(IndexItem.of(IndexItem.Category.TAGS, title, path)); 121 } 122 } 123 124 /** 125 * Adds all the system properties to the content. 126 * 127 * @param target the content to which the links will be added 128 */ 129 protected void addSystemProperties(Content target) { 130 Map<String, List<IndexItem>> searchIndexMap = groupSystemProperties(); 131 Content separator = Text.of(", "); 132 var table = new Table<Void>(HtmlStyle.summaryTable) 133 .setCaption(contents.systemPropertiesSummaryLabel) 134 .setHeader( 135 new TableHeader(contents.propertyLabel, contents.referencedIn)) 136 .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); 137 for (Entry<String, List<IndexItem>> entry : searchIndexMap.entrySet()) { 138 Content propertyName = Text.of(entry.getKey()); 139 List<IndexItem> searchIndexItems = entry.getValue(); 140 Content separatedReferenceLinks = new ContentBuilder(); 141 separatedReferenceLinks.add(createLink(searchIndexItems.get(0))); 142 for (int i = 1; i < searchIndexItems.size(); i++) { 143 separatedReferenceLinks.add(separator); 144 separatedReferenceLinks 145 .add(createLink(searchIndexItems.get(i))); 146 } 147 table.addRow(propertyName, 148 HtmlTree.DIV(HtmlStyle.block, separatedReferenceLinks)); 149 } 150 target.add(table); 151 } 152 153 private Map<String, List<IndexItem>> groupSystemProperties() { 154 return configuration.mainIndex.getItems(DocTree.Kind.SYSTEM_PROPERTY) 155 .stream() 156 .collect(groupingBy(IndexItem::getLabel, TreeMap::new, 157 Collectors.toCollection(ArrayList::new))); 158 } 159 160 private Content createLink(IndexItem i) { 161 assert i.getDocTree().getKind() == DocTree.Kind.SYSTEM_PROPERTY : i; 162 Element element = i.getElement(); 163 if (element instanceof OverviewElement) { 164 return links.createLink(pathToRoot.resolve(i.getUrl()), 165 resources.getText("doclet.Overview")); 166 } else if (element instanceof DocletElement e) { 167 // Implementations of DocletElement do not override equals and 168 // hashCode; putting instances of DocletElement in a map is not 169 // incorrect, but might well be inefficient 170 String t = titles.computeIfAbsent(element, utils::getHTMLTitle); 171 if (t.isBlank()) { 172 // The user should probably be notified (a warning?) that this 173 // file does not have a title 174 Path p = Path.of(e.getFileObject().toUri()); 175 t = p.getFileName().toString(); 176 } 177 ContentBuilder b = new ContentBuilder(); 178 b.add(HtmlTree.CODE(Text.of(i.getHolder() + ": "))); 179 // non-program elements should be displayed using a normal font 180 b.add(t); 181 return links.createLink(pathToRoot.resolve(i.getUrl()), b); 182 } else { 183 // program elements should be displayed using a code font 184 Content link = links.createLink(pathToRoot.resolve(i.getUrl()), 185 i.getHolder()); 186 return HtmlTree.CODE(link); 187 } 188 } 189}