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