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™ 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