duke@1: /* jjg@1357: * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as ohair@554: * published by the Free Software Foundation. Oracle designates this duke@1: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. duke@1: */ duke@1: duke@1: package com.sun.tools.doclets.internal.toolkit.util; duke@1: jjg@1357: import java.util.*; jjg@1357: jjg@1357: import com.sun.javadoc.*; duke@1: import com.sun.tools.doclets.internal.toolkit.*; duke@1: duke@1: /** duke@1: * Build Class Hierarchy for all the Classes. This class builds the Class duke@1: * Tree and the Interface Tree separately. duke@1: * jjg@1359: *

This is NOT part of any supported API. jjg@1359: * If you write code that depends on this, you do so at your own risk. jjg@1359: * This code and its internal interfaces are subject to change or jjg@1359: * deletion without notice. duke@1: * duke@1: * @see java.util.HashMap duke@1: * @see java.util.List duke@1: * @see com.sun.javadoc.Type duke@1: * @see com.sun.javadoc.ClassDoc duke@1: * @author Atul M Dambalkar duke@1: */ duke@1: public class ClassTree { duke@1: duke@1: /** duke@1: * List of baseclasses. Contains only java.lang.Object. Can be used to get duke@1: * the mapped listing of sub-classes. duke@1: */ jjg@74: private List baseclasses = new ArrayList(); duke@1: duke@1: /** duke@1: * Mapping for each Class with their SubClasses duke@1: */ jjg@74: private Map> subclasses = new HashMap>(); duke@1: duke@1: /** duke@1: * List of base-interfaces. Contains list of all the interfaces who do not duke@1: * have super-interfaces. Can be used to get the mapped listing of duke@1: * sub-interfaces. duke@1: */ jjg@74: private List baseinterfaces = new ArrayList(); duke@1: duke@1: /** duke@1: * Mapping for each Interface with their SubInterfaces duke@1: */ jjg@74: private Map> subinterfaces = new HashMap>(); duke@1: jjg@74: private List baseEnums = new ArrayList(); jjg@74: private Map> subEnums = new HashMap>(); duke@1: jjg@74: private List baseAnnotationTypes = new ArrayList(); jjg@74: private Map> subAnnotationTypes = new HashMap>(); duke@1: duke@1: /** duke@1: * Mapping for each Interface with classes who implement it. duke@1: */ jjg@74: private Map> implementingclasses = new HashMap>(); duke@1: duke@1: /** duke@1: * Constructor. Build the Tree using the Root of this Javadoc run. duke@1: * duke@1: * @param configuration the configuration of the doclet. duke@1: * @param noDeprecated Don't add deprecated classes in the class tree, if duke@1: * true. duke@1: */ duke@1: public ClassTree(Configuration configuration, boolean noDeprecated) { duke@1: configuration.message.notice("doclet.Building_Tree"); duke@1: buildTree(configuration.root.classes(), configuration); duke@1: } duke@1: duke@1: /** duke@1: * Constructor. Build the Tree using the Root of this Javadoc run. duke@1: * duke@1: * @param root Root of the Document. duke@1: * @param configuration The curren configuration of the doclet. duke@1: */ duke@1: public ClassTree(RootDoc root, Configuration configuration) { duke@1: buildTree(root.classes(), configuration); duke@1: } duke@1: duke@1: /** duke@1: * Constructor. Build the tree for the given array of classes. duke@1: * duke@1: * @param classes Array of classes. duke@1: * @param configuration The curren configuration of the doclet. duke@1: */ duke@1: public ClassTree(ClassDoc[] classes, Configuration configuration) { duke@1: buildTree(classes, configuration); duke@1: } duke@1: duke@1: /** duke@1: * Generate mapping for the sub-classes for every class in this run. duke@1: * Return the sub-class list for java.lang.Object which will be having duke@1: * sub-class listing for itself and also for each sub-class itself will duke@1: * have their own sub-class lists. duke@1: * duke@1: * @param classes all the classes in this run. duke@1: * @param configuration the current configuration of the doclet. duke@1: */ duke@1: private void buildTree(ClassDoc[] classes, Configuration configuration) { duke@1: for (int i = 0; i < classes.length; i++) { bpatel@995: // In the tree page (e.g overview-tree.html) do not include bpatel@995: // information of classes which are deprecated or are a part of a bpatel@995: // deprecated package. duke@1: if (configuration.nodeprecated && bpatel@995: (Util.isDeprecated(classes[i]) || bpatel@995: Util.isDeprecated(classes[i].containingPackage()))) { duke@1: continue; duke@1: } duke@1: if (classes[i].isEnum()) { duke@1: processType(classes[i], configuration, baseEnums, subEnums); duke@1: } else if (classes[i].isClass()) { duke@1: processType(classes[i], configuration, baseclasses, subclasses); duke@1: } else if (classes[i].isInterface()) { duke@1: processInterface(classes[i]); jjg@74: List list = implementingclasses.get(classes[i]); duke@1: if (list != null) { duke@1: Collections.sort(list); duke@1: } duke@1: } else if (classes[i].isAnnotationType()) { duke@1: processType(classes[i], configuration, baseAnnotationTypes, duke@1: subAnnotationTypes); duke@1: } duke@1: } duke@1: duke@1: Collections.sort(baseinterfaces); jjg@74: for (Iterator> it = subinterfaces.values().iterator(); it.hasNext(); ) { jjg@74: Collections.sort(it.next()); duke@1: } jjg@74: for (Iterator> it = subclasses.values().iterator(); it.hasNext(); ) { jjg@74: Collections.sort(it.next()); duke@1: } duke@1: } duke@1: duke@1: /** duke@1: * For the class passed map it to it's own sub-class listing. duke@1: * For the Class passed, get the super class, duke@1: * if superclass is non null, (it is not "java.lang.Object") duke@1: * get the "value" from the hashmap for this key Class duke@1: * if entry not found create one and get that. duke@1: * add this Class as a sub class in the list duke@1: * Recurse till hits java.lang.Object Null SuperClass. duke@1: * duke@1: * @param cd class for which sub-class mapping to be generated. duke@1: * @param configuration the current configurtation of the doclet. duke@1: */ duke@1: private void processType(ClassDoc cd, Configuration configuration, jjg@74: List bases, Map> subs) { duke@1: ClassDoc superclass = Util.getFirstVisibleSuperClassCD(cd, configuration); duke@1: if (superclass != null) { duke@1: if (!add(subs, superclass, cd)) { duke@1: return; duke@1: } else { duke@1: processType(superclass, configuration, bases, subs); duke@1: } duke@1: } else { // cd is java.lang.Object, add it once to the list duke@1: if (!bases.contains(cd)) { duke@1: bases.add(cd); duke@1: } duke@1: } mcimadamore@184: List intfacs = Util.getAllInterfaces(cd, configuration); mcimadamore@184: for (Iterator iter = intfacs.iterator(); iter.hasNext();) { mcimadamore@184: add(implementingclasses, iter.next().asClassDoc(), cd); duke@1: } duke@1: } duke@1: duke@1: /** duke@1: * For the interface passed get the interfaces which it extends, and then duke@1: * put this interface in the sub-interface list of those interfaces. Do it duke@1: * recursively. If a interface doesn't have super-interface just attach duke@1: * that interface in the list of all the baseinterfaces. duke@1: * duke@1: * @param cd Interface under consideration. duke@1: */ duke@1: private void processInterface(ClassDoc cd) { duke@1: ClassDoc[] intfacs = cd.interfaces(); duke@1: if (intfacs.length > 0) { duke@1: for (int i = 0; i < intfacs.length; i++) { duke@1: if (!add(subinterfaces, intfacs[i], cd)) { duke@1: return; duke@1: } else { duke@1: processInterface(intfacs[i]); // Recurse duke@1: } duke@1: } duke@1: } else { duke@1: // we need to add all the interfaces who do not have duke@1: // super-interfaces to baseinterfaces list to traverse them duke@1: if (!baseinterfaces.contains(cd)) { duke@1: baseinterfaces.add(cd); duke@1: } duke@1: } duke@1: } duke@1: duke@1: /** duke@1: * Adjust the Class Tree. Add the class interface in to it's super-class' duke@1: * or super-interface's sub-interface list. duke@1: * duke@1: * @param map the entire map. duke@1: * @param superclass java.lang.Object or the super-interface. duke@1: * @param cd sub-interface to be mapped. duke@1: * @returns boolean true if class added, false if class already processed. duke@1: */ jjg@74: private boolean add(Map> map, ClassDoc superclass, ClassDoc cd) { jjg@74: List list = map.get(superclass); duke@1: if (list == null) { jjg@74: list = new ArrayList(); duke@1: map.put(superclass, list); duke@1: } duke@1: if (list.contains(cd)) { duke@1: return false; duke@1: } else { duke@1: list.add(cd); duke@1: } duke@1: return true; duke@1: } duke@1: duke@1: /** duke@1: * From the map return the list of sub-classes or sub-interfaces. If list duke@1: * is null create a new one and return it. duke@1: * duke@1: * @param map The entire map. duke@1: * @param cd class for which the sub-class list is requested. duke@1: * @returns List Sub-Class list for the class passed. duke@1: */ jjg@74: private List get(Map> map, ClassDoc cd) { jjg@74: List list = map.get(cd); duke@1: if (list == null) { jjg@74: return new ArrayList(); duke@1: } duke@1: return list; duke@1: } duke@1: duke@1: /** duke@1: * Return the sub-class list for the class passed. duke@1: * duke@1: * @param cd class whose sub-class list is required. duke@1: */ jjg@74: public List subclasses(ClassDoc cd) { duke@1: return get(subclasses, cd); duke@1: } duke@1: duke@1: /** duke@1: * Return the sub-interface list for the interface passed. duke@1: * duke@1: * @param cd interface whose sub-interface list is required. duke@1: */ jjg@74: public List subinterfaces(ClassDoc cd) { duke@1: return get(subinterfaces, cd); duke@1: } duke@1: duke@1: /** duke@1: * Return the list of classes which implement the interface passed. duke@1: * duke@1: * @param cd interface whose implementing-classes list is required. duke@1: */ jjg@74: public List implementingclasses(ClassDoc cd) { jjg@74: List result = get(implementingclasses, cd); jjg@74: List subinterfaces = allSubs(cd, false); duke@1: duke@1: //If class x implements a subinterface of cd, then it follows duke@1: //that class x implements cd. mcimadamore@184: Iterator implementingClassesIter, subInterfacesIter = subinterfaces.listIterator(); duke@1: ClassDoc c; duke@1: while(subInterfacesIter.hasNext()){ mcimadamore@184: implementingClassesIter = implementingclasses( duke@1: subInterfacesIter.next()).listIterator(); duke@1: while(implementingClassesIter.hasNext()){ mcimadamore@184: c = implementingClassesIter.next(); duke@1: if(! result.contains(c)){ duke@1: result.add(c); duke@1: } duke@1: } duke@1: } duke@1: Collections.sort(result); duke@1: return result; duke@1: } duke@1: duke@1: /** duke@1: * Return the sub-class/interface list for the class/interface passed. duke@1: * duke@1: * @param cd class/interface whose sub-class/interface list is required. duke@1: * @param isEnum true if the subclasses should be forced to come from the duke@1: * enum tree. duke@1: */ jjg@74: public List subs(ClassDoc cd, boolean isEnum) { duke@1: if (isEnum) { duke@1: return get(subEnums, cd); duke@1: } else if (cd.isAnnotationType()) { duke@1: return get(subAnnotationTypes, cd); duke@1: } else if (cd.isInterface()) { duke@1: return get(subinterfaces, cd); duke@1: } else if (cd.isClass()) { duke@1: return get(subclasses, cd); duke@1: } else { duke@1: return null; duke@1: } duke@1: duke@1: } duke@1: duke@1: /** duke@1: * Return a list of all direct or indirect, sub-classes and subinterfaces duke@1: * of the ClassDoc argument. duke@1: * duke@1: * @param cd ClassDoc whose sub-classes or sub-interfaces are requested. duke@1: * @param isEnum true if the subclasses should be forced to come from the duke@1: * enum tree. duke@1: */ jjg@74: public List allSubs(ClassDoc cd, boolean isEnum) { jjg@74: List list = subs(cd, isEnum); duke@1: for (int i = 0; i < list.size(); i++) { jjg@74: cd = list.get(i); mcimadamore@184: List tlist = subs(cd, isEnum); duke@1: for (int j = 0; j < tlist.size(); j++) { mcimadamore@184: ClassDoc tcd = tlist.get(j); duke@1: if (!list.contains(tcd)) { duke@1: list.add(tcd); duke@1: } duke@1: } duke@1: } duke@1: Collections.sort(list); duke@1: return list; duke@1: } duke@1: duke@1: /** duke@1: * Return the base-classes list. This will have only one element namely duke@1: * thw classdoc for java.lang.Object, since this is the base class for all duke@1: * classes. duke@1: */ mcimadamore@184: public List baseclasses() { duke@1: return baseclasses; duke@1: } duke@1: duke@1: /** duke@1: * Return the list of base interfaces. This is the list of interfaces duke@1: * which do not have super-interface. duke@1: */ mcimadamore@184: public List baseinterfaces() { duke@1: return baseinterfaces; duke@1: } duke@1: duke@1: /** duke@1: * Return the list of base enums. This is the list of enums duke@1: * which do not have super-enums. duke@1: */ mcimadamore@184: public List baseEnums() { duke@1: return baseEnums; duke@1: } duke@1: duke@1: /** duke@1: * Return the list of base annotation types. This is the list of duke@1: * annotation types which do not have super-annotation types. duke@1: */ mcimadamore@184: public List baseAnnotationTypes() { duke@1: return baseAnnotationTypes; duke@1: } duke@1: }