home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / lang / Package.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  16.8 KB  |  522 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)Package.java    1.28 98/09/08
  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.io.IOException;
  25. import java.net.URL;
  26. import java.net.MalformedURLException;
  27. import java.security.AccessController;
  28. import java.security.PrivilegedAction;
  29.  
  30. import java.util.jar.JarInputStream;
  31. import java.util.jar.Manifest;
  32. import java.util.jar.Attributes;
  33. import java.util.jar.Attributes.Name;
  34. import java.util.jar.JarException;
  35. import java.util.Map;
  36. import java.util.HashMap;
  37. import java.util.Iterator;
  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 implementation title, version, 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. The contents
  64.  * all three implementation strings are vendor specific. The
  65.  * implementation version strings have no specified syntax and should
  66.  * only be compared for equality with desired version identifers.
  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, vendor, 
  110.      * or company that owns and maintains the specification 
  111.      * of 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 this package is sealed.
  150.      *
  151.      * @return true if the package is sealed, false otherwise
  152.      */
  153.     public boolean isSealed() {
  154.     return sealBase != null;
  155.     }
  156.  
  157.     /**
  158.      * Returns true if this package is sealed with respect to the specified
  159.      * code source url.
  160.      *
  161.      * @param url the code source url
  162.      */
  163.     public boolean isSealed(URL url) {
  164.     return url.equals(sealBase);
  165.     }
  166.  
  167.     /**
  168.      * Compare this package's specification version with a
  169.      * desired version. It returns true if
  170.      * this packages specification version number is greater than or equal
  171.      * to the desired version number. <p>
  172.      *
  173.      * Version numbers are compared by sequentially comparing corresponding
  174.      * components of the desired and specification strings.
  175.      * Each component is converted as a decimal integer and the values
  176.      * compared.
  177.      * If the specification value is greater than the desired
  178.      * value true is returned. If the value is less false is returned.
  179.      * If the values are equal the period is skipped and the next pair of
  180.      * components is compared.
  181.      *
  182.      * @param desired the version string of the desired version.
  183.      * @return true if this package's version number is greater
  184.      *         than or equal to the desired version number<br>  
  185.      *        
  186.      * @exception NumberFormatException if the desired or current version
  187.      *        is not of the correct dotted form.
  188.      */
  189.     public boolean isCompatibleWith(String desired)
  190.     throws NumberFormatException
  191.     {
  192.         if (specVersion == null || specVersion.length() < 1) {
  193.         throw new NumberFormatException("Empty version string");
  194.     }
  195.  
  196.         // Until it matches scan and compare numbers
  197.         StringTokenizer dtok = new StringTokenizer(desired, ".", true);
  198.         StringTokenizer stok = new StringTokenizer(specVersion, ".", true);
  199.     while (dtok.hasMoreTokens() || stok.hasMoreTokens()) {
  200.         int dver;
  201.         int sver;
  202.         if (dtok.hasMoreTokens()) {
  203.         dver = Integer.parseInt(dtok.nextToken());
  204.         } else
  205.         dver = 0;
  206.  
  207.         if (stok.hasMoreTokens()) {
  208.         sver = Integer.parseInt(stok.nextToken());
  209.         } else
  210.         sver = 0;
  211.  
  212.             if (sver < dver)
  213.                 return false;        // Known to be incompatible
  214.             if (sver > dver)
  215.                 return true;        // Known to be compatible
  216.  
  217.             // Check for and absorb seperators
  218.             if (dtok.hasMoreTokens())
  219.                 dtok.nextToken();
  220.             if (stok.hasMoreTokens())
  221.                 stok.nextToken();
  222.             // Compare next component
  223.         }
  224.         // All components numerically equal
  225.     return true;
  226.     }
  227.  
  228.     /**
  229.      * Find a package by name in the callers classloader.
  230.      * The callers classloader is used to find the package instance
  231.      * corresponding to the named class. If the callers classloader
  232.      * is null then the set of packages loaded by the system
  233.      * classloader is searched to find the named package. <p>
  234.      *
  235.      * Packages have attributes for versions and specifications only
  236.      * if the class loader created the package
  237.      * instance with the appropriate attributes. Typically, those
  238.      * attributes are defined in the manifests that accompany
  239.      * the classes.
  240.      *
  241.      * @param packageName a package name, for example, java.lang.
  242.      * @return the package of the requested name. It may be null if no package
  243.      *         information is available from the archive or codebase.
  244.      */
  245.     public static Package getPackage(String name) {
  246.     ClassLoader l = ClassLoader.getCallerClassLoader();
  247.     if (l != null) {
  248.         return l.getPackage(name);
  249.     } else {
  250.         return getSystemPackage(name);
  251.     }
  252.     }
  253.  
  254.     /**
  255.      * Get all the packages currently known for the caller's class loader.
  256.      * Those packages correspond to classes loaded via or accessible
  257.      * by name to that class loader.  If the caller's class loader is
  258.      * the bootstrap classloader, which may be represented by 
  259.      * <code>null</code> in some implementations, only packages corresponding 
  260.      * to classes loaded by the bootstrap class loader will be returned.
  261.      *
  262.      * @return a new array of packages known to the callers classloader.
  263.      * An zero length array is returned if none are known.
  264.      */
  265.     public static Package[] getPackages() {
  266.     ClassLoader l = ClassLoader.getCallerClassLoader();
  267.     if (l != null) {
  268.         return l.getPackages();
  269.     } else {
  270.         return getSystemPackages();
  271.     }
  272.     }
  273.  
  274.     /**
  275.      * Get the package for the specified class.
  276.      * The class's class loader is used to find the package instance
  277.      * corresponding to the specified class. If the class loader
  278.      * is the bootstrap class loader, which may be represented by 
  279.      * <code>null</code> in some implementations, then the set of packages 
  280.      * loaded by the bootstrap class loader is searched to find the package.
  281.      * <p>
  282.      * Packages have attributes for versions and specifications only
  283.      * if the class loader created the package
  284.      * instance with the appropriate attributes. Typically those
  285.      * attributes are defined in the manifests that accompany
  286.      * the classes.
  287.      *
  288.      * @param class the class to get the package of.
  289.      * @return the package of the class. It may be null if no package
  290.      *         information is available from the archive or codebase.  */
  291.     static Package getPackage(Class c) {
  292.     String name = c.getName();
  293.     int i = name.lastIndexOf('.');
  294.     if (i != -1) {
  295.         name = name.substring(0, i);
  296.         ClassLoader cl = c.getClassLoader();
  297.         if (cl != null) {
  298.         return cl.getPackage(name);
  299.         } else {
  300.         return getSystemPackage(name);
  301.         }
  302.     } else {
  303.         return null;
  304.     }
  305.     }
  306.  
  307.     /**
  308.      * Return the hashcode computed from the package name.
  309.      * @return the hodecode computed from the package name.
  310.      */
  311.     public int hashCode(){
  312.         return pkgName.hashCode();
  313.     }
  314.  
  315.     /**
  316.      * Returns the string representation of this Package.
  317.      * Its value is the string "package " and the package name.
  318.      * If the package title is defined it is appended.
  319.      * If the package version is defined it is appended.
  320.      * @return the string representation of the package.
  321.      */
  322.     public String toString() {
  323.     String spec = specTitle;
  324.     String ver =  specVersion;
  325.     if (spec != null && spec.length() > 0)
  326.         spec = ", " + spec;
  327.     else
  328.         spec = "";
  329.     if (ver != null && ver.length() > 0)
  330.         ver = ", version " + ver;
  331.     else
  332.         ver = "";
  333.     return "package " + pkgName + spec + ver;
  334.     }
  335.  
  336.     /**
  337.      * Construct a package instance with the specified version
  338.      * information.
  339.      * @param pkgName the name of the package
  340.      * @param spectitle the title of the specification
  341.      * @param specversion the version of the specification
  342.      * @param specvendor the organization that maintains the specification
  343.      * @param impltitle the title of the implementation
  344.      * @param implversion the version of the implementation
  345.      * @param implvendor the organization that maintains the implementation
  346.      * @return a new package for containing the specified information.
  347.      */
  348.     Package(String name, 
  349.         String spectitle, String specversion, String specvendor,
  350.         String impltitle, String implversion, String implvendor,
  351.         URL sealbase)
  352.     {
  353.         pkgName = name;
  354.     implTitle = impltitle;
  355.     implVersion = implversion;
  356.     implVendor = implvendor;
  357.     specTitle = spectitle;
  358.     specVersion = specversion;
  359.     specVendor = specvendor;
  360.     sealBase = sealbase;
  361.     }
  362.  
  363.     /*
  364.      * Construct a package using the attributes from the specified manifest.
  365.      *
  366.      * @param name the package name
  367.      * @param man the optional manifest for the package
  368.      * @param url the optional code source url for the package
  369.      */
  370.     private Package(String name, Manifest man, URL url) {
  371.     String path = name.replace('.', '/').concat("/");
  372.     String sealed = null;
  373.     Attributes attr = man.getAttributes(path);
  374.     if (attr != null) {
  375.         specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
  376.         specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
  377.         specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
  378.         implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
  379.         implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
  380.         implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
  381.         sealed      = attr.getValue(Name.SEALED);
  382.     }
  383.     attr = man.getMainAttributes();
  384.     if (attr != null) {
  385.         if (specTitle == null) {
  386.         specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
  387.         }
  388.         if (specVersion == null) {
  389.         specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
  390.         }
  391.         if (specVendor == null) {
  392.         specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
  393.         }
  394.         if (implTitle == null) {
  395.         implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
  396.         }
  397.         if (implVersion == null) {
  398.         implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
  399.         }
  400.         if (implVendor == null) {
  401.         implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
  402.         }
  403.         if (sealed == null) {
  404.         sealed = attr.getValue(Name.SEALED);
  405.         }
  406.     }
  407.     if ("true".equalsIgnoreCase(sealed)) {
  408.         sealBase = url;
  409.     }
  410.     pkgName = name;
  411.     }
  412.  
  413.     /*
  414.      * Returns the loaded system package for the specified name.
  415.      */
  416.     static Package getSystemPackage(String name) {
  417.     synchronized (pkgs) {
  418.         Package pkg = (Package)pkgs.get(name);
  419.         if (pkg == null) {
  420.         name = name.replace('.', '/').concat("/");
  421.         String fn = getSystemPackage0(name);
  422.         if (fn != null) {
  423.             pkg = defineSystemPackage(name, fn);
  424.         }
  425.         }
  426.         return pkg;
  427.     }
  428.     }
  429.  
  430.     /*
  431.      * Return an array of loaded system packages.
  432.      */
  433.     static Package[] getSystemPackages() {
  434.     // First, update the system package map with new package names
  435.     String[] names = getSystemPackages0();
  436.     synchronized (pkgs) {
  437.         for (int i = 0; i < names.length; i++) {
  438.         defineSystemPackage(names[i], getSystemPackage0(names[i]));
  439.         }
  440.         return (Package[])pkgs.values().toArray(new Package[pkgs.size()]);
  441.     }
  442.     }
  443.  
  444.     private static Package defineSystemPackage(final String iname,
  445.                            final String fn) 
  446.     {
  447.     return (Package) AccessController.doPrivileged(new PrivilegedAction() {
  448.         public Object run() {
  449.         String name = iname;
  450.         // Get the cached code source url for the file name
  451.         URL url = (URL)urls.get(fn);
  452.         if (url == null) {
  453.             // URL not found, so create one
  454.             File file = new File(fn);
  455.             try {
  456.             url = file.toURL();
  457.             } catch (MalformedURLException e) {
  458.             }
  459.             if (url != null) {
  460.             urls.put(fn, url);
  461.             // If loading a JAR file, then also cache the manifest
  462.             if (file.isFile()) {
  463.                 mans.put(fn, loadManifest(fn));
  464.             }
  465.             }
  466.         }
  467.         // Convert to "."-separated package name
  468.         name = name.substring(0, name.length() - 1).replace('/', '.');
  469.         Package pkg;
  470.         Manifest man = (Manifest)mans.get(fn);
  471.         if (man != null) {
  472.             pkg = new Package(name, man, url);
  473.         } else {
  474.             pkg = new Package(name, null, null, null,
  475.                       null, null, null, null);
  476.         }
  477.         pkgs.put(name, pkg);
  478.         return pkg;
  479.         }
  480.     });
  481.     }
  482.  
  483.     /*
  484.      * Returns the Manifest for the specified JAR file name.
  485.      */
  486.     private static Manifest loadManifest(String fn) {
  487.     try {
  488.         FileInputStream fis = new FileInputStream(fn);
  489.         JarInputStream jis = new JarInputStream(fis, false);
  490.         Manifest man = jis.getManifest();
  491.         jis.close();
  492.         return man;
  493.     } catch (IOException e) {
  494.         return null;
  495.     }
  496.     }
  497.  
  498.     // The map of loaded system packages
  499.     private static Map pkgs = new HashMap(31);
  500.     
  501.     // Maps each directory or zip file name to its corresponding url
  502.     private static Map urls = new HashMap(10);
  503.  
  504.     // Maps each code source url for a jar file to its manifest
  505.     private static Map mans = new HashMap(10);
  506.  
  507.     private static native String getSystemPackage0(String name);
  508.     private static native String[] getSystemPackages0();
  509.  
  510.     /*
  511.      * Private storage for the package name and attributes.
  512.      */
  513.     private String pkgName;
  514.     private String specTitle;
  515.     private String specVersion;
  516.     private String specVendor;
  517.     private String implTitle;
  518.     private String implVersion;
  519.     private String implVendor;
  520.     private URL sealBase;
  521. }
  522.