KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > lang > Package


1 /*
2  * @(#)Package.java 1.45 04/04/26
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.lang;
9
10 import java.io.InputStream JavaDoc;
11 import java.util.Enumeration JavaDoc;
12
13 import java.util.StringTokenizer JavaDoc;
14 import java.io.File JavaDoc;
15 import java.io.FileInputStream JavaDoc;
16 import java.io.FileNotFoundException JavaDoc;
17 import java.io.IOException JavaDoc;
18 import java.net.URL JavaDoc;
19 import java.net.MalformedURLException JavaDoc;
20 import java.security.AccessController JavaDoc;
21 import java.security.PrivilegedAction JavaDoc;
22
23 import java.util.jar.JarInputStream JavaDoc;
24 import java.util.jar.Manifest JavaDoc;
25 import java.util.jar.Attributes JavaDoc;
26 import java.util.jar.Attributes.Name;
27 import java.util.jar.JarException JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Iterator JavaDoc;
31
32 import sun.net.www.ParseUtil;
33
34 import java.lang.annotation.Annotation JavaDoc;
35
36 /**
37  * <code>Package</code> objects contain version information
38  * about the implementation and specification of a Java package.
39  * This versioning information is retrieved and made available
40  * by the {@link ClassLoader <code>ClassLoader</code>} instance that
41  * loaded the class(es). Typically, it is stored in the manifest that is
42  * distributed with the classes.
43  *
44  * <p>The set of classes that make up the package may implement a
45  * particular specification and if so the specification title, version number,
46  * and vendor strings identify that specification.
47  * An application can ask if the package is
48  * compatible with a particular version, see the {@link #isCompatibleWith
49  * <code>isCompatibleWith</code>} method for details.
50  *
51  * <p>Specification version numbers use a syntax that consists of positive
52  * decimal integers separated by periods ".", for example "2.0" or
53  * "1.2.3.4.5.6.7". This allows an extensible number to be used to represent
54  * major, minor, micro, etc. versions. The version specification is described
55  * by the following formal grammar:
56  * <blockquote>
57  * <dl>
58  * <dt><i>SpecificationVersion:
59  * <dd>Digits RefinedVersion<sub>opt</sub></i>
60
61  * <p><dt><i>RefinedVersion:</i>
62  * <dd><code>.</code> <i>Digits</i>
63  * <dd><code>.</code> <i>Digits RefinedVersion</i>
64  *
65  * <p><dt><i>Digits:
66  * <dd>Digit
67  * <dd>Digits</i>
68  *
69  * <p><dt><i>Digit:</i>
70  * <dd>any character for which {@link Character#isDigit} returns <code>true</code>,
71  * e.g. 0, 1, 2, ...
72  * </dl>
73  * </blockquote>
74  *
75  * <p>The implementation title, version, and vendor strings identify an
76  * implementation and are made available conveniently to enable accurate
77  * reporting of the packages involved when a problem occurs. The contents
78  * all three implementation strings are vendor specific. The
79  * implementation version strings have no specified syntax and should
80  * only be compared for equality with desired version identifiers.
81  *
82  * <p>Within each <code>ClassLoader</code> instance all classes from the same
83  * java package have the same Package object. The static methods allow a package
84  * to be found by name or the set of all packages known to the current class
85  * loader to be found.
86  *
87  * @see ClassLoader#definePackage
88  */

89 public class Package implements java.lang.reflect.AnnotatedElement JavaDoc {
90     /**
91      * Return the name of this package.
92      *
93      * @return The name of this package using the Java language dot notation
94      * for the package. i.e java.lang
95      */

96     public String JavaDoc getName() {
97     return pkgName;
98     }
99
100
101     /**
102      * Return the title of the specification that this package implements.
103      * @return the specification title, null is returned if it is not known.
104      */

105     public String JavaDoc getSpecificationTitle() {
106     return specTitle;
107     }
108
109     /**
110      * Returns the version number of the specification
111      * that this package implements.
112      * This version string must be a sequence of positive decimal
113      * integers separated by "."'s and may have leading zeros.
114      * When version strings are compared the most significant
115      * numbers are compared.
116      * @return the specification version, null is returned if it is not known.
117      */

118     public String JavaDoc getSpecificationVersion() {
119     return specVersion;
120     }
121
122     /**
123      * Return the name of the organization, vendor,
124      * or company that owns and maintains the specification
125      * of the classes that implement this package.
126      * @return the specification vendor, null is returned if it is not known.
127      */

128     public String JavaDoc getSpecificationVendor() {
129     return specVendor;
130     }
131
132     /**
133      * Return the title of this package.
134      * @return the title of the implementation, null is returned if it is not known.
135      */

136     public String JavaDoc getImplementationTitle() {
137     return implTitle;
138     }
139
140     /**
141      * Return the version of this implementation. It consists of any string
142      * assigned by the vendor of this implementation and does
143      * not have any particular syntax specified or expected by the Java
144      * runtime. It may be compared for equality with other
145      * package version strings used for this implementation
146      * by this vendor for this package.
147      * @return the version of the implementation, null is returned if it is not known.
148      */

149     public String JavaDoc getImplementationVersion() {
150         return implVersion;
151     }
152
153     /**
154      * Returns the name of the organization,
155      * vendor or company that provided this implementation.
156      * @return the vendor that implemented this package..
157      */

158     public String JavaDoc getImplementationVendor() {
159         return implVendor;
160     }
161
162     /**
163      * Returns true if this package is sealed.
164      *
165      * @return true if the package is sealed, false otherwise
166      */

167     public boolean isSealed() {
168     return sealBase != null;
169     }
170
171     /**
172      * Returns true if this package is sealed with respect to the specified
173      * code source url.
174      *
175      * @param url the code source url
176      * @return true if this package is sealed with respect to url
177      */

178     public boolean isSealed(URL JavaDoc url) {
179     return url.equals(sealBase);
180     }
181
182     /**
183      * Compare this package's specification version with a
184      * desired version. It returns true if
185      * this packages specification version number is greater than or equal
186      * to the desired version number. <p>
187      *
188      * Version numbers are compared by sequentially comparing corresponding
189      * components of the desired and specification strings.
190      * Each component is converted as a decimal integer and the values
191      * compared.
192      * If the specification value is greater than the desired
193      * value true is returned. If the value is less false is returned.
194      * If the values are equal the period is skipped and the next pair of
195      * components is compared.
196      *
197      * @param desired the version string of the desired version.
198      * @return true if this package's version number is greater
199      * than or equal to the desired version number
200      *
201      * @exception NumberFormatException if the desired or current version
202      * is not of the correct dotted form.
203      */

204     public boolean isCompatibleWith(String JavaDoc desired)
205     throws NumberFormatException JavaDoc
206     {
207         if (specVersion == null || specVersion.length() < 1) {
208         throw new NumberFormatException JavaDoc("Empty version string");
209     }
210
211     String JavaDoc [] sa = specVersion.split("\\.", -1);
212     int [] si = new int[sa.length];
213     for (int i = 0; i < sa.length; i++) {
214         si[i] = Integer.parseInt(sa[i]);
215         if (si[i] < 0)
216         throw NumberFormatException.forInputString("" + si[i]);
217     }
218
219     String JavaDoc [] da = desired.split("\\.", -1);
220     int [] di = new int[da.length];
221     for (int i = 0; i < da.length; i++) {
222         di[i] = Integer.parseInt(da[i]);
223         if (di[i] < 0)
224         throw NumberFormatException.forInputString("" + di[i]);
225     }
226
227     int len = Math.max(di.length, si.length);
228     for (int i = 0; i < len; i++) {
229         int d = (i < di.length ? di[i] : 0);
230         int s = (i < si.length ? si[i] : 0);
231         if (s < d)
232         return false;
233         if (s > d)
234         return true;
235     }
236     return true;
237     }
238
239     /**
240      * Find a package by name in the callers <code>ClassLoader</code> instance.
241      * The callers <code>ClassLoader</code> instance is used to find the package
242      * instance corresponding to the named class. If the callers
243      * <code>ClassLoader</code> instance is null then the set of packages loaded
244      * by the system <code>ClassLoader</code> instance is searched to find the
245      * named package. <p>
246      *
247      * Packages have attributes for versions and specifications only if the class
248      * loader created the package instance with the appropriate attributes. Typically,
249      * those attributes are defined in the manifests that accompany the classes.
250      *
251      * @param name a package name, for example, java.lang.
252      * @return the package of the requested name. It may be null if no package
253      * information is available from the archive or codebase.
254      */

255     public static Package JavaDoc getPackage(String JavaDoc name) {
256     ClassLoader JavaDoc l = ClassLoader.getCallerClassLoader();
257     if (l != null) {
258         return l.getPackage(name);
259     } else {
260         return getSystemPackage(name);
261     }
262     }
263
264     /**
265      * Get all the packages currently known for the caller's <code>ClassLoader</code>
266      * instance. Those packages correspond to classes loaded via or accessible by
267      * name to that <code>ClassLoader</code> instance. If the caller's
268      * <code>ClassLoader</code> instance is the bootstrap <code>ClassLoader</code>
269      * instance, which may be represented by <code>null</code> in some implementations,
270      * only packages corresponding to classes loaded by the bootstrap
271      * <code>ClassLoader</code> instance will be returned.
272      *
273      * @return a new array of packages known to the callers <code>ClassLoader</code>
274      * instance. An zero length array is returned if none are known.
275      */

276     public static Package JavaDoc[] getPackages() {
277     ClassLoader JavaDoc l = ClassLoader.getCallerClassLoader();
278     if (l != null) {
279         return l.getPackages();
280     } else {
281         return getSystemPackages();
282     }
283     }
284
285     /**
286      * Get the package for the specified class.
287      * The class's class loader is used to find the package instance
288      * corresponding to the specified class. If the class loader
289      * is the bootstrap class loader, which may be represented by
290      * <code>null</code> in some implementations, then the set of packages
291      * loaded by the bootstrap class loader is searched to find the package.
292      * <p>
293      * Packages have attributes for versions and specifications only
294      * if the class loader created the package
295      * instance with the appropriate attributes. Typically those
296      * attributes are defined in the manifests that accompany
297      * the classes.
298      *
299      * @param class the class to get the package of.
300      * @return the package of the class. It may be null if no package
301      * information is available from the archive or codebase. */

302     static Package JavaDoc getPackage(Class JavaDoc c) {
303     String JavaDoc name = c.getName();
304     int i = name.lastIndexOf('.');
305     if (i != -1) {
306         name = name.substring(0, i);
307         ClassLoader JavaDoc cl = c.getClassLoader();
308         if (cl != null) {
309         return cl.getPackage(name);
310         } else {
311         return getSystemPackage(name);
312         }
313     } else {
314         return null;
315     }
316     }
317
318     /**
319      * Return the hash code computed from the package name.
320      * @return the hash code computed from the package name.
321      */

322     public int hashCode(){
323         return pkgName.hashCode();
324     }
325
326     /**
327      * Returns the string representation of this Package.
328      * Its value is the string "package " and the package name.
329      * If the package title is defined it is appended.
330      * If the package version is defined it is appended.
331      * @return the string representation of the package.
332      */

333     public String JavaDoc toString() {
334     String JavaDoc spec = specTitle;
335     String JavaDoc ver = specVersion;
336     if (spec != null && spec.length() > 0)
337         spec = ", " + spec;
338     else
339         spec = "";
340     if (ver != null && ver.length() > 0)
341         ver = ", version " + ver;
342     else
343         ver = "";
344     return "package " + pkgName + spec + ver;
345     }
346
347     private Class JavaDoc<?> getPackageInfo() {
348         if (packageInfo == null) {
349             try {
350                 packageInfo = Class.forName(pkgName + ".package-info", false, loader);
351             } catch (ClassNotFoundException JavaDoc ex) {
352                 // store a proxy for the package info that has no annotations
353
class PackageInfoProxy {}
354                 packageInfo = PackageInfoProxy.class;
355             }
356         }
357         return packageInfo;
358     }
359
360     public <A extends Annotation JavaDoc> A getAnnotation(Class JavaDoc<A> annotationClass) {
361         return getPackageInfo().getAnnotation(annotationClass);
362     }
363
364     public boolean isAnnotationPresent(
365         Class JavaDoc<? extends Annotation JavaDoc> annotationClass)
366     {
367         return getPackageInfo().isAnnotationPresent(annotationClass);
368     }
369
370     public Annotation JavaDoc[] getAnnotations() {
371         return getPackageInfo().getAnnotations();
372     }
373
374     public Annotation JavaDoc[] getDeclaredAnnotations() {
375         return getPackageInfo().getDeclaredAnnotations();
376     }
377
378     /**
379      * Construct a package instance with the specified version
380      * information.
381      * @param pkgName the name of the package
382      * @param spectitle the title of the specification
383      * @param specversion the version of the specification
384      * @param specvendor the organization that maintains the specification
385      * @param impltitle the title of the implementation
386      * @param implversion the version of the implementation
387      * @param implvendor the organization that maintains the implementation
388      * @return a new package for containing the specified information.
389      */

390     Package(String JavaDoc name,
391         String JavaDoc spectitle, String JavaDoc specversion, String JavaDoc specvendor,
392         String JavaDoc impltitle, String JavaDoc implversion, String JavaDoc implvendor,
393         URL JavaDoc sealbase, ClassLoader JavaDoc loader)
394     {
395         pkgName = name;
396     implTitle = impltitle;
397     implVersion = implversion;
398     implVendor = implvendor;
399     specTitle = spectitle;
400     specVersion = specversion;
401     specVendor = specvendor;
402     sealBase = sealbase;
403     this.loader = loader;
404     }
405
406     /*
407      * Construct a package using the attributes from the specified manifest.
408      *
409      * @param name the package name
410      * @param man the optional manifest for the package
411      * @param url the optional code source url for the package
412      */

413     private Package(String JavaDoc name, Manifest JavaDoc man, URL JavaDoc url, ClassLoader JavaDoc loader) {
414     String JavaDoc path = name.replace('.', '/').concat("/");
415     String JavaDoc sealed = null;
416     String JavaDoc specTitle= null;
417     String JavaDoc specVersion= null;
418     String JavaDoc specVendor= null;
419     String JavaDoc implTitle= null;
420     String JavaDoc implVersion= null;
421     String JavaDoc implVendor= null;
422     URL JavaDoc sealBase= null;
423     Attributes JavaDoc attr = man.getAttributes(path);
424     if (attr != null) {
425         specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
426         specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
427         specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
428         implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
429         implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
430         implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
431         sealed = attr.getValue(Name.SEALED);
432     }
433     attr = man.getMainAttributes();
434     if (attr != null) {
435         if (specTitle == null) {
436         specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
437         }
438         if (specVersion == null) {
439         specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
440         }
441         if (specVendor == null) {
442         specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
443         }
444         if (implTitle == null) {
445         implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
446         }
447         if (implVersion == null) {
448         implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
449         }
450         if (implVendor == null) {
451         implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
452         }
453         if (sealed == null) {
454         sealed = attr.getValue(Name.SEALED);
455         }
456     }
457     if ("true".equalsIgnoreCase(sealed)) {
458         sealBase = url;
459     }
460     pkgName = name;
461     this.specTitle = specTitle;
462     this.specVersion = specVersion;
463     this.specVendor = specVendor;
464     this.implTitle = implTitle;
465     this.implVersion = implVersion;
466     this.implVendor = implVendor;
467     this.sealBase = sealBase;
468     this.loader = loader;
469     }
470
471     /*
472      * Returns the loaded system package for the specified name.
473      */

474     static Package JavaDoc getSystemPackage(String JavaDoc name) {
475     synchronized (pkgs) {
476         Package JavaDoc pkg = (Package JavaDoc)pkgs.get(name);
477         if (pkg == null) {
478         name = name.replace('.', '/').concat("/");
479         String JavaDoc fn = getSystemPackage0(name);
480         if (fn != null) {
481             pkg = defineSystemPackage(name, fn);
482         }
483         }
484         return pkg;
485     }
486     }
487
488     /*
489      * Return an array of loaded system packages.
490      */

491     static Package JavaDoc[] getSystemPackages() {
492     // First, update the system package map with new package names
493
String JavaDoc[] names = getSystemPackages0();
494     synchronized (pkgs) {
495         for (int i = 0; i < names.length; i++) {
496         defineSystemPackage(names[i], getSystemPackage0(names[i]));
497         }
498         return (Package JavaDoc[])pkgs.values().toArray(new Package JavaDoc[pkgs.size()]);
499     }
500     }
501
502     private static Package JavaDoc defineSystemPackage(final String JavaDoc iname,
503                            final String JavaDoc fn)
504     {
505     return (Package JavaDoc) AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
506         public Object JavaDoc run() {
507         String JavaDoc name = iname;
508         // Get the cached code source url for the file name
509
URL JavaDoc url = (URL JavaDoc)urls.get(fn);
510         if (url == null) {
511             // URL not found, so create one
512
File JavaDoc file = new File JavaDoc(fn);
513             try {
514             url = ParseUtil.fileToEncodedURL(file);
515             } catch (MalformedURLException JavaDoc e) {
516             }
517             if (url != null) {
518             urls.put(fn, url);
519             // If loading a JAR file, then also cache the manifest
520
if (file.isFile()) {
521                 mans.put(fn, loadManifest(fn));
522             }
523             }
524         }
525         // Convert to "."-separated package name
526
name = name.substring(0, name.length() - 1).replace('/', '.');
527         Package JavaDoc pkg;
528         Manifest JavaDoc man = (Manifest JavaDoc)mans.get(fn);
529         if (man != null) {
530             pkg = new Package JavaDoc(name, man, url, null);
531         } else {
532             pkg = new Package JavaDoc(name, null, null, null,
533                       null, null, null, null, null);
534         }
535         pkgs.put(name, pkg);
536         return pkg;
537         }
538     });
539     }
540
541     /*
542      * Returns the Manifest for the specified JAR file name.
543      */

544     private static Manifest JavaDoc loadManifest(String JavaDoc fn) {
545     try {
546         FileInputStream JavaDoc fis = new FileInputStream JavaDoc(fn);
547         JarInputStream JavaDoc jis = new JarInputStream JavaDoc(fis, false);
548         Manifest JavaDoc man = jis.getManifest();
549         jis.close();
550         return man;
551     } catch (IOException JavaDoc e) {
552         return null;
553     }
554     }
555
556     // The map of loaded system packages
557
private static Map JavaDoc pkgs = new HashMap JavaDoc(31);
558
559     // Maps each directory or zip file name to its corresponding url
560
private static Map JavaDoc urls = new HashMap JavaDoc(10);
561
562     // Maps each code source url for a jar file to its manifest
563
private static Map JavaDoc mans = new HashMap JavaDoc(10);
564
565     private static native String JavaDoc getSystemPackage0(String JavaDoc name);
566     private static native String JavaDoc[] getSystemPackages0();
567
568     /*
569      * Private storage for the package name and attributes.
570      */

571     private final String JavaDoc pkgName;
572     private final String JavaDoc specTitle;
573     private final String JavaDoc specVersion;
574     private final String JavaDoc specVendor;
575     private final String JavaDoc implTitle;
576     private final String JavaDoc implVersion;
577     private final String JavaDoc implVendor;
578     private final URL JavaDoc sealBase;
579     private transient final ClassLoader JavaDoc loader;
580     private transient Class JavaDoc packageInfo;
581 }
582
Popular Tags