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