home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / lang / Package.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  16.9 KB  |  504 lines

  1. /*
  2.  * @(#)Package.java    1.18 98/03/18
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.lang;
  16.  
  17. import java.io.InputStream;
  18. import java.util.Enumeration;
  19.  
  20. import java.util.StringTokenizer;
  21. import java.io.File;
  22. import java.io.FileInputStream;
  23. import java.io.FileNotFoundException;
  24. import java.net.URL;
  25. import java.security.AccessController;
  26.  
  27. import java.util.jar.JarFile;
  28. import java.util.jar.Manifest;
  29. import java.util.jar.Attributes;
  30. import java.util.jar.Attributes.Name;
  31. import java.util.jar.JarException;
  32. import java.util.Map;
  33. import java.util.HashMap;
  34. import java.util.Iterator;
  35.  
  36. import sun.misc.URLClassPath;
  37. import sun.misc.Resource;
  38.  
  39. /**
  40.  * <code>Package</code> objects contain version information
  41.  * about the implementation and specification of a Java package.
  42.  * This versioning information is retrieved and made available
  43.  * by the classloader that loaded the class(es). Typically, it is
  44.  * stored in the manifest that is distributed with the classes.<p>
  45.  *
  46.  * The set of classes that make up the package may implement a
  47.  * particular specification and if
  48.  * so the specification title, version number, and vendor strings 
  49.  * identify that specification. 
  50.  * An application can ask if the package is
  51.  * compatible with a particular version, see the <code>isCompatibleWith</code>
  52.  * method for details. <p>
  53.  *
  54.  * Specification version numbers use a "Dewey Decimal"
  55.  * syntax that consists of positive decimal integers
  56.  * separated by periods ".", for example, "2.0" or "1.2.3.4.5.6.7".
  57.  * This allows an extensible number to be used to
  58.  * represent major, minor, micro, etc versions.
  59.  * The version number must begin with a number. <p>
  60.  *
  61.  * The package title, package, and vendor strings identify an
  62.  * implementation and are made available conveniently to enable accurate
  63.  * reporting of the packages involved when a problem occurs.
  64.  * The version strings have no
  65.  * specified syntax and may only be compared for equality with
  66.  * desired version identifers. The contents are vendor specific.<p>
  67.  *
  68.  * Within each classloader all classes from the same java package have
  69.  * the same Package object.  The static methods allow a package 
  70.  * to be found by name or the set of all packages known
  71.  * to the current class loader to be found.<p>
  72.  *
  73.  * @see ClassLoader#definePackage
  74.  */
  75. public class Package {
  76.     /**
  77.      * Return the name of this package.
  78.      *
  79.      * @return The name of this package using the Java language dot notation
  80.      *         for the package. i.e  java.lang
  81.      */
  82.     public String getName() {
  83.     return pkgName;
  84.     }
  85.  
  86.  
  87.     /**
  88.      * Return the title of the specification that this package implements.
  89.      * @return the specification title, null is returned if it is not known.
  90.      */
  91.     public String getSpecificationTitle() {
  92.     return specTitle;
  93.     }
  94.     
  95.     /**
  96.      * Returns the version number of the specification
  97.      * that this package implements.
  98.      * This version string must be a sequence of positive decimal
  99.      * integers separated by "."'s and may have leading zeros.
  100.      * When version strings are compared the most significant
  101.      * numbers are compared.
  102.      * @return the specification version, null is returned if it is not known.
  103.      */
  104.     public String getSpecificationVersion() {
  105.     return specVersion;
  106.     }
  107.  
  108.     /**
  109.      * Return the name of the organization,
  110.      * vendor, or company that provided
  111.      * the classes that implement this package.
  112.      * @return the specification vendor, null is returned if it is not known.
  113.      */
  114.     public String getSpecificationVendor() {
  115.     return specVendor;
  116.     }
  117.  
  118.     /**
  119.      * Return the title of this package.
  120.      * @return the title of the implementation, null is returned if it is not known.
  121.      */
  122.     public String getImplementationTitle() {
  123.     return implTitle;
  124.     }
  125.  
  126.     /**
  127.      * Return the version of this implementation. It consists of any string
  128.      * assigned by the vendor of this implementation and does
  129.      * not have any particular syntax specified or expected by the Java
  130.      * runtime. It may be compared for equality with other
  131.      * package version strings used for this implementation
  132.      * by this vendor for this package.
  133.      * @return the version of the implementation, null is returned if it is not known.
  134.      */    
  135.     public String getImplementationVersion() {
  136.         return implVersion;
  137.     }
  138.  
  139.     /**
  140.      * Returns the name of the organization,
  141.      * vendor or company that provided this implementation.
  142.      * @return the vendor that implemented this package..
  143.      */
  144.     public String getImplementationVendor() {
  145.         return implVendor;
  146.     }
  147.  
  148.     /**
  149.      * Returns true if the package is sealed. getSealBase() will return the
  150.      * base URL for sealing. Any classes loaded from the package must
  151.      * originate from the same base URL.
  152.      * @return true if the package is sealed, false otherwise
  153.      */
  154.     public boolean isSealed() {
  155.     return sealBase != null;
  156.     }
  157.  
  158.     /**
  159.      * If the package is sealed, then it returns the base URL from which the
  160.      * package was loaded. If the URL returned does not end with a '/' then
  161.      * it refers to a JAR file.
  162.      * @return the base URL that this package was loaded from, or null
  163.      *         if the package was not sealed.
  164.      */
  165.     public URL getSealBase() {
  166.     return sealBase;
  167.     }
  168.  
  169.     /**
  170.      * Compare this package's specification version with a
  171.      * desired version. It returns true if
  172.      * this packages specification version number is greater than or equal
  173.      * to the desired version number. <p>
  174.      *
  175.      * Version numbers are compared by sequentially comparing corresponding
  176.      * components of the desired and specification strings.
  177.      * Each component is converted as a decimal integer and the values
  178.      * compared.
  179.      * If the specification value is greater than the desired
  180.      * value true is returned. If the value is less false is returned.
  181.      * If the values are equal the period is skipped and the next pair of
  182.      * components is compared.
  183.      *
  184.      * @param desired the version string of the desired version.
  185.      * @return true if this package's version number is greater
  186.      *         than or equal to the desired version number<br>  
  187.      *        
  188.      * @exception NumberFormatException if the desired or current version
  189.      *        is not of the correct dotted form.
  190.      */
  191.     public boolean isCompatibleWith(String desired)
  192.     throws NumberFormatException
  193.     {
  194.         if (specVersion == null || specVersion.length() < 1) {
  195.         throw new NumberFormatException("Empty version string");
  196.     }
  197.  
  198.         // Until it matches scan and compare numbers
  199.         StringTokenizer dtok = new StringTokenizer(desired, ".", true);
  200.         StringTokenizer stok = new StringTokenizer(specVersion, ".", true);
  201.     while (dtok.hasMoreTokens() || stok.hasMoreTokens()) {
  202.         int dver;
  203.         int sver;
  204.         if (dtok.hasMoreTokens()) {
  205.         dver = Integer.parseInt(dtok.nextToken());
  206.         } else
  207.         dver = 0;
  208.  
  209.         if (stok.hasMoreTokens()) {
  210.         sver = Integer.parseInt(stok.nextToken());
  211.         } else
  212.         sver = 0;
  213.  
  214.             if (sver < dver)
  215.                 return false;        // Known to be incompatible
  216.             if (sver > dver)
  217.                 return true;        // Known to be compatible
  218.  
  219.             // Check for and absorb seperators
  220.             if (dtok.hasMoreTokens())
  221.                 dtok.nextToken();
  222.             if (stok.hasMoreTokens())
  223.                 stok.nextToken();
  224.             // Compare next component
  225.         }
  226.         // All components numerically equal
  227.     return true;
  228.     }
  229.  
  230.     /**
  231.      * Find a package by name in the callers classloader.
  232.      * The callers classloader is used to find the package instance
  233.      * corresponding to the named class. If the callers classloader
  234.      * is null then the set of packages loaded by the system
  235.      * classloader is searched to find the named package. <p>
  236.      *
  237.      * Packages have attributes for versions and specifications only
  238.      * if the class loader created the package
  239.      * instance with the appropriate attributes. Typically, those
  240.      * attributes are defined in the manifests that accompany
  241.      * the classes.
  242.      *
  243.      * @param packageName a package name, for example, java.lang.
  244.      * @return the package of the requested name. It may be null if no package
  245.      *         information is available from the archive or codebase.
  246.      */
  247.     public static Package getPackage(String name) {
  248.  
  249.     ClassLoader l = getCallerClassLoader();
  250.     if (l != null) {
  251.         return l.getPackage(name);
  252.     } else {
  253.         return getSystemPackage(name);
  254.     }
  255.     }
  256.  
  257.     /**
  258.      * Get all the packages currently known for the callers classloader.
  259.      * Those packages correspond to classes loaded via or accessible
  260.      * by name to that classloader.  If the callers classloader is
  261.      * null only the packages corresponding to system classes will
  262.      * be returned.
  263.      *
  264.      * @return a new array of packages known to the callers classloader.
  265.      * An zero length array is returned if none are known.
  266.      */
  267.     public static Package[] getAllPackages() {
  268.     ClassLoader l = getCallerClassLoader();
  269.     if (l != null) {
  270.         return l.getPackages();
  271.     } else {
  272.         return getSystemPackages();
  273.     }
  274.     }
  275.  
  276.     /**
  277.      * Get the package for the specified class.
  278.      * The classes classloader is used to find the package instance
  279.      * corresponding to the specified class. If the classloader
  280.      * is null then the set of packages loaded by the system
  281.      * classloader is searched to find the package. <p>
  282.      *
  283.      * Packages have attributes for versions and specifications only
  284.      * if the class loader created the package
  285.      * instance with the appropriate attributes. Typically those
  286.      * attributes are defined in the manifests that accompany
  287.      * the classes.
  288.      *
  289.      * @param class the class to get the package of.
  290.      * @return the package of the class. It may be null if no package
  291.      *         information is available from the archive or codebase.  */
  292.     static Package getPackage(Class c) {
  293.     String name = c.getName();
  294.     int i = name.lastIndexOf('.');
  295.     if (i != -1) {
  296.         name = name.substring(0, i);
  297.         ClassLoader cl = c.getClassLoader();
  298.         if (cl != null) {
  299.         return cl.getPackage(name);
  300.         } else {
  301.         return getSystemPackage(name);
  302.         }
  303.     } else {
  304.         return null;
  305.     }
  306.     }
  307.  
  308.     /**
  309.      * Return the hashcode computed from the package name.
  310.      * @return the hodecode computed from the package name.
  311.      */
  312.     public int hashCode(){
  313.         return pkgName.hashCode();
  314.     }
  315.  
  316.     /**
  317.      * Returns the string representation of this Package.
  318.      * Its value is the string "package " and the package name.
  319.      * If the package title is defined it is appended.
  320.      * If the package version is defined it is appended.
  321.      * @return the string representation of the package.
  322.      */
  323.     public String toString() {
  324.     String spec = specTitle;
  325.     String ver =  specVersion;
  326.     if (spec != null && spec.length() > 0)
  327.         spec = ", " + spec;
  328.     else
  329.         spec = "";
  330.     if (ver != null && ver.length() > 0)
  331.         ver = ", version " + ver;
  332.     else
  333.         ver = "";
  334.     return "package " + pkgName + spec + ver;
  335.     }
  336.  
  337.     /**
  338.      * Construct a package instance with the specified version
  339.      * information.
  340.      * @param pkgName the name of the package
  341.      * @param spectitle the title of the specification
  342.      * @param specversion the version of the specification
  343.      * @param specvendor the organization that maintains the specification
  344.      * @param impltitle the title of the implementation
  345.      * @param implversion the version of the implementation
  346.      * @param implvendor the organization that maintains the implementation
  347.      * @return a new package for containing the specified information.
  348.      */
  349.     Package(String name, 
  350.         String spectitle, String specversion, String specvendor,
  351.         String impltitle, String implversion, String implvendor,
  352.         URL sealbase)
  353.     {
  354.         pkgName = name;
  355.     implTitle = impltitle;
  356.     implVersion = implversion;
  357.     implVendor = implvendor;
  358.     specTitle = spectitle;
  359.     specVersion = specversion;
  360.     specVendor = specvendor;
  361.     sealBase = sealbase;
  362.     }
  363.  
  364.     /*
  365.      * Construct a package from its name and the attributes from
  366.      * the manifest.
  367.      */
  368.     private Package(String name, Attributes attr, URL sealbase) {
  369.     pkgName = name;
  370.     sealBase = sealbase;
  371.     if (attr != null) {
  372.         specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
  373.         specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
  374.         specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
  375.         implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
  376.         implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
  377.         implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
  378.     }
  379.     }
  380.  
  381.     /*
  382.      * Returns the system package for the specified name.
  383.      */
  384.     static Package getSystemPackage(String name) {
  385.     return (Package)getSystemPackageMap().get(name);
  386.     }
  387.  
  388.     /**
  389.      * Return an array of the system packages.  The package and
  390.      * version information is extracted from the manifest
  391.      * co-located with the java.lang.Object.class file. <p>
  392.      *
  393.      * @return    An array of Packages of the package information found for
  394.      *        classes in CLASSPATH.
  395.      */
  396.     static Package[] getSystemPackages() {
  397.     Map map = getSystemPackageMap();
  398.     return (Package[])map.values().toArray(new Package[map.size()]);
  399.     }
  400.  
  401.     // The Map of system packages
  402.     private static Map systemPackageMap;
  403.  
  404.     static synchronized Map getSystemPackageMap() {
  405.     if (systemPackageMap == null) {
  406.         Map pkgs = new HashMap(31);
  407.         try {
  408.         AccessController.beginPrivileged();
  409.         URLClassPath ucp = ClassLoader.getSystemClassPath();
  410.         Enumeration e = ucp.getManifests();
  411.         while (e.hasMoreElements()) {
  412.             Resource res = (Resource)e.nextElement();
  413.             definePackages(res, pkgs);
  414.         }
  415.         } finally {
  416.         AccessController.endPrivileged();
  417.         }
  418.         systemPackageMap = pkgs;
  419.     }
  420.     return systemPackageMap;
  421.     }
  422.  
  423.     /* Create the packages from this manifest.
  424.      * For each Name: entry that ends in a "/", i.e corresponds to
  425.      * a directory. If the package has not already been defined.
  426.      * Look for the specified versioning attributes.
  427.      * If not found default to the attributes with the same names
  428.      * in the main attributes.
  429.      */
  430.     private static void definePackages(Resource res, Map pkgs) {
  431.     // XXX Need to figure out how we can set this without exposing
  432.     // file path information to users. Best way is to get rid of
  433.     // getSealBase() by moving package seal checking to here. For
  434.     // now we do not set sealBase for system classes.
  435.     URL sealBase = null;
  436.     Manifest man = res.getManifest();
  437.     Attributes main = man.getMainAttributes();
  438.     String mainSpecTitle   = main.getValue(Name.SPECIFICATION_TITLE);
  439.     String mainSpecVersion = main.getValue(Name.SPECIFICATION_VERSION);
  440.     String mainSpecVendor  = main.getValue(Name.SPECIFICATION_VENDOR);
  441.     String mainImplTitle   = main.getValue(Name.IMPLEMENTATION_TITLE);
  442.     String mainImplVersion = main.getValue(Name.IMPLEMENTATION_VERSION);
  443.     String mainImplVendor  = main.getValue(Name.IMPLEMENTATION_VENDOR);
  444.  
  445.     Map entries = man.getEntries();
  446.     Iterator it = entries.entries().iterator();
  447.     while (it.hasNext()) {
  448.         Map.Entry e = (Map.Entry)it.next();
  449.         String name = (String)e.getKey();
  450.         if (name == null || !name.endsWith("/"))
  451.         continue;
  452.  
  453.         name = (name.substring(0, name.length()-1)).replace('/', '.');
  454.  
  455.         if (pkgs.get(name) == null) {
  456.                 // Define the package using the attributes.
  457.         Attributes attr = (Attributes)e.getValue();
  458.         String
  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.  
  466.         // Apply defaults if not specified for this package.
  467.         if (specTitle == null)
  468.             specTitle = mainSpecTitle;
  469.         if (specVersion == null)
  470.             specVersion = mainSpecVersion;
  471.         if (specVendor == null)
  472.             specVendor = mainSpecVendor;
  473.         if (implTitle == null)
  474.             implTitle = mainImplTitle;
  475.         if (implVersion == null)
  476.             implVersion = mainImplVersion;
  477.         if (implVendor == null)
  478.             implVendor = mainImplVendor;
  479.  
  480.         pkgs.put(name, new Package(name, specTitle, specVersion,
  481.                        specVendor, implTitle,
  482.                        implVersion, implVendor, sealBase));
  483.         }
  484.     }
  485.     }
  486.     /*
  487.      * Private storage for the package name and attributes.
  488.      */
  489.     private String pkgName;
  490.     private String specTitle;
  491.     private String specVersion;
  492.     private String specVendor;
  493.     private String implTitle;
  494.     private String implVersion;
  495.     private String implVendor;
  496.     private URL sealBase;
  497.  
  498.  
  499.     /*
  500.      * Private access to the caller so it's classloader can be returned.
  501.      */
  502.     private static native ClassLoader getCallerClassLoader();
  503. }
  504.