1 /* Package.java -- information about a package 2 Copyright (C) 2000, 2001, 2002, 2003, 2005, 2006 3 Free Software Foundation, Inc. 4 5 This file is part of GNU Classpath. 6 7 GNU Classpath is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2, or (at your option) 10 any later version. 11 12 GNU Classpath is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GNU Classpath; see the file COPYING. If not, write to the 19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20 02110-1301 USA. 21 22 Linking this library statically or dynamically with other modules is 23 making a combined work based on this library. Thus, the terms and 24 conditions of the GNU General Public License cover the whole 25 combination. 26 27 As a special exception, the copyright holders of this library give you 28 permission to link this library with independent modules to produce an 29 executable, regardless of the license terms of these independent 30 modules, and to copy and distribute the resulting executable under 31 terms of your choice, provided that you also meet, for each linked 32 independent module, the terms and conditions of the license of that 33 module. An independent module is a module which is not derived from 34 or based on this library. If you modify this library, you may extend 35 this exception to your version of the library, but you are not 36 obligated to do so. If you do not wish to do so, delete this 37 exception statement from your version. */ 38 39 package java.lang; 40 41 import gnu.classpath.VMStackWalker; 42 43 import java.lang.annotation.Annotation; 44 import java.lang.reflect.AnnotatedElement; 45 import java.net.URL; 46 import java.util.NoSuchElementException; 47 import java.util.StringTokenizer; 48 49 50 /** 51 * Everything you ever wanted to know about a package. This class makes it 52 * possible to attach specification and implementation information to a 53 * package as explained in the 54 * <a href="http://java.sun.com/products/jdk/1.3/docs/guide/versioning/spec/VersioningSpecification.html#PackageVersionSpecification">Package Versioning Specification</a> 55 * section of the 56 * <a href="http://java.sun.com/products/jdk/1.3/docs/guide/versioning/spec/VersioningSpecification.html">Product Versioning Specification</a>. 57 * It also allows packages to be sealed with respect to the originating URL. 58 * 59 * <p>The most useful method is the <code>isCompatibleWith()</code> method that 60 * compares a desired version of a specification with the version of the 61 * specification as implemented by a package. A package is considered 62 * compatible with another version if the version of the specification is 63 * equal or higher then the requested version. Version numbers are represented 64 * as strings of positive numbers separated by dots (e.g. "1.2.0"). 65 * The first number is called the major number, the second the minor, 66 * the third the micro, etc. A version is considered higher then another 67 * version if it has a bigger major number then the another version or when 68 * the major numbers of the versions are equal if it has a bigger minor number 69 * then the other version, etc. (If a version has no minor, micro, etc numbers 70 * then they are considered the be 0.) 71 * 72 * @author Mark Wielaard (mark@klomp.org) 73 * @see ClassLoader#definePackage(String, String, String, String, String, 74 * String, String, URL) 75 * @since 1.2 76 * @status updated to 1.5 77 */ 78 public class Package 79 implements AnnotatedElement 80 { 81 /** The name of the Package */ 82 private final String name; 83 84 /** The name if the implementation */ 85 private final String implTitle; 86 87 /** The vendor that wrote this implementation */ 88 private final String implVendor; 89 90 /** The version of this implementation */ 91 private final String implVersion; 92 93 /** The name of the specification */ 94 private final String specTitle; 95 96 /** The name of the specification designer */ 97 private final String specVendor; 98 99 /** The version of this specification */ 100 private final String specVersion; 101 102 /** If sealed the origin of the package classes, otherwise null */ 103 private final URL sealed; 104 105 /** The class loader that defined this package */ 106 private ClassLoader loader; 107 108 /** @deprecated Please use the other constructor that takes the class loader 109 * that defines the Package. 110 */ Package(String name, String specTitle, String specVendor, String specVersion, String implTitle, String implVendor, String implVersion, URL sealed)111 Package(String name, 112 String specTitle, String specVendor, String specVersion, 113 String implTitle, String implVendor, String implVersion, URL sealed) 114 { 115 this(name, specTitle, specVendor, specVersion, implTitle, implVendor, 116 implVersion, sealed, null); 117 } 118 119 /** 120 * A package local constructor for the Package class. All parameters except 121 * the <code>name</code> of the package may be <code>null</code>. 122 * There are no public constructors defined for Package; this is a package 123 * local constructor that is used by java.lang.Classloader.definePackage(). 124 * 125 * @param name The name of the Package 126 * @param specTitle The name of the specification 127 * @param specVendor The name of the specification designer 128 * @param specVersion The version of this specification 129 * @param implTitle The name of the implementation 130 * @param implVendor The vendor that wrote this implementation 131 * @param implVersion The version of this implementation 132 * @param sealed If sealed the origin of the package classes 133 */ Package(String name, String specTitle, String specVendor, String specVersion, String implTitle, String implVendor, String implVersion, URL sealed, ClassLoader loader)134 Package(String name, 135 String specTitle, String specVendor, String specVersion, 136 String implTitle, String implVendor, String implVersion, URL sealed, 137 ClassLoader loader) 138 { 139 if (name == null) 140 throw new IllegalArgumentException("null Package name"); 141 142 this.name = name; 143 this.implTitle = implTitle; 144 this.implVendor = implVendor; 145 this.implVersion = implVersion; 146 this.specTitle = specTitle; 147 this.specVendor = specVendor; 148 this.specVersion = specVersion; 149 this.sealed = sealed; 150 this.loader = loader; 151 } 152 153 /** 154 * Returns the Package name in dot-notation. 155 * 156 * @return the non-null package name 157 */ getName()158 public String getName() 159 { 160 return name; 161 } 162 163 /** 164 * Returns the name of the specification, or null if unknown. 165 * 166 * @return the specification title 167 */ getSpecificationTitle()168 public String getSpecificationTitle() 169 { 170 return specTitle; 171 } 172 173 /** 174 * Returns the version of the specification, or null if unknown. 175 * 176 * @return the specification version 177 */ getSpecificationVersion()178 public String getSpecificationVersion() 179 { 180 return specVersion; 181 } 182 183 /** 184 * Returns the name of the specification designer, or null if unknown. 185 * 186 * @return the specification vendor 187 */ getSpecificationVendor()188 public String getSpecificationVendor() 189 { 190 return specVendor; 191 } 192 193 /** 194 * Returns the name of the implementation, or null if unknown. 195 * 196 * @return the implementation title 197 */ getImplementationTitle()198 public String getImplementationTitle() 199 { 200 return implTitle; 201 } 202 203 /** 204 * Returns the version of this implementation, or null if unknown. 205 * 206 * @return the implementation version 207 */ getImplementationVersion()208 public String getImplementationVersion() 209 { 210 return implVersion; 211 } 212 213 /** 214 * Returns the vendor that wrote this implementation, or null if unknown. 215 * 216 * @return the implementation vendor 217 */ getImplementationVendor()218 public String getImplementationVendor() 219 { 220 return implVendor; 221 } 222 223 /** 224 * Returns true if this Package is sealed. 225 * 226 * @return true if the package is sealed 227 */ isSealed()228 public boolean isSealed() 229 { 230 return sealed != null; 231 } 232 233 /** 234 * Returns true if this Package is sealed and the origin of the classes is 235 * the given URL. 236 * 237 * @param url the URL to test 238 * @return true if the package is sealed by this URL 239 * @throws NullPointerException if url is null 240 */ isSealed(URL url)241 public boolean isSealed(URL url) 242 { 243 return url.equals(sealed); 244 } 245 246 /** 247 * Checks if the version of the specification is higher or at least as high 248 * as the desired version. Comparison is done by sequentially comparing 249 * dotted decimal numbers from the parameter and from 250 * <code>getSpecificationVersion</code>. 251 * 252 * @param version the (minimal) desired version of the specification 253 * 254 * @return true if the version is compatible, false otherwise 255 * 256 * @throws NumberFormatException if either version string is invalid 257 * @throws NullPointerException if either version string is null 258 */ isCompatibleWith(String version)259 public boolean isCompatibleWith(String version) 260 { 261 StringTokenizer versionTokens = new StringTokenizer(version, "."); 262 StringTokenizer specTokens = new StringTokenizer(specVersion, "."); 263 try 264 { 265 while (versionTokens.hasMoreElements()) 266 { 267 int vers = Integer.parseInt(versionTokens.nextToken()); 268 int spec = Integer.parseInt(specTokens.nextToken()); 269 if (spec < vers) 270 return false; 271 else if (spec > vers) 272 return true; 273 // They must be equal, next Token please! 274 } 275 } 276 catch (NoSuchElementException e) 277 { 278 // This must have been thrown by spec.nextToken() so return false. 279 return false; 280 } 281 // They must have been exactly the same version. 282 // Or the specVersion has more subversions. That is also good. 283 return true; 284 } 285 286 /** 287 * Returns the named package if it is known by the callers class loader. 288 * It may return null if the package is unknown, when there is no 289 * information on that particular package available or when the callers 290 * classloader is null. 291 * 292 * @param name the name of the desired package 293 * @return the package by that name in the current ClassLoader 294 */ getPackage(String name)295 public static Package getPackage(String name) 296 { 297 // Get the caller's classloader 298 ClassLoader cl = VMStackWalker.getCallingClassLoader(); 299 return cl != null ? cl.getPackage(name) : VMClassLoader.getPackage(name); 300 } 301 302 /** 303 * Returns all the packages that are known to the callers class loader. 304 * It may return an empty array if the classloader of the caller is null. 305 * 306 * @return an array of all known packages 307 */ getPackages()308 public static Package[] getPackages() 309 { 310 // Get the caller's classloader 311 ClassLoader cl = VMStackWalker.getCallingClassLoader(); 312 return cl != null ? cl.getPackages() : VMClassLoader.getPackages(); 313 } 314 315 /** 316 * Returns the hashCode of the name of this package. 317 * 318 * @return the hash code 319 */ hashCode()320 public int hashCode() 321 { 322 return name.hashCode(); 323 } 324 325 /** 326 * Returns a string representation of this package. It is specified to 327 * be <code>"package " + getName() + (getSpecificationTitle() == null 328 * ? "" : ", " + getSpecificationTitle()) + (getSpecificationVersion() 329 * == null ? "" : ", version " + getSpecificationVersion())</code>. 330 * 331 * @return the string representation of the package 332 */ toString()333 public String toString() 334 { 335 return ("package " + name + (specTitle == null ? "" : ", " + specTitle) 336 + (specVersion == null ? "" : ", version " + specVersion)); 337 } 338 339 /** 340 * Returns this package's annotation for the specified annotation type, 341 * or <code>null</code> if no such annotation exists. 342 * 343 * @param annotationClass the type of annotation to look for. 344 * @return this package's annotation for the specified type, or 345 * <code>null</code> if no such annotation exists. 346 * @since 1.5 347 */ getAnnotation(Class<A> annotationClass)348 public <A extends Annotation> A getAnnotation(Class<A> annotationClass) 349 { 350 A foundAnnotation = null; 351 Annotation[] annotations = getAnnotations(); 352 for (Annotation annotation : annotations) 353 if (annotation.annotationType() == annotationClass) 354 foundAnnotation = (A) annotation; 355 return foundAnnotation; 356 } 357 358 /** 359 * Returns all annotations associated with this package. If there are 360 * no annotations associated with this package, then a zero-length array 361 * will be returned. The returned array may be modified by the client 362 * code, but this will have no effect on the annotation content of this 363 * package, and hence no effect on the return value of this method for 364 * future callers. 365 * 366 * @return this package' annotations. 367 * @since 1.5 368 */ getAnnotations()369 public Annotation[] getAnnotations() 370 { 371 /** All a package's annotations are declared within it. */ 372 return getDeclaredAnnotations(); 373 } 374 375 /** 376 * Returns all annotations directly defined by this package. If there are 377 * no annotations associated with this package, then a zero-length array 378 * will be returned. The returned array may be modified by the client 379 * code, but this will have no effect on the annotation content of this 380 * package, and hence no effect on the return value of this method for 381 * future callers. 382 * 383 * @return the annotations directly defined by this package. 384 * @since 1.5 385 */ getDeclaredAnnotations()386 public Annotation[] getDeclaredAnnotations() 387 { 388 try 389 { 390 Class pkgInfo = Class.forName(name + ".package-info", false, loader); 391 return pkgInfo.getDeclaredAnnotations(); 392 } 393 catch (ClassNotFoundException _) 394 { 395 return new Annotation[0]; 396 } 397 } 398 399 /** 400 * Returns true if an annotation for the specified type is associated 401 * with this package. This is primarily a short-hand for using marker 402 * annotations. 403 * 404 * @param annotationClass the type of annotation to look for. 405 * @return true if an annotation exists for the specified type. 406 * @since 1.5 407 */ isAnnotationPresent(Class<? extends Annotation> annotationClass)408 public boolean isAnnotationPresent(Class<? extends Annotation> 409 annotationClass) 410 { 411 return getAnnotation(annotationClass) != null; 412 } 413 414 } // class Package 415