PackageInfo.java revision 5118ffe3bf77ec4efa070f36a7a62fd5d1bf16bf
1/*
2 * Copyright (C) 2010 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.doclava;
18
19import com.google.doclava.apicheck.ApiInfo;
20import com.google.clearsilver.jsilver.data.Data;
21
22import com.sun.javadoc.*;
23import java.util.*;
24
25public class PackageInfo extends DocInfo implements ContainerInfo {
26  public static final String DEFAULT_PACKAGE = "default package";
27
28  public static final Comparator<PackageInfo> comparator = new Comparator<PackageInfo>() {
29    public int compare(PackageInfo a, PackageInfo b) {
30      return a.name().compareTo(b.name());
31    }
32  };
33
34  public PackageInfo(PackageDoc pkg, String name, SourcePositionInfo position) {
35    super(pkg.getRawCommentText(), position);
36    if (name.isEmpty()) {
37      mName = DEFAULT_PACKAGE;
38    } else {
39      mName = name;
40    }
41
42    mPackage = pkg;
43    initializeMaps();
44  }
45
46  public PackageInfo(String name) {
47    super("", null);
48    mName = name;
49    initializeMaps();
50  }
51
52  public PackageInfo(String name, SourcePositionInfo position) {
53    super("", position);
54
55    if (name.isEmpty()) {
56      mName = "default package";
57    } else {
58      mName = name;
59    }
60    initializeMaps();
61  }
62
63  private void initializeMaps() {
64      mAnnotationsMap = new HashMap<String, ClassInfo>();
65      mInterfacesMap = new HashMap<String, ClassInfo>();
66      mOrdinaryClassesMap = new HashMap<String, ClassInfo>();
67      mEnumsMap = new HashMap<String, ClassInfo>();
68      mExceptionsMap = new HashMap<String, ClassInfo>();
69      mErrorsMap = new HashMap<String, ClassInfo>();
70  }
71
72  public String htmlPage() {
73    String s = mName;
74    s = s.replace('.', '/');
75    s += "/package-summary.html";
76    s = Doclava.javadocDir + s;
77    return s;
78  }
79
80  @Override
81  public ContainerInfo parent() {
82    return null;
83  }
84
85  @Override
86  public boolean isHidden() {
87    if (mHidden == null) {
88      if (hasHideComment()) {
89        // We change the hidden value of the package if a class wants to be not hidden.
90        ClassInfo[][] types = new ClassInfo[][] { annotations(), interfaces(), ordinaryClasses(),
91            enums(), exceptions() };
92        for (ClassInfo[] type : types) {
93          if (type != null) {
94            for (ClassInfo c : type) {
95              if (c.hasShowAnnotation()) {
96                mHidden = false;
97                return false;
98              }
99            }
100          }
101        }
102        mHidden = true;
103      } else {
104        mHidden = false;
105      }
106    }
107    return mHidden;
108  }
109
110  @Override
111  public boolean isRemoved() {
112    if (mRemoved == null) {
113      if (hasRemovedComment()) {
114        // We change the removed value of the package if a class wants to be not hidden.
115        ClassInfo[][] types = new ClassInfo[][] { annotations(), interfaces(), ordinaryClasses(),
116            enums(), exceptions() };
117        for (ClassInfo[] type : types) {
118          if (type != null) {
119            for (ClassInfo c : type) {
120              if (c.hasShowAnnotation()) {
121                mRemoved = false;
122                return false;
123              }
124            }
125          }
126        }
127        mRemoved = true;
128      } else {
129        mRemoved = false;
130      }
131    }
132
133    return mRemoved;
134  }
135
136  @Override
137  public boolean isHiddenOrRemoved() {
138    return isHidden() || isRemoved();
139  }
140
141  /**
142   * Used by ClassInfo to determine packages default visability before annoations.
143   */
144  public boolean hasHideComment() {
145    if (mHiddenByComment == null) {
146      mHiddenByComment = comment().isHidden();
147    }
148    return mHiddenByComment;
149  }
150
151  public boolean hasRemovedComment() {
152    if (mRemovedByComment == null) {
153      mRemovedByComment = comment().isRemoved();
154    }
155
156    return mRemovedByComment;
157  }
158
159  public boolean checkLevel() {
160    // TODO should return false if all classes are hidden but the package isn't.
161    // We don't have this so I'm not doing it now.
162    return !isHiddenOrRemoved();
163  }
164
165  public String name() {
166    return mName;
167  }
168
169  public String qualifiedName() {
170    return mName;
171  }
172
173  public TagInfo[] inlineTags() {
174    return comment().tags();
175  }
176
177  public TagInfo[] firstSentenceTags() {
178    return comment().briefTags();
179  }
180
181  /**
182   * @param classes the Array of ClassInfo to be filtered
183   * @return an Array of ClassInfo without any hidden or removed classes
184   */
185  public static ClassInfo[] filterHiddenAndRemoved(ClassInfo[] classes) {
186    ArrayList<ClassInfo> out = new ArrayList<ClassInfo>();
187
188    for (ClassInfo cl : classes) {
189      if (!cl.isHiddenOrRemoved()) {
190        out.add(cl);
191      }
192    }
193
194    return out.toArray(new ClassInfo[0]);
195  }
196
197  public void makeLink(Data data, String base) {
198    if (checkLevel()) {
199      data.setValue(base + ".link", htmlPage());
200    }
201    data.setValue(base + ".name", name());
202    data.setValue(base + ".since", getSince());
203  }
204
205  public void makeClassLinkListHDF(Data data, String base) {
206    makeLink(data, base);
207    ClassInfo.makeLinkListHDF(data, base + ".annotations", annotations());
208    ClassInfo.makeLinkListHDF(data, base + ".interfaces", interfaces());
209    ClassInfo.makeLinkListHDF(data, base + ".classes", ordinaryClasses());
210    ClassInfo.makeLinkListHDF(data, base + ".enums", enums());
211    ClassInfo.makeLinkListHDF(data, base + ".exceptions", exceptions());
212    ClassInfo.makeLinkListHDF(data, base + ".errors", errors());
213    data.setValue(base + ".since", getSince());
214  }
215
216  public ClassInfo[] annotations() {
217    if (mAnnotations == null) {
218      mAnnotations =
219          ClassInfo.sortByName(filterHiddenAndRemoved(
220              Converter.convertClasses(mPackage.annotationTypes())));
221    }
222    return mAnnotations;
223  }
224
225  public ClassInfo[] interfaces() {
226    if (mInterfaces == null) {
227      mInterfaces =
228          ClassInfo.sortByName(filterHiddenAndRemoved(
229              Converter.convertClasses(mPackage.interfaces())));
230    }
231    return mInterfaces;
232  }
233
234  public ClassInfo[] ordinaryClasses() {
235    if (mOrdinaryClasses == null) {
236      mOrdinaryClasses =
237          ClassInfo.sortByName(filterHiddenAndRemoved(
238              Converter.convertClasses(mPackage.ordinaryClasses())));
239    }
240    return mOrdinaryClasses;
241  }
242
243  public ClassInfo[] enums() {
244    if (mEnums == null) {
245      mEnums = ClassInfo.sortByName(filterHiddenAndRemoved(
246          Converter.convertClasses(mPackage.enums())));
247    }
248    return mEnums;
249  }
250
251  public ClassInfo[] exceptions() {
252    if (mExceptions == null) {
253      mExceptions =
254          ClassInfo.sortByName(filterHiddenAndRemoved(
255              Converter.convertClasses(mPackage.exceptions())));
256    }
257    return mExceptions;
258  }
259
260  public ClassInfo[] errors() {
261    if (mErrors == null) {
262      mErrors = ClassInfo.sortByName(filterHiddenAndRemoved(
263          Converter.convertClasses(mPackage.errors())));
264    }
265    return mErrors;
266  }
267
268  public ApiInfo containingApi() {
269    return mContainingApi;
270  }
271
272  public void setContainingApi(ApiInfo api) {
273    mContainingApi = api;
274  }
275
276  // in hashed containers, treat the name as the key
277  @Override
278  public int hashCode() {
279    return mName.hashCode();
280  }
281
282  private Boolean mHidden = null;
283  private Boolean mHiddenByComment = null;
284  private Boolean mRemoved = null;
285  private Boolean mRemovedByComment = null;
286  private String mName;
287  private PackageDoc mPackage;
288  private ApiInfo mContainingApi;
289  private ClassInfo[] mAnnotations;
290  private ClassInfo[] mInterfaces;
291  private ClassInfo[] mOrdinaryClasses;
292  private ClassInfo[] mEnums;
293  private ClassInfo[] mExceptions;
294  private ClassInfo[] mErrors;
295
296  private HashMap<String, ClassInfo> mAnnotationsMap;
297  private HashMap<String, ClassInfo> mInterfacesMap;
298  private HashMap<String, ClassInfo> mOrdinaryClassesMap;
299  private HashMap<String, ClassInfo> mEnumsMap;
300  private HashMap<String, ClassInfo> mExceptionsMap;
301  private HashMap<String, ClassInfo> mErrorsMap;
302
303
304  public ClassInfo getClass(String className) {
305      ClassInfo cls = mInterfacesMap.get(className);
306
307      if (cls != null) {
308          return cls;
309      }
310
311      cls = mOrdinaryClassesMap.get(className);
312
313      if (cls != null) {
314          return cls;
315      }
316
317      cls = mEnumsMap.get(className);
318
319      if (cls != null) {
320          return cls;
321      }
322
323      cls = mEnumsMap.get(className);
324
325      if (cls != null) {
326          return cls;
327      }
328      cls = mAnnotationsMap.get(className);
329
330      if (cls != null) {
331          return cls;
332      }
333
334      return mErrorsMap.get(className);
335  }
336
337  public void addAnnotation(ClassInfo cls) {
338      cls.setPackage(this);
339      mAnnotationsMap.put(cls.name(), cls);
340  }
341
342  public ClassInfo getAnnotation(String annotationName) {
343      return mAnnotationsMap.get(annotationName);
344  }
345
346  public void addInterface(ClassInfo cls) {
347      cls.setPackage(this);
348      mInterfacesMap.put(cls.name(), cls);
349  }
350
351  public ClassInfo getInterface(String interfaceName) {
352      return mInterfacesMap.get(interfaceName);
353  }
354
355  public ClassInfo getOrdinaryClass(String className) {
356      return mOrdinaryClassesMap.get(className);
357  }
358
359  public void addOrdinaryClass(ClassInfo cls) {
360      cls.setPackage(this);
361      mOrdinaryClassesMap.put(cls.name(), cls);
362  }
363
364  public ClassInfo getEnum(String enumName) {
365      return mEnumsMap.get(enumName);
366  }
367
368  public void addEnum(ClassInfo cls) {
369      cls.setPackage(this);
370      this.mEnumsMap.put(cls.name(), cls);
371  }
372
373  public ClassInfo getException(String exceptionName) {
374      return mExceptionsMap.get(exceptionName);
375  }
376
377  public ClassInfo getError(String errorName) {
378      return mErrorsMap.get(errorName);
379  }
380
381  // TODO: Leftovers from ApiCheck that should be better merged.
382  private HashMap<String, ClassInfo> mClasses = new HashMap<String, ClassInfo>();
383
384  public void addClass(ClassInfo cls) {
385    cls.setPackage(this);
386    mClasses.put(cls.name(), cls);
387  }
388
389  public HashMap<String, ClassInfo> allClasses() {
390    return mClasses;
391  }
392
393  public boolean isConsistent(PackageInfo pInfo) {
394    boolean consistent = true;
395    for (ClassInfo cInfo : mClasses.values()) {
396      if (pInfo.mClasses.containsKey(cInfo.name())) {
397        if (!cInfo.isConsistent(pInfo.mClasses.get(cInfo.name()))) {
398          consistent = false;
399        }
400      } else {
401        Errors.error(Errors.REMOVED_CLASS, cInfo.position(), "Removed public class "
402            + cInfo.qualifiedName());
403        consistent = false;
404      }
405    }
406    for (ClassInfo cInfo : pInfo.mClasses.values()) {
407      if (!mClasses.containsKey(cInfo.name())) {
408        Errors.error(Errors.ADDED_CLASS, cInfo.position(), "Added class " + cInfo.name()
409            + " to package " + pInfo.name());
410        consistent = false;
411      }
412    }
413    return consistent;
414  }
415}
416