Home | History | Annotate | Download | only in doclava
      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 
     17 package com.google.doclava;
     18 
     19 import com.google.doclava.apicheck.ApiInfo;
     20 import com.google.clearsilver.jsilver.data.Data;
     21 
     22 import com.sun.javadoc.*;
     23 import java.util.*;
     24 
     25 public 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       if (Doclava.hiddenPackages.contains(mName)) {
    147         mHiddenByComment = true;
    148       } else {
    149         mHiddenByComment = comment().isHidden();
    150       }
    151     }
    152     return mHiddenByComment;
    153   }
    154 
    155   public boolean hasRemovedComment() {
    156     if (mRemovedByComment == null) {
    157       mRemovedByComment = comment().isRemoved();
    158     }
    159 
    160     return mRemovedByComment;
    161   }
    162 
    163   public boolean checkLevel() {
    164     // TODO should return false if all classes are hidden but the package isn't.
    165     // We don't have this so I'm not doing it now.
    166     return !isHiddenOrRemoved();
    167   }
    168 
    169   public String name() {
    170     return mName;
    171   }
    172 
    173   public String qualifiedName() {
    174     return mName;
    175   }
    176 
    177   public TagInfo[] inlineTags() {
    178     return comment().tags();
    179   }
    180 
    181   public TagInfo[] firstSentenceTags() {
    182     return comment().briefTags();
    183   }
    184 
    185   /**
    186    * @param classes the Array of ClassInfo to be filtered
    187    * @return an Array of ClassInfo without any hidden or removed classes
    188    */
    189   public static ClassInfo[] filterHiddenAndRemoved(ClassInfo[] classes) {
    190     ArrayList<ClassInfo> out = new ArrayList<ClassInfo>();
    191 
    192     for (ClassInfo cl : classes) {
    193       if (!cl.isHiddenOrRemoved()) {
    194         out.add(cl);
    195       }
    196     }
    197 
    198     return out.toArray(new ClassInfo[0]);
    199   }
    200 
    201   public void makeLink(Data data, String base) {
    202     if (checkLevel()) {
    203       data.setValue(base + ".link", htmlPage());
    204     }
    205     data.setValue(base + ".name", name());
    206     data.setValue(base + ".since", getSince());
    207   }
    208 
    209   public void makeClassLinkListHDF(Data data, String base) {
    210     makeLink(data, base);
    211     ClassInfo.makeLinkListHDF(data, base + ".annotations", annotations());
    212     ClassInfo.makeLinkListHDF(data, base + ".interfaces", interfaces());
    213     ClassInfo.makeLinkListHDF(data, base + ".classes", ordinaryClasses());
    214     ClassInfo.makeLinkListHDF(data, base + ".enums", enums());
    215     ClassInfo.makeLinkListHDF(data, base + ".exceptions", exceptions());
    216     ClassInfo.makeLinkListHDF(data, base + ".errors", errors());
    217     data.setValue(base + ".since", getSince());
    218   }
    219 
    220   public ClassInfo[] annotations() {
    221     if (mAnnotations == null) {
    222       mAnnotations =
    223           ClassInfo.sortByName(filterHiddenAndRemoved(
    224               Converter.convertClasses(mPackage.annotationTypes())));
    225     }
    226     return mAnnotations;
    227   }
    228 
    229   public ClassInfo[] interfaces() {
    230     if (mInterfaces == null) {
    231       mInterfaces =
    232           ClassInfo.sortByName(filterHiddenAndRemoved(
    233               Converter.convertClasses(mPackage.interfaces())));
    234     }
    235     return mInterfaces;
    236   }
    237 
    238   public ClassInfo[] ordinaryClasses() {
    239     if (mOrdinaryClasses == null) {
    240       mOrdinaryClasses =
    241           ClassInfo.sortByName(filterHiddenAndRemoved(
    242               Converter.convertClasses(mPackage.ordinaryClasses())));
    243     }
    244     return mOrdinaryClasses;
    245   }
    246 
    247   public ClassInfo[] enums() {
    248     if (mEnums == null) {
    249       mEnums = ClassInfo.sortByName(filterHiddenAndRemoved(
    250           Converter.convertClasses(mPackage.enums())));
    251     }
    252     return mEnums;
    253   }
    254 
    255   public ClassInfo[] exceptions() {
    256     if (mExceptions == null) {
    257       mExceptions =
    258           ClassInfo.sortByName(filterHiddenAndRemoved(
    259               Converter.convertClasses(mPackage.exceptions())));
    260     }
    261     return mExceptions;
    262   }
    263 
    264   public ClassInfo[] errors() {
    265     if (mErrors == null) {
    266       mErrors = ClassInfo.sortByName(filterHiddenAndRemoved(
    267           Converter.convertClasses(mPackage.errors())));
    268     }
    269     return mErrors;
    270   }
    271 
    272   public ApiInfo containingApi() {
    273     return mContainingApi;
    274   }
    275 
    276   public void setContainingApi(ApiInfo api) {
    277     mContainingApi = api;
    278   }
    279 
    280   // in hashed containers, treat the name as the key
    281   @Override
    282   public int hashCode() {
    283     return mName.hashCode();
    284   }
    285 
    286   private Boolean mHidden = null;
    287   private Boolean mHiddenByComment = null;
    288   private Boolean mRemoved = null;
    289   private Boolean mRemovedByComment = null;
    290   private String mName;
    291   private PackageDoc mPackage;
    292   private ApiInfo mContainingApi;
    293   private ClassInfo[] mAnnotations;
    294   private ClassInfo[] mInterfaces;
    295   private ClassInfo[] mOrdinaryClasses;
    296   private ClassInfo[] mEnums;
    297   private ClassInfo[] mExceptions;
    298   private ClassInfo[] mErrors;
    299 
    300   private HashMap<String, ClassInfo> mAnnotationsMap;
    301   private HashMap<String, ClassInfo> mInterfacesMap;
    302   private HashMap<String, ClassInfo> mOrdinaryClassesMap;
    303   private HashMap<String, ClassInfo> mEnumsMap;
    304   private HashMap<String, ClassInfo> mExceptionsMap;
    305   private HashMap<String, ClassInfo> mErrorsMap;
    306 
    307 
    308   public ClassInfo getClass(String className) {
    309       ClassInfo cls = mInterfacesMap.get(className);
    310 
    311       if (cls != null) {
    312           return cls;
    313       }
    314 
    315       cls = mOrdinaryClassesMap.get(className);
    316 
    317       if (cls != null) {
    318           return cls;
    319       }
    320 
    321       cls = mEnumsMap.get(className);
    322 
    323       if (cls != null) {
    324           return cls;
    325       }
    326 
    327       cls = mEnumsMap.get(className);
    328 
    329       if (cls != null) {
    330           return cls;
    331       }
    332       cls = mAnnotationsMap.get(className);
    333 
    334       if (cls != null) {
    335           return cls;
    336       }
    337 
    338       return mErrorsMap.get(className);
    339   }
    340 
    341   public void addAnnotation(ClassInfo cls) {
    342       cls.setPackage(this);
    343       mAnnotationsMap.put(cls.name(), cls);
    344   }
    345 
    346   public ClassInfo getAnnotation(String annotationName) {
    347       return mAnnotationsMap.get(annotationName);
    348   }
    349 
    350   public void addInterface(ClassInfo cls) {
    351       cls.setPackage(this);
    352       mInterfacesMap.put(cls.name(), cls);
    353   }
    354 
    355   public ClassInfo getInterface(String interfaceName) {
    356       return mInterfacesMap.get(interfaceName);
    357   }
    358 
    359   public ClassInfo getOrdinaryClass(String className) {
    360       return mOrdinaryClassesMap.get(className);
    361   }
    362 
    363   public void addOrdinaryClass(ClassInfo cls) {
    364       cls.setPackage(this);
    365       mOrdinaryClassesMap.put(cls.name(), cls);
    366   }
    367 
    368   public ClassInfo getEnum(String enumName) {
    369       return mEnumsMap.get(enumName);
    370   }
    371 
    372   public void addEnum(ClassInfo cls) {
    373       cls.setPackage(this);
    374       this.mEnumsMap.put(cls.name(), cls);
    375   }
    376 
    377   public ClassInfo getException(String exceptionName) {
    378       return mExceptionsMap.get(exceptionName);
    379   }
    380 
    381   public ClassInfo getError(String errorName) {
    382       return mErrorsMap.get(errorName);
    383   }
    384 
    385   // TODO: Leftovers from ApiCheck that should be better merged.
    386   private HashMap<String, ClassInfo> mClasses = new HashMap<String, ClassInfo>();
    387 
    388   public void addClass(ClassInfo cls) {
    389     cls.setPackage(this);
    390     mClasses.put(cls.name(), cls);
    391   }
    392 
    393   public HashMap<String, ClassInfo> allClasses() {
    394     return mClasses;
    395   }
    396 
    397   public boolean isConsistent(PackageInfo pInfo) {
    398     boolean consistent = true;
    399     for (ClassInfo cInfo : mClasses.values()) {
    400       if (pInfo.mClasses.containsKey(cInfo.name())) {
    401         if (!cInfo.isConsistent(pInfo.mClasses.get(cInfo.name()))) {
    402           consistent = false;
    403         }
    404       } else {
    405         Errors.error(Errors.REMOVED_CLASS, cInfo.position(), "Removed public class "
    406             + cInfo.qualifiedName());
    407         consistent = false;
    408       }
    409     }
    410     for (ClassInfo cInfo : pInfo.mClasses.values()) {
    411       if (!mClasses.containsKey(cInfo.name())) {
    412         Errors.error(Errors.ADDED_CLASS, cInfo.position(), "Added class " + cInfo.name()
    413             + " to package " + pInfo.name());
    414         consistent = false;
    415       }
    416     }
    417     return consistent;
    418   }
    419 }
    420