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: }