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