View Javadoc
1   /*
2    * Copyright (c) 1998, 2013, 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 com.sun.tools.doclets.internal.toolkit.util;
27  
28  import java.util.*;
29  
30  import com.sun.javadoc.*;
31  import com.sun.tools.doclets.internal.toolkit.*;
32  
33  /**
34   * Build Class Hierarchy for all the Classes. This class builds the Class
35   * Tree and the Interface Tree separately.
36   *
37   *  <p><b>This is NOT part of any supported API.
38   *  If you write code that depends on this, you do so at your own risk.
39   *  This code and its internal interfaces are subject to change or
40   *  deletion without notice.</b>
41   *
42   * @see java.util.HashMap
43   * @see java.util.List
44   * @see com.sun.javadoc.Type
45   * @see com.sun.javadoc.ClassDoc
46   * @author Atul M Dambalkar
47   */
48  public class ClassTree {
49  
50      /**
51       * List of baseclasses. Contains only java.lang.Object. Can be used to get
52       * the mapped listing of sub-classes.
53       */
54      private List<ClassDoc> baseclasses = new ArrayList<ClassDoc>();
55  
56      /**
57      * Mapping for each Class with their SubClasses
58      */
59      private Map<ClassDoc,List<ClassDoc>> subclasses = new HashMap<ClassDoc,List<ClassDoc>>();
60  
61      /**
62       * List of base-interfaces. Contains list of all the interfaces who do not
63       * have super-interfaces. Can be used to get the mapped listing of
64       * sub-interfaces.
65       */
66      private List<ClassDoc> baseinterfaces = new ArrayList<ClassDoc>();
67  
68      /**
69      * Mapping for each Interface with their SubInterfaces
70      */
71      private Map<ClassDoc,List<ClassDoc>> subinterfaces = new HashMap<ClassDoc,List<ClassDoc>>();
72  
73      private List<ClassDoc> baseEnums = new ArrayList<ClassDoc>();
74      private Map<ClassDoc,List<ClassDoc>> subEnums = new HashMap<ClassDoc,List<ClassDoc>>();
75  
76      private List<ClassDoc> baseAnnotationTypes = new ArrayList<ClassDoc>();
77      private Map<ClassDoc,List<ClassDoc>> subAnnotationTypes = new HashMap<ClassDoc,List<ClassDoc>>();
78  
79      /**
80      * Mapping for each Interface with classes who implement it.
81      */
82      private Map<ClassDoc,List<ClassDoc>> implementingclasses = new HashMap<ClassDoc,List<ClassDoc>>();
83  
84      /**
85       * Constructor. Build the Tree using the Root of this Javadoc run.
86       *
87       * @param configuration the configuration of the doclet.
88       * @param noDeprecated Don't add deprecated classes in the class tree, if
89       * true.
90       */
91      public ClassTree(Configuration configuration, boolean noDeprecated) {
92          configuration.message.notice("doclet.Building_Tree");
93          buildTree(configuration.root.classes(), configuration);
94      }
95  
96      /**
97       * Constructor. Build the Tree using the Root of this Javadoc run.
98       *
99       * @param root Root of the Document.
100      * @param configuration The curren configuration of the doclet.
101      */
102     public ClassTree(RootDoc root, Configuration configuration) {
103         buildTree(root.classes(), configuration);
104     }
105 
106     /**
107      * Constructor. Build the tree for the given array of classes.
108      *
109      * @param classes Array of classes.
110      * @param configuration The curren configuration of the doclet.
111      */
112     public ClassTree(ClassDoc[] classes, Configuration configuration) {
113         buildTree(classes, configuration);
114     }
115 
116     /**
117      * Generate mapping for the sub-classes for every class in this run.
118      * Return the sub-class list for java.lang.Object which will be having
119      * sub-class listing for itself and also for each sub-class itself will
120      * have their own sub-class lists.
121      *
122      * @param classes all the classes in this run.
123      * @param configuration the current configuration of the doclet.
124      */
125     private void buildTree(ClassDoc[] classes, Configuration configuration) {
126         for (int i = 0; i < classes.length; i++) {
127             // In the tree page (e.g overview-tree.html) do not include
128             // information of classes which are deprecated or are a part of a
129             // deprecated package.
130             if (configuration.nodeprecated &&
131                     (Util.isDeprecated(classes[i]) ||
132                     Util.isDeprecated(classes[i].containingPackage()))) {
133                 continue;
134             }
135 
136             if (configuration.javafx
137                     && classes[i].tags("treatAsPrivate").length > 0) {
138                 continue;
139             }
140 
141             if (classes[i].isEnum()) {
142                 processType(classes[i], configuration, baseEnums, subEnums);
143             } else if (classes[i].isClass()) {
144                 processType(classes[i], configuration, baseclasses, subclasses);
145             } else if (classes[i].isInterface()) {
146                 processInterface(classes[i]);
147                 List<ClassDoc> list = implementingclasses.get(classes[i]);
148                 if (list != null) {
149                     Collections.sort(list);
150                 }
151             } else if (classes[i].isAnnotationType()) {
152                 processType(classes[i], configuration, baseAnnotationTypes,
153                     subAnnotationTypes);
154             }
155         }
156 
157         Collections.sort(baseinterfaces);
158         for (Iterator<List<ClassDoc>> it = subinterfaces.values().iterator(); it.hasNext(); ) {
159             Collections.sort(it.next());
160         }
161         for (Iterator<List<ClassDoc>> it = subclasses.values().iterator(); it.hasNext(); ) {
162             Collections.sort(it.next());
163         }
164     }
165 
166     /**
167      * For the class passed map it to it's own sub-class listing.
168      * For the Class passed, get the super class,
169      * if superclass is non null, (it is not "java.lang.Object")
170      *    get the "value" from the hashmap for this key Class
171      *    if entry not found create one and get that.
172      *    add this Class as a sub class in the list
173      *    Recurse till hits java.lang.Object Null SuperClass.
174      *
175      * @param cd class for which sub-class mapping to be generated.
176      * @param configuration the current configurtation of the doclet.
177      */
178     private void processType(ClassDoc cd, Configuration configuration,
179             List<ClassDoc> bases, Map<ClassDoc,List<ClassDoc>> subs) {
180         ClassDoc superclass = Util.getFirstVisibleSuperClassCD(cd, configuration);
181         if (superclass != null) {
182             if (!add(subs, superclass, cd)) {
183                 return;
184             } else {
185                 processType(superclass, configuration, bases, subs);
186             }
187         } else {     // cd is java.lang.Object, add it once to the list
188             if (!bases.contains(cd)) {
189                 bases.add(cd);
190             }
191         }
192         List<Type> intfacs = Util.getAllInterfaces(cd, configuration);
193         for (Iterator<Type> iter = intfacs.iterator(); iter.hasNext();) {
194             add(implementingclasses, iter.next().asClassDoc(), cd);
195         }
196     }
197 
198     /**
199      * For the interface passed get the interfaces which it extends, and then
200      * put this interface in the sub-interface list of those interfaces. Do it
201      * recursively. If a interface doesn't have super-interface just attach
202      * that interface in the list of all the baseinterfaces.
203      *
204      * @param cd Interface under consideration.
205      */
206     private void processInterface(ClassDoc cd) {
207         ClassDoc[] intfacs = cd.interfaces();
208         if (intfacs.length > 0) {
209             for (int i = 0; i < intfacs.length; i++) {
210                 if (!add(subinterfaces, intfacs[i], cd)) {
211                     return;
212                 } else {
213                     processInterface(intfacs[i]);   // Recurse
214                 }
215             }
216         } else {
217             // we need to add all the interfaces who do not have
218             // super-interfaces to baseinterfaces list to traverse them
219             if (!baseinterfaces.contains(cd)) {
220                 baseinterfaces.add(cd);
221             }
222         }
223     }
224 
225     /**
226      * Adjust the Class Tree. Add the class interface  in to it's super-class'
227      * or super-interface's sub-interface list.
228      *
229      * @param map the entire map.
230      * @param superclass java.lang.Object or the super-interface.
231      * @param cd sub-interface to be mapped.
232      * @returns boolean true if class added, false if class already processed.
233      */
234     private boolean add(Map<ClassDoc,List<ClassDoc>> map, ClassDoc superclass, ClassDoc cd) {
235         List<ClassDoc> list = map.get(superclass);
236         if (list == null) {
237             list = new ArrayList<ClassDoc>();
238             map.put(superclass, list);
239         }
240         if (list.contains(cd)) {
241             return false;
242         } else {
243             list.add(cd);
244         }
245         return true;
246     }
247 
248     /**
249      * From the map return the list of sub-classes or sub-interfaces. If list
250      * is null create a new one and return it.
251      *
252      * @param map The entire map.
253      * @param cd class for which the sub-class list is requested.
254      * @returns List Sub-Class list for the class passed.
255      */
256     private List<ClassDoc> get(Map<ClassDoc,List<ClassDoc>> map, ClassDoc cd) {
257         List<ClassDoc> list = map.get(cd);
258         if (list == null) {
259             return new ArrayList<ClassDoc>();
260         }
261         return list;
262     }
263 
264     /**
265      *  Return the sub-class list for the class passed.
266      *
267      * @param cd class whose sub-class list is required.
268      */
269     public List<ClassDoc> subclasses(ClassDoc cd) {
270         return get(subclasses, cd);
271     }
272 
273     /**
274      *  Return the sub-interface list for the interface passed.
275      *
276      * @param cd interface whose sub-interface list is required.
277      */
278     public List<ClassDoc> subinterfaces(ClassDoc cd) {
279         return get(subinterfaces, cd);
280     }
281 
282     /**
283      *  Return the list of classes which implement the interface passed.
284      *
285      * @param cd interface whose implementing-classes list is required.
286      */
287     public List<ClassDoc> implementingclasses(ClassDoc cd) {
288         List<ClassDoc> result = get(implementingclasses, cd);
289         List<ClassDoc> subinterfaces = allSubs(cd, false);
290 
291         //If class x implements a subinterface of cd, then it follows
292         //that class x implements cd.
293         Iterator<ClassDoc> implementingClassesIter, subInterfacesIter = subinterfaces.listIterator();
294         ClassDoc c;
295         while(subInterfacesIter.hasNext()){
296             implementingClassesIter = implementingclasses(
297                     subInterfacesIter.next()).listIterator();
298             while(implementingClassesIter.hasNext()){
299                 c = implementingClassesIter.next();
300                 if(! result.contains(c)){
301                     result.add(c);
302                 }
303             }
304         }
305         Collections.sort(result);
306         return result;
307     }
308 
309     /**
310      *  Return the sub-class/interface list for the class/interface passed.
311      *
312      * @param cd class/interface whose sub-class/interface list is required.
313      * @param isEnum true if the subclasses should be forced to come from the
314      * enum tree.
315      */
316     public List<ClassDoc> subs(ClassDoc cd, boolean isEnum) {
317         if (isEnum) {
318             return get(subEnums, cd);
319         } else if (cd.isAnnotationType()) {
320             return get(subAnnotationTypes, cd);
321         } else if (cd.isInterface()) {
322             return get(subinterfaces, cd);
323         } else if (cd.isClass()) {
324             return get(subclasses, cd);
325         } else {
326             return null;
327         }
328 
329     }
330 
331     /**
332      * Return a list of all direct or indirect, sub-classes and subinterfaces
333      * of the ClassDoc argument.
334      *
335      * @param cd ClassDoc whose sub-classes or sub-interfaces are requested.
336      * @param isEnum true if the subclasses should be forced to come from the
337      * enum tree.
338      */
339     public List<ClassDoc> allSubs(ClassDoc cd, boolean isEnum) {
340         List<ClassDoc> list = subs(cd, isEnum);
341         for (int i = 0; i < list.size(); i++) {
342             cd = list.get(i);
343             List<ClassDoc> tlist = subs(cd, isEnum);
344             for (int j = 0; j < tlist.size(); j++) {
345                 ClassDoc tcd = tlist.get(j);
346                 if (!list.contains(tcd)) {
347                     list.add(tcd);
348                 }
349             }
350         }
351         Collections.sort(list);
352         return list;
353     }
354 
355     /**
356      *  Return the base-classes list. This will have only one element namely
357      *  thw classdoc for java.lang.Object, since this is the base class for all
358      *  classes.
359      */
360     public List<ClassDoc> baseclasses() {
361         return baseclasses;
362     }
363 
364     /**
365      *  Return the list of base interfaces. This is the list of interfaces
366      *  which do not have super-interface.
367      */
368     public List<ClassDoc> baseinterfaces() {
369         return baseinterfaces;
370     }
371 
372     /**
373      *  Return the list of base enums. This is the list of enums
374      *  which do not have super-enums.
375      */
376     public List<ClassDoc> baseEnums() {
377         return baseEnums;
378     }
379 
380     /**
381      *  Return the list of base annotation types. This is the list of
382      *  annotation types which do not have super-annotation types.
383      */
384     public List<ClassDoc> baseAnnotationTypes() {
385         return baseAnnotationTypes;
386     }
387 }