1 /* 2 * Copyright (c) 2003, 2016, 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.toolkit.builders; 27 28 import java.io.*; 29 import java.util.*; 30 31 import javax.lang.model.element.Element; 32 import javax.lang.model.element.PackageElement; 33 import javax.lang.model.element.TypeElement; 34 import javax.lang.model.element.VariableElement; 35 36 import jdk.javadoc.internal.doclets.toolkit.ConstantsSummaryWriter; 37 import jdk.javadoc.internal.doclets.toolkit.Content; 38 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; 39 40 41 /** 42 * Builds the Constants Summary Page. 43 * 44 * <p><b>This is NOT part of any supported API. 45 * If you write code that depends on this, you do so at your own risk. 46 * This code and its internal interfaces are subject to change or 47 * deletion without notice.</b> 48 * 49 * @author Jamie Ho 50 * @author Bhavesh Patel (Modified) 51 * @since 1.5 52 */ 53 public class ConstantsSummaryBuilder extends AbstractBuilder { 54 55 /** 56 * The root element of the constant summary XML is {@value}. 57 */ 58 public static final String ROOT = "ConstantSummary"; 59 60 /** 61 * The maximum number of package directories shown in the constant 62 * value index. 63 */ 64 public static final int MAX_CONSTANT_VALUE_INDEX_LENGTH = 2; 65 66 /** 67 * The writer used to write the results. 68 */ 69 protected final ConstantsSummaryWriter writer; 70 71 /** 72 * The set of TypeElements that have constant fields. 73 */ 74 protected final Set<TypeElement> typeElementsWithConstFields; 75 76 /** 77 * The set of printed package headers. 78 */ 79 protected final Set<PackageElement> printedPackageHeaders; 80 81 /** 82 * The current package being documented. 83 */ 84 private PackageElement currentPackage; 85 86 /** 87 * The current class being documented. 88 */ 89 private TypeElement currentClass; 90 91 /** 92 * The content tree for the constant summary documentation. 93 */ 94 private Content contentTree; 95 96 /** 97 * True if first package is listed. 98 */ 99 private boolean first = true; 100 101 /** 102 * Construct a new ConstantsSummaryBuilder. 103 * 104 * @param context the build context. 105 * @param writer the writer for the summary. 106 */ 107 private ConstantsSummaryBuilder(Context context, 108 ConstantsSummaryWriter writer) { 109 super(context); 110 this.writer = writer; 111 this.typeElementsWithConstFields = new HashSet<>(); 112 this.printedPackageHeaders = new TreeSet<>(utils.makePackageComparator()); 113 } 114 115 /** 116 * Construct a ConstantsSummaryBuilder. 117 * 118 * @param context the build context. 119 * @param writer the writer for the summary. 120 */ 121 public static ConstantsSummaryBuilder getInstance(Context context, 122 ConstantsSummaryWriter writer) { 123 return new ConstantsSummaryBuilder(context, writer); 124 } 125 126 /** 127 * {@inheritDoc} 128 */ 129 @Override 130 public void build() throws IOException { 131 if (writer == null) { 132 //Doclet does not support this output. 133 return; 134 } 135 build(layoutParser.parseXML(ROOT), contentTree); 136 } 137 138 /** 139 * {@inheritDoc} 140 */ 141 @Override 142 public String getName() { 143 return ROOT; 144 } 145 146 /** 147 * Build the constant summary. 148 * 149 * @param node the XML element that specifies which components to document 150 * @param contentTree the content tree to which the documentation will be added 151 */ 152 public void buildConstantSummary(XMLNode node, Content contentTree) throws Exception { 153 contentTree = writer.getHeader(); 154 buildChildren(node, contentTree); 155 writer.addFooter(contentTree); 156 writer.printDocument(contentTree); 157 writer.close(); 158 } 159 160 /** 161 * Build the list of packages. 162 * 163 * @param node the XML element that specifies which components to document 164 * @param contentTree the content tree to which the content list will be added 165 */ 166 public void buildContents(XMLNode node, Content contentTree) { 167 Content contentListTree = writer.getContentsHeader(); 168 printedPackageHeaders.clear(); 169 for (PackageElement pkg : configuration.packages) { 170 if (hasConstantField(pkg) && !hasPrintedPackageIndex(pkg)) { 171 writer.addLinkToPackageContent(pkg, printedPackageHeaders, contentListTree); 172 } 173 } 174 writer.addContentsList(contentTree, contentListTree); 175 } 176 177 /** 178 * Build the summary for each documented package. 179 * 180 * @param node the XML element that specifies which components to document 181 * @param contentTree the tree to which the summaries will be added 182 */ 183 public void buildConstantSummaries(XMLNode node, Content contentTree) { 184 printedPackageHeaders.clear(); 185 Content summariesTree = writer.getConstantSummaries(); 186 for (PackageElement aPackage : configuration.packages) { 187 if (hasConstantField(aPackage)) { 188 currentPackage = aPackage; 189 //Build the documentation for the current package. 190 buildChildren(node, summariesTree); 191 first = false; 192 } 193 } 194 writer.addConstantSummaries(contentTree, summariesTree); 195 } 196 197 /** 198 * Build the header for the given package. 199 * 200 * @param node the XML element that specifies which components to document 201 * @param summariesTree the tree to which the package header will be added 202 */ 203 public void buildPackageHeader(XMLNode node, Content summariesTree) { 204 String parsedPackageName = utils.parsePackageName(currentPackage); 205 PackageElement p = utils.elementUtils.getPackageElement(parsedPackageName); 206 if (!printedPackageHeaders.contains(p)) { 207 writer.addPackageName(currentPackage, summariesTree, first); 208 printedPackageHeaders.add(p); 209 } 210 } 211 212 /** 213 * Build the summary for the current class. 214 * 215 * @param node the XML element that specifies which components to document 216 * @param summariesTree the tree to which the class constant summary will be added 217 */ 218 public void buildClassConstantSummary(XMLNode node, Content summariesTree) { 219 SortedSet<TypeElement> classes = !currentPackage.isUnnamed() 220 ? utils.getAllClasses(currentPackage) 221 : configuration.classDocCatalog.allUnnamedClasses(); 222 Content classConstantTree = writer.getClassConstantHeader(); 223 for (TypeElement te : classes) { 224 if (!typeElementsWithConstFields.contains(te) || 225 !utils.isIncluded(te)) { 226 continue; 227 } 228 currentClass = te; 229 //Build the documentation for the current class. 230 buildChildren(node, classConstantTree); 231 } 232 writer.addClassConstant(summariesTree, classConstantTree); 233 } 234 235 /** 236 * Build the summary of constant members in the class. 237 * 238 * @param node the XML element that specifies which components to document 239 * @param classConstantTree the tree to which the constant members table 240 * will be added 241 */ 242 public void buildConstantMembers(XMLNode node, Content classConstantTree) { 243 new ConstantFieldBuilder(currentClass).buildMembersSummary(node, classConstantTree); 244 } 245 246 /** 247 * Return true if the given package has constant fields to document. 248 * 249 * @param pkg the package being checked. 250 * @return true if the given package has constant fields to document. 251 */ 252 private boolean hasConstantField(PackageElement pkg) { 253 SortedSet<TypeElement> classes = !pkg.isUnnamed() 254 ? utils.getAllClasses(pkg) 255 : configuration.classDocCatalog.allUnnamedClasses(); 256 boolean found = false; 257 for (TypeElement te : classes) { 258 if (utils.isIncluded(te) && hasConstantField(te)) { 259 found = true; 260 } 261 } 262 return found; 263 } 264 265 /** 266 * Return true if the given class has constant fields to document. 267 * 268 * @param typeElement the class being checked. 269 * @return true if the given package has constant fields to document. 270 */ 271 private boolean hasConstantField (TypeElement typeElement) { 272 VisibleMemberMap visibleMemberMapFields = new VisibleMemberMap(typeElement, 273 VisibleMemberMap.Kind.FIELDS, configuration); 274 SortedSet<Element> fields = visibleMemberMapFields.getLeafClassMembers(); 275 for (Element f : fields) { 276 VariableElement field = (VariableElement)f; 277 if (field.getConstantValue() != null) { 278 typeElementsWithConstFields.add(typeElement); 279 return true; 280 } 281 } 282 return false; 283 } 284 285 /** 286 * Return true if the given package name has been printed. Also 287 * return true if the root of this package has been printed. 288 * 289 * @param pkgname the name of the package to check. 290 */ 291 private boolean hasPrintedPackageIndex(PackageElement pkg) { 292 for (PackageElement printedPkg : printedPackageHeaders) { 293 if (utils.getPackageName(pkg).startsWith(utils.parsePackageName(printedPkg))) { 294 return true; 295 } 296 } 297 return false; 298 } 299 300 /** 301 * Print the table of constants. 302 * 303 * @author Jamie Ho 304 * @since 1.4 305 */ 306 private class ConstantFieldBuilder { 307 308 /** 309 * The map used to get the visible variables. 310 */ 311 protected VisibleMemberMap visibleMemberMapFields = null; 312 313 /** 314 * The map used to get the visible variables. 315 */ 316 protected VisibleMemberMap visibleMemberMapEnumConst = null; 317 318 /** 319 * The typeElement that we are examining constants for. 320 */ 321 protected TypeElement typeElement; 322 323 /** 324 * Construct a ConstantFieldSubWriter. 325 * @param typeElement the typeElement that we are examining constants for. 326 */ 327 public ConstantFieldBuilder(TypeElement typeElement) { 328 this.typeElement = typeElement; 329 visibleMemberMapFields = new VisibleMemberMap(typeElement, 330 VisibleMemberMap.Kind.FIELDS, configuration); 331 visibleMemberMapEnumConst = new VisibleMemberMap(typeElement, 332 VisibleMemberMap.Kind.ENUM_CONSTANTS, configuration); 333 } 334 335 /** 336 * Builds the table of constants for a given class. 337 * 338 * @param node the XML element that specifies which components to document 339 * @param classConstantTree the tree to which the class constants table 340 * will be added 341 */ 342 protected void buildMembersSummary(XMLNode node, Content classConstantTree) { 343 SortedSet<VariableElement> members = members(); 344 if (!members.isEmpty()) { 345 writer.addConstantMembers(typeElement, members, classConstantTree); 346 } 347 } 348 349 /** 350 * Return the list of visible constant fields for the given TypeElement. 351 * @return the list of visible constant fields for the given TypeElement. 352 */ 353 protected SortedSet<VariableElement> members() { 354 SortedSet<Element> list = visibleMemberMapFields.getLeafClassMembers(); 355 list.addAll(visibleMemberMapEnumConst.getLeafClassMembers()); 356 SortedSet<VariableElement> inclList = 357 new TreeSet<>(utils.makeGeneralPurposeComparator()); 358 for (Element element : list) { 359 VariableElement member = (VariableElement)element; 360 if (member.getConstantValue() != null) { 361 inclList.add(member); 362 } 363 } 364 return inclList; 365 } 366 } 367 }