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

Print this page
rev 10786 : 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;
*** 474,484 **** * * @param name the package name * @param man the optional manifest for the package * @param url the optional code source url for the package */ ! private Package(String name, Manifest man, URL url, ClassLoader loader) { String path = name.replace('.', '/').concat("/"); String sealed = null; String specTitle= null; String specVersion= null; String specVendor= null; --- 468,478 ---- * * @param name the package name * @param man the optional manifest for the package * @param url the optional code source url for the package */ ! private Package(String name, Manifest man, URL url) { String path = name.replace('.', '/').concat("/"); String sealed = null; String specTitle= null; String specVersion= null; String specVendor= null;
*** 529,632 **** this.specVendor = specVendor; this.implTitle = implTitle; this.implVersion = implVersion; this.implVendor = implVendor; this.sealBase = sealBase; ! this.loader = loader; } /* * 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. */ private static Manifest loadManifest(String fn) { try (FileInputStream fis = new FileInputStream(fn); JarInputStream jis = new JarInputStream(fis, false)) { return jis.getManifest(); } catch (IOException e) { ! 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(); /* --- 523,655 ---- this.specVendor = specVendor; this.implTitle = implTitle; this.implVersion = implVersion; this.implVendor = implVendor; this.sealBase = sealBase; ! this.loader = null; } /* * 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) { // Convert to "."-separated package name ! String name = iname.substring(0, iname.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); ! pkgs.putIfAbsent(name, new Package(name, cachedManifest.getManifest(), ! cachedManifest.getURL())); ! // Ensure we only expose one Package object ! return pkgs.get(name); } ! ! private static CachedManifest createCachedManifest(String fn) { ! if (!manifests.containsKey(fn)) { ! manifests.putIfAbsent(fn, new CachedManifest(fn)); } ! return manifests.get(fn); } + private static final Manifest EMPTY_MANIFEST = new Manifest(); + /* * Returns the Manifest for the specified JAR file name. */ private static Manifest loadManifest(String fn) { try (FileInputStream fis = new FileInputStream(fn); JarInputStream jis = new JarInputStream(fis, false)) { return jis.getManifest(); } catch (IOException e) { ! return EMPTY_MANIFEST; } } // The map of loaded system packages ! private static final ConcurrentHashMap<String, Package> pkgs ! = new ConcurrentHashMap<>(); ! ! ! // Maps each directory or zip file name to its corresponding manifest, if ! // it exists ! private static final ConcurrentHashMap<String, CachedManifest> manifests ! = new ConcurrentHashMap<>(); ! ! private static class CachedManifest { ! private final String fileName; ! private final URL url; ! private volatile Manifest manifest = EMPTY_MANIFEST; ! ! CachedManifest(final String fileName) { ! this.fileName = fileName; ! this.url = AccessController.doPrivileged(new PrivilegedAction<URL>() { ! public URL run() { ! final File file = new File(fileName); ! if (file.isFile()) { ! try { ! return ParseUtil.fileToEncodedURL(file); ! } catch (MalformedURLException e) { ! } ! } ! return null; ! } ! }); ! } ! public URL getURL() { ! return url; ! } ! public Manifest getManifest() { ! resolveManifest(); ! return manifest; ! } ! ! private void resolveManifest() { ! if (manifest != null || url == null) { ! return; ! } ! synchronized(this) { ! if (manifest == null) { ! manifest = AccessController.doPrivileged(new PrivilegedAction<Manifest>() { ! public Manifest run() { ! return loadManifest(fileName); ! } ! }); ! } ! } ! } ! } private static native String getSystemPackage0(String name); private static native String[] getSystemPackages0(); /*