src/share/classes/sun/misc/URLClassPath.java

Print this page
rev 10187 : mq

*** 1,7 **** /* ! * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 36,45 **** --- 36,46 ---- import java.util.jar.Attributes; import java.util.jar.Attributes.Name; import java.net.JarURLConnection; import java.net.MalformedURLException; import java.net.URL; + import java.net.URLClassLoader; import java.net.URLConnection; import java.net.HttpURLConnection; import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; import java.io.*;
*** 50,59 **** --- 51,61 ---- import java.security.PrivilegedAction; import java.security.PrivilegedExceptionAction; import java.security.cert.Certificate; import sun.misc.FileURLMapper; import sun.net.util.URLUtil; + import sun.security.action.GetPropertyAction; /** * This class is used to maintain a search path of URLs for loading classes * and resources from both JAR files and directories. *
*** 61,79 **** */ public class URLClassPath { final static String USER_AGENT_JAVA_VERSION = "UA-Java-Version"; final static String JAVA_VERSION; private static final boolean DEBUG; private static final boolean DISABLE_JAR_CHECKING; static { JAVA_VERSION = java.security.AccessController.doPrivileged( ! new sun.security.action.GetPropertyAction("java.version")); DEBUG = (java.security.AccessController.doPrivileged( ! new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.debug")) != null); String p = java.security.AccessController.doPrivileged( ! new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.disableJarChecking")); DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.equals("") : false; } /* The original search path of URLs. */ private ArrayList<URL> path = new ArrayList<URL>(); --- 63,84 ---- */ public class URLClassPath { final static String USER_AGENT_JAVA_VERSION = "UA-Java-Version"; final static String JAVA_VERSION; private static final boolean DEBUG; + private static final boolean DEBUG_LOOKUP_CACHE; private static final boolean DISABLE_JAR_CHECKING; static { JAVA_VERSION = java.security.AccessController.doPrivileged( ! new GetPropertyAction("java.version")); DEBUG = (java.security.AccessController.doPrivileged( ! new GetPropertyAction("sun.misc.URLClassPath.debug")) != null); ! DEBUG_LOOKUP_CACHE = (java.security.AccessController.doPrivileged( ! new GetPropertyAction("sun.misc.URLClassPath.debugLookupCache")) != null); String p = java.security.AccessController.doPrivileged( ! new GetPropertyAction("sun.misc.URLClassPath.disableJarChecking")); DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.equals("") : false; } /* The original search path of URLs. */ private ArrayList<URL> path = new ArrayList<URL>();
*** 147,156 **** --- 152,167 ---- if (url == null || path.contains(url)) return; urls.add(0, url); path.add(url); + + if (lookupCacheURLs != null) { + // The lookup cache is no longer valid, since getLookupCache() + // does not consider the newly added url. + disableAllLookupCaches(); + } } } /** * Returns the original search path of URLs.
*** 170,180 **** * @return a <code>URL</code> for the resource, or <code>null</code> * if the resource could not be found. */ public URL findResource(String name, boolean check) { Loader loader; ! for (int i = 0; (loader = getLoader(i)) != null; i++) { URL url = loader.findResource(name, check); if (url != null) { return url; } } --- 181,192 ---- * @return a <code>URL</code> for the resource, or <code>null</code> * if the resource could not be found. */ public URL findResource(String name, boolean check) { Loader loader; ! int[] cache = getLookupCache(name); ! for (int i = 0; (loader = getNextLoader(cache, i)) != null; i++) { URL url = loader.findResource(name, check); if (url != null) { return url; } }
*** 193,203 **** if (DEBUG) { System.err.println("URLClassPath.getResource(\"" + name + "\")"); } Loader loader; ! for (int i = 0; (loader = getLoader(i)) != null; i++) { Resource res = loader.getResource(name, check); if (res != null) { return res; } } --- 205,216 ---- if (DEBUG) { System.err.println("URLClassPath.getResource(\"" + name + "\")"); } Loader loader; ! int[] cache = getLookupCache(name); ! for (int i = 0; (loader = getNextLoader(cache, i)) != null; i++) { Resource res = loader.getResource(name, check); if (res != null) { return res; } }
*** 213,230 **** */ public Enumeration<URL> findResources(final String name, final boolean check) { return new Enumeration<URL>() { private int index = 0; private URL url = null; private boolean next() { if (url != null) { return true; } else { Loader loader; ! while ((loader = getLoader(index++)) != null) { url = loader.findResource(name, check); if (url != null) { return true; } } --- 226,244 ---- */ public Enumeration<URL> findResources(final String name, final boolean check) { return new Enumeration<URL>() { private int index = 0; + private int[] cache = getLookupCache(name); private URL url = null; private boolean next() { if (url != null) { return true; } else { Loader loader; ! while ((loader = getNextLoader(cache, index++)) != null) { url = loader.findResource(name, check); if (url != null) { return true; } }
*** 260,277 **** */ public Enumeration<Resource> getResources(final String name, final boolean check) { return new Enumeration<Resource>() { private int index = 0; private Resource res = null; private boolean next() { if (res != null) { return true; } else { Loader loader; ! while ((loader = getLoader(index++)) != null) { res = loader.getResource(name, check); if (res != null) { return true; } } --- 274,292 ---- */ public Enumeration<Resource> getResources(final String name, final boolean check) { return new Enumeration<Resource>() { private int index = 0; + private int[] cache = getLookupCache(name); private Resource res = null; private boolean next() { if (res != null) { return true; } else { Loader loader; ! while ((loader = getNextLoader(cache, index++)) != null) { res = loader.getResource(name, check); if (res != null) { return true; } }
*** 296,305 **** --- 311,465 ---- public Enumeration<Resource> getResources(final String name) { return getResources(name, true); } + private static volatile boolean lookupCacheEnabled + = "true".equals(VM.getSavedProperty("sun.cds.enableSharedLookupCache")); + private URL[] lookupCacheURLs; + private ClassLoader lookupCacheLoader; + + synchronized void initLookupCache(ClassLoader loader) { + if ((lookupCacheURLs = getLookupCacheURLs(loader)) != null) { + lookupCacheLoader = loader; + } else { + // This JVM instance does not support lookup cache. + disableAllLookupCaches(); + } + } + + static void disableAllLookupCaches() { + lookupCacheEnabled = false; + } + + private static native URL[] getLookupCacheURLs(ClassLoader loader); + private static native int[] getLookupCacheForClassLoader(ClassLoader loader, + String name); + private static native boolean knownToNotExist0(ClassLoader loader, + String className); + + synchronized boolean knownToNotExist(String className) { + if (lookupCacheURLs != null && lookupCacheEnabled) { + return knownToNotExist0(lookupCacheLoader, className); + } + + // Don't know if this class exists or not -- need to do a full search. + return false; + } + + /** + * Returns an array of the index to lookupCacheURLs that may + * contain the specified resource. The values in the returned + * array are in strictly ascending order and must be a valid index + * to lookupCacheURLs array. + * + * This method returns an empty array if the specified resource + * cannot be found in this URLClassPath. If there is no lookup + * cache or it's disabled, this method returns null and the lookup + * should search the entire classpath. + * + * Example: if lookupCacheURLs contains {a.jar, b.jar, c.jar, d.jar} + * and package "foo" only exists in a.jar and c.jar, + * getLookupCache("foo/Bar.class") will return {0, 2} + * + * @param name the resource name + * @return an array of the index to lookupCacheURLs that may contain the + * specified resource; or null if no lookup cache is used. + */ + private synchronized int[] getLookupCache(String name) { + if (lookupCacheURLs == null || !lookupCacheEnabled) { + return null; + } + + int[] cache = getLookupCacheForClassLoader(lookupCacheLoader, name); + if (cache != null && cache.length > 0) { + int maxindex = cache[cache.length - 1]; // cache[] is strictly ascending. + if (!ensureLoaderOpened(maxindex)) { + if (DEBUG_LOOKUP_CACHE) { + System.out.println("Expanded loaders FAILED " + + loaders.size() + " for maxindex=" + maxindex); + } + return null; + } + } + + return cache; + } + + private boolean ensureLoaderOpened(int index) { + if (loaders.size() <= index) { + // Open all Loaders up to, and including, index + if (getLoader(index) == null) { + return false; + } + if (!lookupCacheEnabled) { + // cache was invalidated as the result of the above call. + return false; + } + if (DEBUG_LOOKUP_CACHE) { + System.out.println("Expanded loaders " + loaders.size() + + " to index=" + index); + } + } + return true; + } + + /* + * The CLASS-PATH attribute was expanded by the VM when building + * the resource lookup cache in the same order as the getLoader + * method does. This method validates if the URL from the lookup + * cache matches the URL of the Loader at the given index; + * otherwise, this method disables the lookup cache. + */ + private synchronized void validateLookupCache(int index, + String urlNoFragString) { + if (lookupCacheURLs != null && lookupCacheEnabled) { + if (index < lookupCacheURLs.length && + urlNoFragString.equals( + URLUtil.urlNoFragString(lookupCacheURLs[index]))) { + return; + } + if (DEBUG || DEBUG_LOOKUP_CACHE) { + System.out.println("WARNING: resource lookup cache invalidated " + + "for lookupCacheLoader at " + index); + } + disableAllLookupCaches(); + } + } + + /** + * Returns the next Loader that may contain the resource to + * lookup. If the given cache is null, return loaders.get(index) + * that may be lazily created; otherwise, cache[index] is the next + * Loader that may contain the resource to lookup and so returns + * loaders.get(cache[index]). + * + * If cache is non-null, loaders.get(cache[index]) must be present. + * + * @param cache lookup cache. If null, search the entire class path + * @param index index to the given cache array; or to the loaders list. + */ + private synchronized Loader getNextLoader(int[] cache, int index) { + if (closed) { + return null; + } + if (cache != null) { + if (index < cache.length) { + Loader loader = loaders.get(cache[index]); + if (DEBUG_LOOKUP_CACHE) { + System.out.println("HASCACHE: Loading from : " + cache[index] + + " = " + loader.getBaseURL()); + } + return loader; + } else { + return null; // finished iterating over cache[] + } + } else { + return getLoader(index); + } + } + /* * Returns the Loader at the specified position in the URL search * path. The URLs are opened and expanded as needed. Returns null * if the specified index is out of range. */
*** 339,351 **** --- 499,515 ---- } catch (IOException e) { // Silently ignore for now... continue; } // Finally, add the Loader to the search path. + validateLookupCache(loaders.size(), urlNoFragString); loaders.add(loader); lmap.put(urlNoFragString, loader); } + if (DEBUG_LOOKUP_CACHE) { + System.out.println("NOCACHE: Loading from : " + index ); + } return loaders.get(index); } /* * Returns the Loader for the specified base URL.