1 /* 2 * Copyright (c) 1998, 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 26 package jdk.javadoc.internal.doclets.toolkit.util; 27 28 import java.util.*; 29 30 import javax.lang.model.element.Element; 31 import javax.lang.model.element.ModuleElement; 32 import javax.lang.model.element.PackageElement; 33 import javax.lang.model.element.TypeElement; 34 35 import jdk.javadoc.doclet.DocletEnvironment; 36 import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; 37 import jdk.javadoc.internal.doclets.toolkit.Messages; 38 39 /** 40 * Build the mapping of each Unicode character with it's member lists 41 * containing members names starting with it. Also build a list for all the 42 * Unicode characters which start a member name. Member name is 43 * classkind or field or method or constructor name. 44 * 45 * <p><b>This is NOT part of any supported API. 46 * If you write code that depends on this, you do so at your own risk. 47 * This code and its internal interfaces are subject to change or 48 * deletion without notice.</b> 49 * 50 * @see java.lang.Character 51 * @author Atul M Dambalkar 52 */ 53 public class IndexBuilder { 54 55 /** 56 * Mapping of each Unicode Character with the member list containing 57 * members with names starting with it. 58 */ 59 private final Map<Character, SortedSet<Element>> indexmap; 60 61 /** 62 * Don't generate deprecated information if true. 63 */ 64 private boolean noDeprecated; 65 66 /** 67 * Build this Index only for classes? 68 */ 69 private boolean classesOnly; 70 71 /** 72 * Indicates javafx mode. 73 */ 74 private boolean javafx; 75 76 private final BaseConfiguration configuration; 77 private final Utils utils; 78 private final Comparator<Element> comparator; 79 80 /** 81 * Constructor. Build the index map. 82 * 83 * @param configuration the current configuration of the doclet. 84 * @param noDeprecated true if -nodeprecated option is used, 85 * false otherwise. 86 */ 87 public IndexBuilder(BaseConfiguration configuration, boolean noDeprecated) { 88 this(configuration, noDeprecated, false); 89 } 90 91 /** 92 * Constructor. Build the index map. 93 * 94 * @param configuration the current configuration of the doclet. 95 * @param noDeprecated true if -nodeprecated option is used, 96 * false otherwise. 97 * @param classesOnly Include only classes in index. 98 */ 99 public IndexBuilder(BaseConfiguration configuration, boolean noDeprecated, 100 boolean classesOnly) { 101 this.configuration = configuration; 102 this.utils = configuration.utils; 103 104 Messages messages = configuration.getMessages(); 105 if (classesOnly) { 106 messages.notice("doclet.Building_Index_For_All_Classes"); 107 } else { 108 messages.notice("doclet.Building_Index"); 109 } 110 111 this.noDeprecated = noDeprecated; 112 this.classesOnly = classesOnly; 113 this.javafx = configuration.javafx; 114 this.indexmap = new TreeMap<>(); 115 comparator = classesOnly 116 ? utils.makeAllClassesComparator() 117 : utils.makeIndexUseComparator(); 118 buildIndexMap(configuration.docEnv); 119 } 120 121 /** 122 * Get all the members in all the Packages and all the Classes 123 * given on the command line. Form separate list of those members depending 124 * upon their names. 125 * 126 * @param docEnv the doclet environment 127 */ 128 protected void buildIndexMap(DocletEnvironment docEnv) { 129 Set<PackageElement> packages = configuration.getSpecifiedPackageElements(); 130 Set<TypeElement> classes = configuration.getIncludedTypeElements(); 131 if (!classesOnly) { 132 if (packages.isEmpty()) { 133 Set<PackageElement> set = new HashSet<>(); 134 for (TypeElement aClass : classes) { 135 PackageElement pkg = utils.containingPackage(aClass); 136 if (pkg != null && !pkg.isUnnamed()) { 137 set.add(pkg); 138 } 139 } 140 adjustIndexMap(set); 141 } else { 142 adjustIndexMap(packages); 143 } 144 } 145 adjustIndexMap(classes); 146 if (!classesOnly) { 147 for (TypeElement aClass : classes) { 148 if (shouldAddToIndexMap(aClass)) { 149 putMembersInIndexMap(aClass); 150 } 151 } 152 if (configuration.showModules) { 153 addModulesToIndexMap(); 154 } 155 } 156 } 157 158 /** 159 * Put all the members(fields, methods and constructors) in the te 160 * to the indexmap. 161 * 162 * @param te TypeElement whose members will be added to the indexmap. 163 */ 164 protected void putMembersInIndexMap(TypeElement te) { 165 adjustIndexMap(utils.getAnnotationFields(te)); 166 adjustIndexMap(utils.getFields(te)); 167 adjustIndexMap(utils.getMethods(te)); 168 adjustIndexMap(utils.getConstructors(te)); 169 adjustIndexMap(utils.getEnumConstants(te)); 170 } 171 172 173 /** 174 * Adjust list of members according to their names. Check the first 175 * character in a member name, and then add the member to a list of members 176 * for that particular unicode character. 177 * 178 * @param elements Array of members. 179 */ 180 protected void adjustIndexMap(Iterable<? extends Element> elements) { 181 for (Element element : elements) { 182 if (shouldAddToIndexMap(element)) { 183 String name = utils.isPackage(element) 184 ? utils.getPackageName((PackageElement)element) 185 : utils.getSimpleName(element); 186 char ch = (name.length() == 0) ? 187 '*' : 188 Character.toUpperCase(name.charAt(0)); 189 Character unicode = ch; 190 SortedSet<Element> list = indexmap.computeIfAbsent(unicode, 191 c -> new TreeSet<>(comparator)); 192 list.add(element); 193 } 194 } 195 } 196 197 /** 198 * Add all the modules to index map. 199 */ 200 protected void addModulesToIndexMap() { 201 for (ModuleElement mdle : configuration.modules) { 202 String mdleName = mdle.getQualifiedName().toString(); 203 char ch = (mdleName.length() == 0) 204 ? '*' 205 : Character.toUpperCase(mdleName.charAt(0)); 206 Character unicode = ch; 207 SortedSet<Element> list = indexmap.computeIfAbsent(unicode, 208 c -> new TreeSet<>(comparator)); 209 list.add(mdle); 210 } 211 } 212 213 /** 214 * Should this element be added to the index map? 215 */ 216 protected boolean shouldAddToIndexMap(Element element) { 217 if (utils.isHidden(element)) { 218 return false; 219 } 220 221 if (utils.isPackage(element)) 222 // Do not add to index map if -nodeprecated option is set and the 223 // package is marked as deprecated. 224 return !(noDeprecated && configuration.utils.isDeprecated(element)); 225 else 226 // Do not add to index map if -nodeprecated option is set and if the 227 // element is marked as deprecated or the containing package is marked as 228 // deprecated. 229 return !(noDeprecated && 230 (configuration.utils.isDeprecated(element) || 231 configuration.utils.isDeprecated(utils.containingPackage(element)))); 232 } 233 234 /** 235 * Return a map of all the individual member lists with Unicode character. 236 * 237 * @return Map index map. 238 */ 239 public Map<Character, SortedSet<Element>> getIndexMap() { 240 return indexmap; 241 } 242 243 /** 244 * Return the sorted list of members, for passed Unicode Character. 245 * 246 * @param index index Unicode character. 247 * @return List member list for specific Unicode character. 248 */ 249 public List<? extends Element> getMemberList(Character index) { 250 SortedSet<Element> set = indexmap.get(index); 251 if (set == null) 252 return null; 253 List<Element> out = new ArrayList<>(); 254 out.addAll(set); 255 return out; 256 } 257 258 /** 259 * Array of IndexMap keys, Unicode characters. 260 */ 261 public List<Character> index() { 262 return new ArrayList<>(indexmap.keySet()); 263 } 264 }