Save This Page
Home » openjdk-7 » java » lang » [javadoc | source]
    1   /*
    2    * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package java.lang;
   27   
   28   import java.io.InputStream;
   29   import java.util.Enumeration;
   30   
   31   import java.util.StringTokenizer;
   32   import java.io.File;
   33   import java.io.FileInputStream;
   34   import java.io.FileNotFoundException;
   35   import java.io.IOException;
   36   import java.net.URL;
   37   import java.net.MalformedURLException;
   38   import java.security.AccessController;
   39   import java.security.PrivilegedAction;
   40   
   41   import java.util.jar.JarInputStream;
   42   import java.util.jar.Manifest;
   43   import java.util.jar.Attributes;
   44   import java.util.jar.Attributes.Name;
   45   import java.util.jar.JarException;
   46   import java.util.Map;
   47   import java.util.HashMap;
   48   import java.util.Iterator;
   49   
   50   import sun.net.www.ParseUtil;
   51   
   52   import java.lang.annotation.Annotation;
   53   
   54   /**
   55    * {@code Package} objects contain version information
   56    * about the implementation and specification of a Java package.
   57    * This versioning information is retrieved and made available
   58    * by the {@link ClassLoader} instance that
   59    * loaded the class(es).  Typically, it is stored in the manifest that is
   60    * distributed with the classes.
   61    *
   62    * <p>The set of classes that make up the package may implement a
   63    * particular specification and if so the specification title, version number,
   64    * and vendor strings identify that specification.
   65    * An application can ask if the package is
   66    * compatible with a particular version, see the {@link
   67    * #isCompatibleWith isCompatibleWith}
   68    * method for details.
   69    *
   70    * <p>Specification version numbers use a syntax that consists of nonnegative
   71    * decimal integers separated by periods ".", for example "2.0" or
   72    * "1.2.3.4.5.6.7".  This allows an extensible number to be used to represent
   73    * major, minor, micro, etc. versions.  The version specification is described
   74    * by the following formal grammar:
   75    * <blockquote>
   76    * <dl>
   77    * <dt><i>SpecificationVersion:
   78    * <dd>Digits RefinedVersion<sub>opt</sub></i>
   79   
   80    * <p><dt><i>RefinedVersion:</i>
   81    * <dd>{@code .} <i>Digits</i>
   82    * <dd>{@code .} <i>Digits RefinedVersion</i>
   83    *
   84    * <p><dt><i>Digits:
   85    * <dd>Digit
   86    * <dd>Digits</i>
   87    *
   88    * <p><dt><i>Digit:</i>
   89    * <dd>any character for which {@link Character#isDigit} returns {@code true},
   90    * e.g. 0, 1, 2, ...
   91    * </dl>
   92    * </blockquote>
   93    *
   94    * <p>The implementation title, version, and vendor strings identify an
   95    * implementation and are made available conveniently to enable accurate
   96    * reporting of the packages involved when a problem occurs. The contents
   97    * all three implementation strings are vendor specific. The
   98    * implementation version strings have no specified syntax and should
   99    * only be compared for equality with desired version identifiers.
  100    *
  101    * <p>Within each {@code ClassLoader} instance all classes from the same
  102    * java package have the same Package object.  The static methods allow a package
  103    * to be found by name or the set of all packages known to the current class
  104    * loader to be found.
  105    *
  106    * @see ClassLoader#definePackage
  107    */
  108   public class Package implements java.lang.reflect.AnnotatedElement {
  109       /**
  110        * Return the name of this package.
  111        *
  112        * @return  The fully-qualified name of this package as defined in the
  113        *          <em>Java Language Specification, Third Edition</em>
  114        *          <a href="http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.5.3">
  115        *          &sect;6.5.3</a>, for example, {@code java.lang}
  116        */
  117       public String getName() {
  118           return pkgName;
  119       }
  120   
  121   
  122       /**
  123        * Return the title of the specification that this package implements.
  124        * @return the specification title, null is returned if it is not known.
  125        */
  126       public String getSpecificationTitle() {
  127           return specTitle;
  128       }
  129   
  130       /**
  131        * Returns the version number of the specification
  132        * that this package implements.
  133        * This version string must be a sequence of nonnegative decimal
  134        * integers separated by "."'s and may have leading zeros.
  135        * When version strings are compared the most significant
  136        * numbers are compared.
  137        * @return the specification version, null is returned if it is not known.
  138        */
  139       public String getSpecificationVersion() {
  140           return specVersion;
  141       }
  142   
  143       /**
  144        * Return the name of the organization, vendor,
  145        * or company that owns and maintains the specification
  146        * of the classes that implement this package.
  147        * @return the specification vendor, null is returned if it is not known.
  148        */
  149       public String getSpecificationVendor() {
  150           return specVendor;
  151       }
  152   
  153       /**
  154        * Return the title of this package.
  155        * @return the title of the implementation, null is returned if it is not known.
  156        */
  157       public String getImplementationTitle() {
  158           return implTitle;
  159       }
  160   
  161       /**
  162        * Return the version of this implementation. It consists of any string
  163        * assigned by the vendor of this implementation and does
  164        * not have any particular syntax specified or expected by the Java
  165        * runtime. It may be compared for equality with other
  166        * package version strings used for this implementation
  167        * by this vendor for this package.
  168        * @return the version of the implementation, null is returned if it is not known.
  169        */
  170       public String getImplementationVersion() {
  171           return implVersion;
  172       }
  173   
  174       /**
  175        * Returns the name of the organization,
  176        * vendor or company that provided this implementation.
  177        * @return the vendor that implemented this package..
  178        */
  179       public String getImplementationVendor() {
  180           return implVendor;
  181       }
  182   
  183       /**
  184        * Returns true if this package is sealed.
  185        *
  186        * @return true if the package is sealed, false otherwise
  187        */
  188       public boolean isSealed() {
  189           return sealBase != null;
  190       }
  191   
  192       /**
  193        * Returns true if this package is sealed with respect to the specified
  194        * code source url.
  195        *
  196        * @param url the code source url
  197        * @return true if this package is sealed with respect to url
  198        */
  199       public boolean isSealed(URL url) {
  200           return url.equals(sealBase);
  201       }
  202   
  203       /**
  204        * Compare this package's specification version with a
  205        * desired version. It returns true if
  206        * this packages specification version number is greater than or equal
  207        * to the desired version number. <p>
  208        *
  209        * Version numbers are compared by sequentially comparing corresponding
  210        * components of the desired and specification strings.
  211        * Each component is converted as a decimal integer and the values
  212        * compared.
  213        * If the specification value is greater than the desired
  214        * value true is returned. If the value is less false is returned.
  215        * If the values are equal the period is skipped and the next pair of
  216        * components is compared.
  217        *
  218        * @param desired the version string of the desired version.
  219        * @return true if this package's version number is greater
  220        *          than or equal to the desired version number
  221        *
  222        * @exception NumberFormatException if the desired or current version
  223        *          is not of the correct dotted form.
  224        */
  225       public boolean isCompatibleWith(String desired)
  226           throws NumberFormatException
  227       {
  228           if (specVersion == null || specVersion.length() < 1) {
  229               throw new NumberFormatException("Empty version string");
  230           }
  231   
  232           String [] sa = specVersion.split("\\.", -1);
  233           int [] si = new int[sa.length];
  234           for (int i = 0; i < sa.length; i++) {
  235               si[i] = Integer.parseInt(sa[i]);
  236               if (si[i] < 0)
  237                   throw NumberFormatException.forInputString("" + si[i]);
  238           }
  239   
  240           String [] da = desired.split("\\.", -1);
  241           int [] di = new int[da.length];
  242           for (int i = 0; i < da.length; i++) {
  243               di[i] = Integer.parseInt(da[i]);
  244               if (di[i] < 0)
  245                   throw NumberFormatException.forInputString("" + di[i]);
  246           }
  247   
  248           int len = Math.max(di.length, si.length);
  249           for (int i = 0; i < len; i++) {
  250               int d = (i < di.length ? di[i] : 0);
  251               int s = (i < si.length ? si[i] : 0);
  252               if (s < d)
  253                   return false;
  254               if (s > d)
  255                   return true;
  256           }
  257           return true;
  258       }
  259   
  260       /**
  261        * Find a package by name in the callers {@code ClassLoader} instance.
  262        * The callers {@code ClassLoader} instance is used to find the package
  263        * instance corresponding to the named class. If the callers
  264        * {@code ClassLoader} instance is null then the set of packages loaded
  265        * by the system {@code ClassLoader} instance is searched to find the
  266        * named package. <p>
  267        *
  268        * Packages have attributes for versions and specifications only if the class
  269        * loader created the package instance with the appropriate attributes. Typically,
  270        * those attributes are defined in the manifests that accompany the classes.
  271        *
  272        * @param name a package name, for example, java.lang.
  273        * @return the package of the requested name. It may be null if no package
  274        *          information is available from the archive or codebase.
  275        */
  276       public static Package getPackage(String name) {
  277           ClassLoader l = ClassLoader.getCallerClassLoader();
  278           if (l != null) {
  279               return l.getPackage(name);
  280           } else {
  281               return getSystemPackage(name);
  282           }
  283       }
  284   
  285       /**
  286        * Get all the packages currently known for the caller's {@code ClassLoader}
  287        * instance.  Those packages correspond to classes loaded via or accessible by
  288        * name to that {@code ClassLoader} instance.  If the caller's
  289        * {@code ClassLoader} instance is the bootstrap {@code ClassLoader}
  290        * instance, which may be represented by {@code null} in some implementations,
  291        * only packages corresponding to classes loaded by the bootstrap
  292        * {@code ClassLoader} instance will be returned.
  293        *
  294        * @return a new array of packages known to the callers {@code ClassLoader}
  295        * instance.  An zero length array is returned if none are known.
  296        */
  297       public static Package[] getPackages() {
  298           ClassLoader l = ClassLoader.getCallerClassLoader();
  299           if (l != null) {
  300               return l.getPackages();
  301           } else {
  302               return getSystemPackages();
  303           }
  304       }
  305   
  306       /**
  307        * Get the package for the specified class.
  308        * The class's class loader is used to find the package instance
  309        * corresponding to the specified class. If the class loader
  310        * is the bootstrap class loader, which may be represented by
  311        * {@code null} in some implementations, then the set of packages
  312        * loaded by the bootstrap class loader is searched to find the package.
  313        * <p>
  314        * Packages have attributes for versions and specifications only
  315        * if the class loader created the package
  316        * instance with the appropriate attributes. Typically those
  317        * attributes are defined in the manifests that accompany
  318        * the classes.
  319        *
  320        * @param class the class to get the package of.
  321        * @return the package of the class. It may be null if no package
  322        *          information is available from the archive or codebase.  */
  323       static Package getPackage(Class c) {
  324           String name = c.getName();
  325           int i = name.lastIndexOf('.');
  326           if (i != -1) {
  327               name = name.substring(0, i);
  328               ClassLoader cl = c.getClassLoader();
  329               if (cl != null) {
  330                   return cl.getPackage(name);
  331               } else {
  332                   return getSystemPackage(name);
  333               }
  334           } else {
  335               return null;
  336           }
  337       }
  338   
  339       /**
  340        * Return the hash code computed from the package name.
  341        * @return the hash code computed from the package name.
  342        */
  343       public int hashCode(){
  344           return pkgName.hashCode();
  345       }
  346   
  347       /**
  348        * Returns the string representation of this Package.
  349        * Its value is the string "package " and the package name.
  350        * If the package title is defined it is appended.
  351        * If the package version is defined it is appended.
  352        * @return the string representation of the package.
  353        */
  354       public String toString() {
  355           String spec = specTitle;
  356           String ver =  specVersion;
  357           if (spec != null && spec.length() > 0)
  358               spec = ", " + spec;
  359           else
  360               spec = "";
  361           if (ver != null && ver.length() > 0)
  362               ver = ", version " + ver;
  363           else
  364               ver = "";
  365           return "package " + pkgName + spec + ver;
  366       }
  367   
  368       private Class<?> getPackageInfo() {
  369           if (packageInfo == null) {
  370               try {
  371                   packageInfo = Class.forName(pkgName + ".package-info", false, loader);
  372               } catch (ClassNotFoundException ex) {
  373                   // store a proxy for the package info that has no annotations
  374                   class PackageInfoProxy {}
  375                   packageInfo = PackageInfoProxy.class;
  376               }
  377           }
  378           return packageInfo;
  379       }
  380   
  381       /**
  382        * @throws NullPointerException {@inheritDoc}
  383        * @since 1.5
  384        */
  385       public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
  386           return getPackageInfo().getAnnotation(annotationClass);
  387       }
  388   
  389       /**
  390        * @throws NullPointerException {@inheritDoc}
  391        * @since 1.5
  392        */
  393       public boolean isAnnotationPresent(
  394           Class<? extends Annotation> annotationClass) {
  395           return getPackageInfo().isAnnotationPresent(annotationClass);
  396       }
  397   
  398       /**
  399        * @since 1.5
  400        */
  401       public Annotation[] getAnnotations() {
  402           return getPackageInfo().getAnnotations();
  403       }
  404   
  405       /**
  406        * @since 1.5
  407        */
  408       public Annotation[] getDeclaredAnnotations()  {
  409           return getPackageInfo().getDeclaredAnnotations();
  410       }
  411   
  412       /**
  413        * Construct a package instance with the specified version
  414        * information.
  415        * @param pkgName the name of the package
  416        * @param spectitle the title of the specification
  417        * @param specversion the version of the specification
  418        * @param specvendor the organization that maintains the specification
  419        * @param impltitle the title of the implementation
  420        * @param implversion the version of the implementation
  421        * @param implvendor the organization that maintains the implementation
  422        * @return a new package for containing the specified information.
  423        */
  424       Package(String name,
  425               String spectitle, String specversion, String specvendor,
  426               String impltitle, String implversion, String implvendor,
  427               URL sealbase, ClassLoader loader)
  428       {
  429           pkgName = name;
  430           implTitle = impltitle;
  431           implVersion = implversion;
  432           implVendor = implvendor;
  433           specTitle = spectitle;
  434           specVersion = specversion;
  435           specVendor = specvendor;
  436           sealBase = sealbase;
  437           this.loader = loader;
  438       }
  439   
  440       /*
  441        * Construct a package using the attributes from the specified manifest.
  442        *
  443        * @param name the package name
  444        * @param man the optional manifest for the package
  445        * @param url the optional code source url for the package
  446        */
  447       private Package(String name, Manifest man, URL url, ClassLoader loader) {
  448           String path = name.replace('.', '/').concat("/");
  449           String sealed = null;
  450           String specTitle= null;
  451           String specVersion= null;
  452           String specVendor= null;
  453           String implTitle= null;
  454           String implVersion= null;
  455           String implVendor= null;
  456           URL sealBase= null;
  457           Attributes attr = man.getAttributes(path);
  458           if (attr != null) {
  459               specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
  460               specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
  461               specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
  462               implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
  463               implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
  464               implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
  465               sealed      = attr.getValue(Name.SEALED);
  466           }
  467           attr = man.getMainAttributes();
  468           if (attr != null) {
  469               if (specTitle == null) {
  470                   specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
  471               }
  472               if (specVersion == null) {
  473                   specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
  474               }
  475               if (specVendor == null) {
  476                   specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
  477               }
  478               if (implTitle == null) {
  479                   implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
  480               }
  481               if (implVersion == null) {
  482                   implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
  483               }
  484               if (implVendor == null) {
  485                   implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
  486               }
  487               if (sealed == null) {
  488                   sealed = attr.getValue(Name.SEALED);
  489               }
  490           }
  491           if ("true".equalsIgnoreCase(sealed)) {
  492               sealBase = url;
  493           }
  494           pkgName = name;
  495           this.specTitle = specTitle;
  496           this.specVersion = specVersion;
  497           this.specVendor = specVendor;
  498           this.implTitle = implTitle;
  499           this.implVersion = implVersion;
  500           this.implVendor = implVendor;
  501           this.sealBase = sealBase;
  502           this.loader = loader;
  503       }
  504   
  505       /*
  506        * Returns the loaded system package for the specified name.
  507        */
  508       static Package getSystemPackage(String name) {
  509           synchronized (pkgs) {
  510               Package pkg = pkgs.get(name);
  511               if (pkg == null) {
  512                   name = name.replace('.', '/').concat("/");
  513                   String fn = getSystemPackage0(name);
  514                   if (fn != null) {
  515                       pkg = defineSystemPackage(name, fn);
  516                   }
  517               }
  518               return pkg;
  519           }
  520       }
  521   
  522       /*
  523        * Return an array of loaded system packages.
  524        */
  525       static Package[] getSystemPackages() {
  526           // First, update the system package map with new package names
  527           String[] names = getSystemPackages0();
  528           synchronized (pkgs) {
  529               for (int i = 0; i < names.length; i++) {
  530                   defineSystemPackage(names[i], getSystemPackage0(names[i]));
  531               }
  532               return pkgs.values().toArray(new Package[pkgs.size()]);
  533           }
  534       }
  535   
  536       private static Package defineSystemPackage(final String iname,
  537                                                  final String fn)
  538       {
  539           return AccessController.doPrivileged(new PrivilegedAction<Package>() {
  540               public Package run() {
  541                   String name = iname;
  542                   // Get the cached code source url for the file name
  543                   URL url = urls.get(fn);
  544                   if (url == null) {
  545                       // URL not found, so create one
  546                       File file = new File(fn);
  547                       try {
  548                           url = ParseUtil.fileToEncodedURL(file);
  549                       } catch (MalformedURLException e) {
  550                       }
  551                       if (url != null) {
  552                           urls.put(fn, url);
  553                           // If loading a JAR file, then also cache the manifest
  554                           if (file.isFile()) {
  555                               mans.put(fn, loadManifest(fn));
  556                           }
  557                       }
  558                   }
  559                   // Convert to "."-separated package name
  560                   name = name.substring(0, name.length() - 1).replace('/', '.');
  561                   Package pkg;
  562                   Manifest man = mans.get(fn);
  563                   if (man != null) {
  564                       pkg = new Package(name, man, url, null);
  565                   } else {
  566                       pkg = new Package(name, null, null, null,
  567                                         null, null, null, null, null);
  568                   }
  569                   pkgs.put(name, pkg);
  570                   return pkg;
  571               }
  572           });
  573       }
  574   
  575       /*
  576        * Returns the Manifest for the specified JAR file name.
  577        */
  578       private static Manifest loadManifest(String fn) {
  579           try {
  580               FileInputStream fis = new FileInputStream(fn);
  581               JarInputStream jis = new JarInputStream(fis, false);
  582               Manifest man = jis.getManifest();
  583               jis.close();
  584               return man;
  585           } catch (IOException e) {
  586               return null;
  587           }
  588       }
  589   
  590       // The map of loaded system packages
  591       private static Map<String, Package> pkgs
  592           = new HashMap<String, Package>(31);
  593   
  594       // Maps each directory or zip file name to its corresponding url
  595       private static Map<String, URL> urls
  596           = new HashMap<String, URL>(10);
  597   
  598       // Maps each code source url for a jar file to its manifest
  599       private static Map<String, Manifest> mans
  600           = new HashMap<String, Manifest>(10);
  601   
  602       private static native String getSystemPackage0(String name);
  603       private static native String[] getSystemPackages0();
  604   
  605       /*
  606        * Private storage for the package name and attributes.
  607        */
  608       private final String pkgName;
  609       private final String specTitle;
  610       private final String specVersion;
  611       private final String specVendor;
  612       private final String implTitle;
  613       private final String implVersion;
  614       private final String implVendor;
  615       private final URL sealBase;
  616       private transient final ClassLoader loader;
  617       private transient Class packageInfo;
  618   }

Save This Page
Home » openjdk-7 » java » lang » [javadoc | source]