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();
/*