src/java.base/share/classes/java/lang/Package.java

Print this page
rev 10764 : 8060130: Simplify the synchronization of defining and getting java.lang.Package
Reviewed-by: mchung

*** 24,54 **** */ package java.lang; import java.lang.reflect.AnnotatedElement; - import java.io.InputStream; - import java.util.Enumeration; - import java.util.StringTokenizer; import java.io.File; import java.io.FileInputStream; - import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; import java.net.MalformedURLException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import java.util.jar.Attributes; import java.util.jar.Attributes.Name; - import java.util.jar.JarException; import java.util.Map; - import java.util.HashMap; - import java.util.Iterator; import sun.net.www.ParseUtil; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; --- 24,48 ---- */ package java.lang; import java.lang.reflect.AnnotatedElement; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URL; import java.net.MalformedURLException; import java.security.AccessController; import java.security.PrivilegedAction; + import java.util.concurrent.ConcurrentHashMap; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import java.util.jar.Attributes; import java.util.jar.Attributes.Name; import java.util.Map; import sun.net.www.ParseUtil; import sun.reflect.CallerSensitive; import sun.reflect.Reflection;
*** 536,609 **** /* * Returns the loaded system package for the specified name. */ static Package getSystemPackage(String name) { - synchronized (pkgs) { Package pkg = pkgs.get(name); if (pkg == null) { ! name = name.replace('.', '/').concat("/"); String fn = getSystemPackage0(name); if (fn != null) { pkg = defineSystemPackage(name, fn); } } return pkg; } - } /* * Return an array of loaded system packages. */ static Package[] getSystemPackages() { // First, update the system package map with new package names String[] names = getSystemPackages0(); - synchronized (pkgs) { for (String name : names) { defineSystemPackage(name, getSystemPackage0(name)); } - return pkgs.values().toArray(new Package[pkgs.size()]); } } private static Package defineSystemPackage(final String iname, final String fn) { - return AccessController.doPrivileged(new PrivilegedAction<Package>() { - public Package run() { String name = iname; - // Get the cached code source url for the file name - URL url = urls.get(fn); - if (url == null) { - // URL not found, so create one - File file = new File(fn); - try { - url = ParseUtil.fileToEncodedURL(file); - } catch (MalformedURLException e) { - } - if (url != null) { - urls.put(fn, url); - // If loading a JAR file, then also cache the manifest - if (file.isFile()) { - mans.put(fn, loadManifest(fn)); - } - } - } // Convert to "."-separated package name name = name.substring(0, name.length() - 1).replace('/', '.'); Package pkg; ! Manifest man = mans.get(fn); ! if (man != null) { ! pkg = new Package(name, man, url, null); } else { pkg = new Package(name, null, null, null, null, null, null, null, null); } pkgs.put(name, pkg); return pkg; } }); } /* * Returns the Manifest for the specified JAR file name. */ --- 530,611 ---- /* * Returns the loaded system package for the specified name. */ static Package getSystemPackage(String name) { Package pkg = pkgs.get(name); if (pkg == null) { ! name = name.replace('.', '/') + "/"; String fn = getSystemPackage0(name); if (fn != null) { pkg = defineSystemPackage(name, fn); } } return pkg; } /* * Return an array of loaded system packages. */ static Package[] getSystemPackages() { // First, update the system package map with new package names String[] names = getSystemPackages0(); for (String name : names) { + if (!pkgs.containsKey(name)) { defineSystemPackage(name, getSystemPackage0(name)); } } + return pkgs.values().toArray(new Package[pkgs.size()]); } private static Package defineSystemPackage(final String iname, final String fn) { String name = iname; // Convert to "."-separated package name name = name.substring(0, name.length() - 1).replace('/', '.'); + // Creates a cached manifest for the file name, allowing + // only-once, lazy reads of manifest from jar files + CachedManifest cachedManifest = createCachedManifest(fn); Package pkg; ! Manifest manifest = cachedManifest.getManifest(); ! if (manifest != null) { ! pkg = new Package(name, manifest, ! cachedManifest.getURL(), null); } else { pkg = new Package(name, null, null, null, null, null, null, null, null); } pkgs.put(name, pkg); return pkg; } + + private static CachedManifest createCachedManifest(String fn) { + CachedManifest manifest = manifests.get(fn); + if (manifest != null) { + return manifest; + } + URL url = AccessController.doPrivileged(new PrivilegedAction<URL>() { + public URL run() { + final File file = new File(fn); + if (file.isFile()) { + try { + return ParseUtil.fileToEncodedURL(file); + } catch (MalformedURLException e) { + } + } + return null; + } }); + if (url == null) { + return NO_MANIFEST; + } + manifest = new CachedManifest(fn); + CachedManifest oldManifest = manifests.putIfAbsent(fn, manifest); + // return the manifest which was created first to ensure + // only one manifest is ever read for any particular file + return (oldManifest != null) ? oldManifest : manifest; } /* * Returns the Manifest for the specified JAR file name. */
*** 616,632 **** return null; } } // The map of loaded system packages ! private static Map<String, Package> pkgs = new HashMap<>(31); ! // Maps each directory or zip file name to its corresponding url ! private static Map<String, URL> urls = new HashMap<>(10); ! // Maps each code source url for a jar file to its manifest ! private static Map<String, Manifest> mans = new HashMap<>(10); private static native String getSystemPackage0(String name); private static native String[] getSystemPackages0(); /* --- 618,686 ---- return null; } } // The map of loaded system packages ! private static final Map<String, Package> pkgs = new ConcurrentHashMap<>(); ! ! // Maps each directory or zip file name to its corresponding manifest, if ! // it exists ! private static final Map<String, CachedManifest> manifests = ! new ConcurrentHashMap<>(); ! private static final CachedManifest NO_MANIFEST = new CachedManifest(); ! private static class CachedManifest { ! private final String fileName; ! private volatile boolean resolved; ! private volatile Manifest manifest; ! private volatile URL url; ! ! CachedManifest() { ! this.fileName = null; ! this.resolved = true; ! } ! ! CachedManifest(String fileName) { ! this.fileName = fileName; ! } ! ! public URL getURL() { ! resolveManifest(); ! return url; ! } ! ! public Manifest getManifest() { ! resolveManifest(); ! return manifest; ! } ! ! private void resolveManifest() { ! if (resolved) { ! return; ! } ! synchronized(this) { ! if (resolved) { ! return; ! } ! AccessController.doPrivileged(new PrivilegedAction<Package>() { ! public Package run() { ! final File file = new File(fileName); ! if (file.isFile()) { ! try { ! url = ParseUtil.fileToEncodedURL(file); ! manifest = loadManifest(fileName); ! } catch (MalformedURLException e) { ! } ! } ! return null; ! } ! }); ! resolved = true; ! } ! } ! } private static native String getSystemPackage0(String name); private static native String[] getSystemPackages0(); /*