langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/ClassTree.java
changeset 10 06bc494ca11e
child 868 d0f233085cbb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/ClassTree.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,375 @@
+/*
+ * Copyright 1998-2004 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.doclets.internal.toolkit.util;
+
+import com.sun.tools.doclets.internal.toolkit.*;
+import com.sun.javadoc.*;
+import java.util.*;
+
+/**
+ * Build Class Hierarchy for all the Classes. This class builds the Class
+ * Tree and the Interface Tree separately.
+ *
+ * This code is not part of an API.
+ * It is implementation that is subject to change.
+ * Do not use it as an API
+ *
+ * @see java.util.HashMap
+ * @see java.util.List
+ * @see com.sun.javadoc.Type
+ * @see com.sun.javadoc.ClassDoc
+ * @author Atul M Dambalkar
+ */
+public class ClassTree {
+
+    /**
+     * List of baseclasses. Contains only java.lang.Object. Can be used to get
+     * the mapped listing of sub-classes.
+     */
+    private List baseclasses = new ArrayList();
+
+    /**
+    * Mapping for each Class with their SubClasses
+    */
+    private Map subclasses = new HashMap();
+
+    /**
+     * List of base-interfaces. Contains list of all the interfaces who do not
+     * have super-interfaces. Can be used to get the mapped listing of
+     * sub-interfaces.
+     */
+    private List baseinterfaces = new ArrayList();
+
+    /**
+    * Mapping for each Interface with their SubInterfaces
+    */
+    private Map subinterfaces = new HashMap();
+
+    private List baseEnums = new ArrayList();
+    private Map subEnums = new HashMap();
+
+    private List baseAnnotationTypes = new ArrayList();
+    private Map subAnnotationTypes = new HashMap();
+
+    /**
+    * Mapping for each Interface with classes who implement it.
+    */
+    private Map implementingclasses = new HashMap();
+
+    /**
+     * Constructor. Build the Tree using the Root of this Javadoc run.
+     *
+     * @param configuration the configuration of the doclet.
+     * @param noDeprecated Don't add deprecated classes in the class tree, if
+     * true.
+     */
+    public ClassTree(Configuration configuration, boolean noDeprecated) {
+        configuration.message.notice("doclet.Building_Tree");
+        buildTree(configuration.root.classes(), configuration);
+    }
+
+    /**
+     * Constructor. Build the Tree using the Root of this Javadoc run.
+     *
+     * @param root Root of the Document.
+     * @param configuration The curren configuration of the doclet.
+     */
+    public ClassTree(RootDoc root, Configuration configuration) {
+        buildTree(root.classes(), configuration);
+    }
+
+    /**
+     * Constructor. Build the tree for the given array of classes.
+     *
+     * @param classes Array of classes.
+     * @param configuration The curren configuration of the doclet.
+     */
+    public ClassTree(ClassDoc[] classes, Configuration configuration) {
+        buildTree(classes, configuration);
+    }
+
+    /**
+     * Generate mapping for the sub-classes for every class in this run.
+     * Return the sub-class list for java.lang.Object which will be having
+     * sub-class listing for itself and also for each sub-class itself will
+     * have their own sub-class lists.
+     *
+     * @param classes all the classes in this run.
+     * @param configuration the current configuration of the doclet.
+     */
+    private void buildTree(ClassDoc[] classes, Configuration configuration) {
+        for (int i = 0; i < classes.length; i++) {
+            if (configuration.nodeprecated &&
+                    classes[i].tags("deprecated").length > 0) {
+                continue;
+            }
+            if (classes[i].isEnum()) {
+                processType(classes[i], configuration, baseEnums, subEnums);
+            } else if (classes[i].isClass()) {
+                processType(classes[i], configuration, baseclasses, subclasses);
+            } else if (classes[i].isInterface()) {
+                processInterface(classes[i]);
+                List list  = (List)implementingclasses.get(classes[i]);
+                if (list != null) {
+                    Collections.sort(list);
+                }
+            } else if (classes[i].isAnnotationType()) {
+                processType(classes[i], configuration, baseAnnotationTypes,
+                    subAnnotationTypes);
+            }
+        }
+
+        Collections.sort(baseinterfaces);
+        for (Iterator it = subinterfaces.values().iterator(); it.hasNext(); ) {
+            Collections.sort((List)it.next());
+        }
+        for (Iterator it = subclasses.values().iterator(); it.hasNext(); ) {
+            Collections.sort((List)it.next());
+        }
+    }
+
+    /**
+     * For the class passed map it to it's own sub-class listing.
+     * For the Class passed, get the super class,
+     * if superclass is non null, (it is not "java.lang.Object")
+     *    get the "value" from the hashmap for this key Class
+     *    if entry not found create one and get that.
+     *    add this Class as a sub class in the list
+     *    Recurse till hits java.lang.Object Null SuperClass.
+     *
+     * @param cd class for which sub-class mapping to be generated.
+     * @param configuration the current configurtation of the doclet.
+     */
+    private void processType(ClassDoc cd, Configuration configuration,
+            List bases, Map subs) {
+        ClassDoc superclass = Util.getFirstVisibleSuperClassCD(cd, configuration);
+        if (superclass != null) {
+            if (!add(subs, superclass, cd)) {
+                return;
+            } else {
+                processType(superclass, configuration, bases, subs);
+            }
+        } else {     // cd is java.lang.Object, add it once to the list
+            if (!bases.contains(cd)) {
+                bases.add(cd);
+            }
+        }
+        List intfacs = Util.getAllInterfaces(cd, configuration);
+        for (Iterator iter = intfacs.iterator(); iter.hasNext();) {
+            add(implementingclasses, ((Type) iter.next()).asClassDoc(), cd);
+        }
+    }
+
+    /**
+     * For the interface passed get the interfaces which it extends, and then
+     * put this interface in the sub-interface list of those interfaces. Do it
+     * recursively. If a interface doesn't have super-interface just attach
+     * that interface in the list of all the baseinterfaces.
+     *
+     * @param cd Interface under consideration.
+     */
+    private void processInterface(ClassDoc cd) {
+        ClassDoc[] intfacs = cd.interfaces();
+        if (intfacs.length > 0) {
+            for (int i = 0; i < intfacs.length; i++) {
+                if (!add(subinterfaces, intfacs[i], cd)) {
+                    return;
+                } else {
+                    processInterface(intfacs[i]);   // Recurse
+                }
+            }
+        } else {
+            // we need to add all the interfaces who do not have
+            // super-interfaces to baseinterfaces list to traverse them
+            if (!baseinterfaces.contains(cd)) {
+                baseinterfaces.add(cd);
+            }
+        }
+    }
+
+    /**
+     * Adjust the Class Tree. Add the class interface  in to it's super-class'
+     * or super-interface's sub-interface list.
+     *
+     * @param map the entire map.
+     * @param superclass java.lang.Object or the super-interface.
+     * @param cd sub-interface to be mapped.
+     * @returns boolean true if class added, false if class already processed.
+     */
+    private boolean add(Map map, ClassDoc superclass, ClassDoc cd) {
+        List list = (List)map.get(superclass);
+        if (list == null) {
+            list = new ArrayList();
+            map.put(superclass, list);
+        }
+        if (list.contains(cd)) {
+            return false;
+        } else {
+            list.add(cd);
+        }
+        return true;
+    }
+
+    /**
+     * From the map return the list of sub-classes or sub-interfaces. If list
+     * is null create a new one and return it.
+     *
+     * @param map The entire map.
+     * @param cd class for which the sub-class list is requested.
+     * @returns List Sub-Class list for the class passed.
+     */
+    private List get(Map map, ClassDoc cd) {
+        List list = (List)map.get(cd);
+        if (list == null) {
+            return new ArrayList();
+        }
+        return list;
+    }
+
+    /**
+     *  Return the sub-class list for the class passed.
+     *
+     * @param cd class whose sub-class list is required.
+     */
+    public List subclasses(ClassDoc cd) {
+        return get(subclasses, cd);
+    }
+
+    /**
+     *  Return the sub-interface list for the interface passed.
+     *
+     * @param cd interface whose sub-interface list is required.
+     */
+    public List subinterfaces(ClassDoc cd) {
+        return get(subinterfaces, cd);
+    }
+
+    /**
+     *  Return the list of classes which implement the interface passed.
+     *
+     * @param cd interface whose implementing-classes list is required.
+     */
+    public List implementingclasses(ClassDoc cd) {
+        List result = get(implementingclasses, cd);
+        List subinterfaces = allSubs(cd, false);
+
+        //If class x implements a subinterface of cd, then it follows
+        //that class x implements cd.
+        Iterator implementingClassesIter, subInterfacesIter = subinterfaces.listIterator();
+        ClassDoc c;
+        while(subInterfacesIter.hasNext()){
+            implementingClassesIter = implementingclasses((ClassDoc)
+                    subInterfacesIter.next()).listIterator();
+            while(implementingClassesIter.hasNext()){
+                c = (ClassDoc)implementingClassesIter.next();
+                if(! result.contains(c)){
+                    result.add(c);
+                }
+            }
+        }
+        Collections.sort(result);
+        return result;
+    }
+
+    /**
+     *  Return the sub-class/interface list for the class/interface passed.
+     *
+     * @param cd class/interface whose sub-class/interface list is required.
+     * @param isEnum true if the subclasses should be forced to come from the
+     * enum tree.
+     */
+    public List subs(ClassDoc cd, boolean isEnum) {
+        if (isEnum) {
+            return get(subEnums, cd);
+        } else if (cd.isAnnotationType()) {
+            return get(subAnnotationTypes, cd);
+        } else if (cd.isInterface()) {
+            return get(subinterfaces, cd);
+        } else if (cd.isClass()) {
+            return get(subclasses, cd);
+        } else {
+            return null;
+        }
+
+    }
+
+    /**
+     * Return a list of all direct or indirect, sub-classes and subinterfaces
+     * of the ClassDoc argument.
+     *
+     * @param cd ClassDoc whose sub-classes or sub-interfaces are requested.
+     * @param isEnum true if the subclasses should be forced to come from the
+     * enum tree.
+     */
+    public List allSubs(ClassDoc cd, boolean isEnum) {
+        List list = subs(cd, isEnum);
+        for (int i = 0; i < list.size(); i++) {
+            cd = (ClassDoc)list.get(i);
+            List tlist = subs(cd, isEnum);
+            for (int j = 0; j < tlist.size(); j++) {
+                ClassDoc tcd = (ClassDoc)tlist.get(j);
+                if (!list.contains(tcd)) {
+                    list.add(tcd);
+                }
+            }
+        }
+        Collections.sort(list);
+        return list;
+    }
+
+    /**
+     *  Return the base-classes list. This will have only one element namely
+     *  thw classdoc for java.lang.Object, since this is the base class for all
+     *  classes.
+     */
+    public List baseclasses() {
+        return baseclasses;
+    }
+
+    /**
+     *  Return the list of base interfaces. This is the list of interfaces
+     *  which do not have super-interface.
+     */
+    public List baseinterfaces() {
+        return baseinterfaces;
+    }
+
+    /**
+     *  Return the list of base enums. This is the list of enums
+     *  which do not have super-enums.
+     */
+    public List baseEnums() {
+        return baseEnums;
+    }
+
+    /**
+     *  Return the list of base annotation types. This is the list of
+     *  annotation types which do not have super-annotation types.
+     */
+    public List baseAnnotationTypes() {
+        return baseAnnotationTypes;
+    }
+}