Source for java.lang.Package

   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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 408:   public boolean isAnnotationPresent(Class<? extends Annotation>
 409:                                      annotationClass)
 410:   {
 411:     return getAnnotation(annotationClass) != null;
 412:   }
 413: 
 414: } // class Package