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