9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang;
27
28 import java.lang.reflect.AnnotatedElement;
29 import java.io.InputStream;
30 import java.util.Enumeration;
31
32 import java.util.StringTokenizer;
33 import java.io.File;
34 import java.io.FileInputStream;
35 import java.io.FileNotFoundException;
36 import java.io.IOException;
37 import java.net.URL;
38 import java.net.MalformedURLException;
39 import java.security.AccessController;
40 import java.security.PrivilegedAction;
41
42 import java.util.jar.JarInputStream;
43 import java.util.jar.Manifest;
44 import java.util.jar.Attributes;
45 import java.util.jar.Attributes.Name;
46 import java.util.jar.JarException;
47 import java.util.Map;
48 import java.util.HashMap;
49 import java.util.Iterator;
50
51 import sun.net.www.ParseUtil;
52 import sun.reflect.CallerSensitive;
53 import sun.reflect.Reflection;
54
55 import java.lang.annotation.Annotation;
56
57 /**
58 * {@code Package} objects contain version information
59 * about the implementation and specification of a Java package.
60 * This versioning information is retrieved and made available
61 * by the {@link ClassLoader} instance that
62 * loaded the class(es). Typically, it is stored in the manifest that is
63 * distributed with the classes.
64 *
65 * <p>The set of classes that make up the package may implement a
66 * particular specification and if so the specification title, version number,
67 * and vendor strings identify that specification.
68 * An application can ask if the package is
69 * compatible with a particular version, see the {@link
521 }
522 }
523 if ("true".equalsIgnoreCase(sealed)) {
524 sealBase = url;
525 }
526 pkgName = name;
527 this.specTitle = specTitle;
528 this.specVersion = specVersion;
529 this.specVendor = specVendor;
530 this.implTitle = implTitle;
531 this.implVersion = implVersion;
532 this.implVendor = implVendor;
533 this.sealBase = sealBase;
534 this.loader = loader;
535 }
536
537 /*
538 * Returns the loaded system package for the specified name.
539 */
540 static Package getSystemPackage(String name) {
541 synchronized (pkgs) {
542 Package pkg = pkgs.get(name);
543 if (pkg == null) {
544 name = name.replace('.', '/').concat("/");
545 String fn = getSystemPackage0(name);
546 if (fn != null) {
547 pkg = defineSystemPackage(name, fn);
548 }
549 }
550 return pkg;
551 }
552 }
553
554 /*
555 * Return an array of loaded system packages.
556 */
557 static Package[] getSystemPackages() {
558 // First, update the system package map with new package names
559 String[] names = getSystemPackages0();
560 synchronized (pkgs) {
561 for (String name : names) {
562 defineSystemPackage(name, getSystemPackage0(name));
563 }
564 return pkgs.values().toArray(new Package[pkgs.size()]);
565 }
566 }
567
568 private static Package defineSystemPackage(final String iname,
569 final String fn)
570 {
571 return AccessController.doPrivileged(new PrivilegedAction<Package>() {
572 public Package run() {
573 String name = iname;
574 // Get the cached code source url for the file name
575 URL url = urls.get(fn);
576 if (url == null) {
577 // URL not found, so create one
578 File file = new File(fn);
579 try {
580 url = ParseUtil.fileToEncodedURL(file);
581 } catch (MalformedURLException e) {
582 }
583 if (url != null) {
584 urls.put(fn, url);
585 // If loading a JAR file, then also cache the manifest
586 if (file.isFile()) {
587 mans.put(fn, loadManifest(fn));
588 }
589 }
590 }
591 // Convert to "."-separated package name
592 name = name.substring(0, name.length() - 1).replace('/', '.');
593 Package pkg;
594 Manifest man = mans.get(fn);
595 if (man != null) {
596 pkg = new Package(name, man, url, null);
597 } else {
598 pkg = new Package(name, null, null, null,
599 null, null, null, null, null);
600 }
601 pkgs.put(name, pkg);
602 return pkg;
603 }
604 });
605 }
606
607 /*
608 * Returns the Manifest for the specified JAR file name.
609 */
610 private static Manifest loadManifest(String fn) {
611 try (FileInputStream fis = new FileInputStream(fn);
612 JarInputStream jis = new JarInputStream(fis, false))
613 {
614 return jis.getManifest();
615 } catch (IOException e) {
616 return null;
617 }
618 }
619
620 // The map of loaded system packages
621 private static Map<String, Package> pkgs = new HashMap<>(31);
622
623 // Maps each directory or zip file name to its corresponding url
624 private static Map<String, URL> urls = new HashMap<>(10);
625
626 // Maps each code source url for a jar file to its manifest
627 private static Map<String, Manifest> mans = new HashMap<>(10);
628
629 private static native String getSystemPackage0(String name);
630 private static native String[] getSystemPackages0();
631
632 /*
633 * Private storage for the package name and attributes.
634 */
635 private final String pkgName;
636 private final String specTitle;
637 private final String specVersion;
638 private final String specVendor;
639 private final String implTitle;
640 private final String implVersion;
641 private final String implVendor;
642 private final URL sealBase;
643 private transient final ClassLoader loader;
644 private transient Class<?> packageInfo;
645 }
|
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang;
27
28 import java.lang.reflect.AnnotatedElement;
29
30 import java.io.File;
31 import java.io.FileInputStream;
32 import java.io.IOException;
33 import java.net.URL;
34 import java.net.MalformedURLException;
35 import java.security.AccessController;
36 import java.security.PrivilegedAction;
37
38 import java.util.concurrent.ConcurrentHashMap;
39 import java.util.jar.JarInputStream;
40 import java.util.jar.Manifest;
41 import java.util.jar.Attributes;
42 import java.util.jar.Attributes.Name;
43 import java.util.Map;
44
45 import sun.net.www.ParseUtil;
46 import sun.reflect.CallerSensitive;
47 import sun.reflect.Reflection;
48
49 import java.lang.annotation.Annotation;
50
51 /**
52 * {@code Package} objects contain version information
53 * about the implementation and specification of a Java package.
54 * This versioning information is retrieved and made available
55 * by the {@link ClassLoader} instance that
56 * loaded the class(es). Typically, it is stored in the manifest that is
57 * distributed with the classes.
58 *
59 * <p>The set of classes that make up the package may implement a
60 * particular specification and if so the specification title, version number,
61 * and vendor strings identify that specification.
62 * An application can ask if the package is
63 * compatible with a particular version, see the {@link
515 }
516 }
517 if ("true".equalsIgnoreCase(sealed)) {
518 sealBase = url;
519 }
520 pkgName = name;
521 this.specTitle = specTitle;
522 this.specVersion = specVersion;
523 this.specVendor = specVendor;
524 this.implTitle = implTitle;
525 this.implVersion = implVersion;
526 this.implVendor = implVendor;
527 this.sealBase = sealBase;
528 this.loader = loader;
529 }
530
531 /*
532 * Returns the loaded system package for the specified name.
533 */
534 static Package getSystemPackage(String name) {
535 Package pkg = pkgs.get(name);
536 if (pkg == null) {
537 name = name.replace('.', '/') + "/";
538 String fn = getSystemPackage0(name);
539 if (fn != null) {
540 pkg = defineSystemPackage(name, fn);
541 }
542 }
543 return pkg;
544 }
545
546 /*
547 * Return an array of loaded system packages.
548 */
549 static Package[] getSystemPackages() {
550 // First, update the system package map with new package names
551 String[] names = getSystemPackages0();
552 for (String name : names) {
553 if (!pkgs.containsKey(name)) {
554 defineSystemPackage(name, getSystemPackage0(name));
555 }
556 }
557 return pkgs.values().toArray(new Package[pkgs.size()]);
558 }
559
560 private static Package defineSystemPackage(final String iname,
561 final String fn)
562 {
563 String name = iname;
564 // Convert to "."-separated package name
565 name = name.substring(0, name.length() - 1).replace('/', '.');
566 // Creates a cached manifest for the file name, allowing
567 // only-once, lazy reads of manifest from jar files
568 CachedManifest cachedManifest = createCachedManifest(fn);
569 Package pkg;
570 Manifest manifest = cachedManifest.getManifest();
571 if (manifest != null) {
572 pkg = new Package(name, manifest,
573 cachedManifest.getURL(), null);
574 } else {
575 pkg = new Package(name, null, null, null,
576 null, null, null, null, null);
577 }
578 pkgs.put(name, pkg);
579 return pkg;
580 }
581
582 private static CachedManifest createCachedManifest(String fn) {
583 CachedManifest manifest = manifests.get(fn);
584 if (manifest != null) {
585 return manifest;
586 }
587 URL url = AccessController.doPrivileged(new PrivilegedAction<URL>() {
588 public URL run() {
589 final File file = new File(fn);
590 if (file.isFile()) {
591 try {
592 return ParseUtil.fileToEncodedURL(file);
593 } catch (MalformedURLException e) {
594 }
595 }
596 return null;
597 }
598 });
599 if (url == null) {
600 return NO_MANIFEST;
601 }
602 manifest = new CachedManifest(fn);
603 CachedManifest oldManifest = manifests.putIfAbsent(fn, manifest);
604 // return the manifest which was created first to ensure
605 // only one manifest is ever read for any particular file
606 return (oldManifest != null) ? oldManifest : manifest;
607 }
608
609 /*
610 * Returns the Manifest for the specified JAR file name.
611 */
612 private static Manifest loadManifest(String fn) {
613 try (FileInputStream fis = new FileInputStream(fn);
614 JarInputStream jis = new JarInputStream(fis, false))
615 {
616 return jis.getManifest();
617 } catch (IOException e) {
618 return null;
619 }
620 }
621
622 // The map of loaded system packages
623 private static final Map<String, Package> pkgs = new ConcurrentHashMap<>();
624
625 // Maps each directory or zip file name to its corresponding manifest, if
626 // it exists
627 private static final Map<String, CachedManifest> manifests =
628 new ConcurrentHashMap<>();
629
630 private static final CachedManifest NO_MANIFEST = new CachedManifest();
631
632 private static class CachedManifest {
633 private final String fileName;
634 private volatile boolean resolved;
635 private volatile Manifest manifest;
636 private volatile URL url;
637
638 CachedManifest() {
639 this.fileName = null;
640 this.resolved = true;
641 }
642
643 CachedManifest(String fileName) {
644 this.fileName = fileName;
645 }
646
647 public URL getURL() {
648 resolveManifest();
649 return url;
650 }
651
652 public Manifest getManifest() {
653 resolveManifest();
654 return manifest;
655 }
656
657 private void resolveManifest() {
658 if (resolved) {
659 return;
660 }
661 synchronized(this) {
662 if (resolved) {
663 return;
664 }
665 AccessController.doPrivileged(new PrivilegedAction<Package>() {
666 public Package run() {
667 final File file = new File(fileName);
668 if (file.isFile()) {
669 try {
670 url = ParseUtil.fileToEncodedURL(file);
671 manifest = loadManifest(fileName);
672 } catch (MalformedURLException e) {
673 }
674 }
675 return null;
676 }
677 });
678 resolved = true;
679 }
680 }
681 }
682
683 private static native String getSystemPackage0(String name);
684 private static native String[] getSystemPackages0();
685
686 /*
687 * Private storage for the package name and attributes.
688 */
689 private final String pkgName;
690 private final String specTitle;
691 private final String specVersion;
692 private final String specVendor;
693 private final String implTitle;
694 private final String implVersion;
695 private final String implVendor;
696 private final URL sealBase;
697 private transient final ClassLoader loader;
698 private transient Class<?> packageInfo;
699 }
|