* define the proxy class in the default loader. * * If the interface classes can not be loaded from the default * loader or the default loader is null, try to load them from * the RMI class loader. Then try to define the proxy class * in the RMI class loader. * * Additionally, if any of the proxy interface classes are not * public, all of the non-public interfaces must reside in the * same class loader or it will be impossible to define the * proxy class (an IllegalAccessError will be thrown). An * attempt to load the interfaces from the default loader is * made. If the attempt fails, a second attempt will be made * to load the interfaces from the RMI loader. If all of the * non-public interfaces classes do reside in the same class * loader, then we attempt to define the proxy class in the * class loader of the non-public interfaces. No other * attempt to define the proxy class will be made. */ ClassLoader parent = getRMIContextClassLoader(); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "(thread context class loader: " + parent + ")"); } URL[] urls; if (codebase != null) { urls = pathToURLs(codebase); } else { urls = getDefaultCodebaseURLs(); } /* * If no security manager is set, disable access to RMI class * loaders and use the would-de parent instead. */ SecurityManager sm = System.getSecurityManager(); if (sm == null) { try { Class c = loadProxyClass(interfaces, defaultLoader, parent, false); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "(no security manager: codebase disabled) " + "proxy class defined by " + c.getClassLoader()); } return c; } catch (ClassNotFoundException e) { if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "(no security manager: codebase disabled) " + "proxy class resolution failed", e); } throw new ClassNotFoundException(e.getMessage() + " (no security manager: RMI class loader disabled)", e.getException()); } } /* * Get or create the RMI class loader for this codebase URL path * and parent class loader pair. */ Loader loader = lookupLoader(urls, parent); try { if (loader != null) { /* * Verify that the caller has permission to access this loader. */ loader.checkPermissions(); } } catch (SecurityException e) { /* * If the current access control context does not have permission * to access all of the URLs in the codebase path, wrap the * resulting security exception in a ClassNotFoundException, so * the caller can handle this outcome just like any other class * loading failure (see bugid 4146529). */ try { /* * But first, check to see if the proxy class could have been * resolved without the security-offending codebase anyway; * if so, return successfully (see bugids 4191926 & 4349670). */ Class c = loadProxyClass(interfaces, defaultLoader, parent, false); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "(access to codebase denied) " + "proxy class defined by " + c.getClassLoader()); } return c; } catch (ClassNotFoundException unimportant) { /* * Presumably the security exception is the more important * exception to report in this case. */ if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "(access to codebase denied) " + "proxy class resolution failed", e); } throw new ClassNotFoundException( "access to class loader denied", e); } } try { Class c = loadProxyClass(interfaces, defaultLoader, loader, true); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "proxy class defined by " + c.getClassLoader()); } return c; } catch (ClassNotFoundException e) { if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "proxy class resolution failed", e); } throw e; } } /** * Define a proxy class in the default loader if appropriate. * Define the class in an RMI class loader otherwise. The proxy * class will implement classes which are named in the supplied * interfaceNames. */ private static Class loadProxyClass(String[] interfaceNames, ClassLoader defaultLoader, ClassLoader codebaseLoader, boolean preferCodebase) throws ClassNotFoundException { ClassLoader proxyLoader = null; Class[] classObjs = new Class[interfaceNames.length]; boolean[] nonpublic = { false }; defaultLoaderCase: if (defaultLoader != null) { try { proxyLoader = loadProxyInterfaces(interfaceNames, defaultLoader, classObjs, nonpublic); if (loaderLog.isLoggable(Log.VERBOSE)) { ClassLoader[] definingLoaders = new ClassLoader[classObjs.length]; for (int i = 0; i < definingLoaders.length; i++) { definingLoaders[i] = classObjs[i].getClassLoader(); } loaderLog.log(Log.VERBOSE, "proxy interfaces found via defaultLoader, " + "defined by " + Arrays.asList(definingLoaders)); } } catch (ClassNotFoundException e) { break defaultLoaderCase; } if (!nonpublic[0]) { if (preferCodebase) { try { return Proxy.getProxyClass(codebaseLoader, classObjs); } catch (IllegalArgumentException e) { } } proxyLoader = defaultLoader; } return loadProxyClass(proxyLoader, classObjs); } nonpublic[0] = false; proxyLoader = loadProxyInterfaces(interfaceNames, codebaseLoader, classObjs, nonpublic); if (loaderLog.isLoggable(Log.VERBOSE)) { ClassLoader[] definingLoaders = new ClassLoader[classObjs.length]; for (int i = 0; i < definingLoaders.length; i++) { definingLoaders[i] = classObjs[i].getClassLoader(); } loaderLog.log(Log.VERBOSE, "proxy interfaces found via codebase, " + "defined by " + Arrays.asList(definingLoaders)); } if (!nonpublic[0]) { proxyLoader = codebaseLoader; } return loadProxyClass(proxyLoader, classObjs); } /** * Define a proxy class in the given class loader. The proxy * class will implement the given interfaces Classes. */ private static Class loadProxyClass(ClassLoader loader, Class[] interfaces) throws ClassNotFoundException { try { return Proxy.getProxyClass(loader, interfaces); } catch (IllegalArgumentException e) { throw new ClassNotFoundException( "error creating dynamic proxy class", e); } } /* * Load Class objects for the names in the interfaces array fron * the given class loader. * * We pass classObjs and nonpublic arrays to avoid needing a * multi-element return value. nonpublic is an array to enable * the method to take a boolean argument by reference. * * nonpublic array is needed to signal when the return value of * this method should be used as the proxy class loader. Because * null represents a valid class loader, that value is * insufficient to signal that the return value should not be used * as the proxy class loader. */ private static ClassLoader loadProxyInterfaces(String[] interfaces, ClassLoader loader, Class[] classObjs, boolean[] nonpublic) throws ClassNotFoundException { /* loader of a non-public interface class */ ClassLoader nonpublicLoader = null; for (int i = 0; i < interfaces.length; i++) { Class cl = (classObjs[i] = Class.forName(interfaces[i], false, loader)); if (!Modifier.isPublic(cl.getModifiers())) { ClassLoader current = cl.getClassLoader(); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "non-public interface \"" + interfaces[i] + "\" defined by " + current); } if (!nonpublic[0]) { nonpublicLoader = current; nonpublic[0] = true; } else if (current != nonpublicLoader) { throw new IllegalAccessError( "non-public interfaces defined in different " + "class loaders"); } } } return nonpublicLoader; } /** * Convert a string containing a space-separated list of URLs into a * corresponding array of URL objects, throwing a MalformedURLException * if any of the URLs are invalid. */ private static URL[] pathToURLs(String path) throws MalformedURLException { synchronized (pathToURLsCache) { Object[] v = pathToURLsCache.get(path); if (v != null) { return ((URL[])v[0]); } } StringTokenizer st = new StringTokenizer(path); // divide by spaces URL[] urls = new URL[st.countTokens()]; for (int i = 0; st.hasMoreTokens(); i++) { urls[i] = new URL(st.nextToken()); } synchronized (pathToURLsCache) { pathToURLsCache.put(path, new Object[] {urls, new SoftReference<String>(path)}); } return urls; } /** map from weak(key=string) to [URL[], soft(key)] */ private static final Map<String, Object[]> pathToURLsCache = new WeakHashMap<String, Object[]>(5); /** * Convert an array of URL objects into a corresponding string * containing a space-separated list of URLs. * * Note that if the array has zero elements, the return value is * null, not the empty string. */ private static String urlsToPath(URL[] urls) { if (urls.length == 0) { return null; } else if (urls.length == 1) { return urls[0].toExternalForm(); } else { StringBuffer path = new StringBuffer(urls[0].toExternalForm()); for (int i = 1; i < urls.length; i++) { path.append(' '); path.append(urls[i].toExternalForm()); } return path.toString(); } } /** * Return the class loader to be used as the parent for an RMI class * loader used in the current execution context. */ private static ClassLoader getRMIContextClassLoader() { /* * The current implementation simply uses the current thread's * context class loader. */ return Thread.currentThread().getContextClassLoader(); } /** * Look up the RMI class loader for the given codebase URL path * and the given parent class loader. A new class loader instance * will be created and returned if no match is found. */ private static Loader lookupLoader(final URL[] urls, final ClassLoader parent) { /* * If the requested codebase URL path is empty, the supplied * parent class loader will be sufficient. * * REMIND: To be conservative, this optimization is commented out * for now so that it does not open a security hole in the future * by providing untrusted code with direct access to the public * loadClass() method of a class loader instance that it cannot * get a reference to. (It's an unlikely optimization anyway.) * * if (urls.length == 0) { * return parent; * } */ LoaderEntry entry; Loader loader; synchronized (LoaderHandler.class) { /* * Take this opportunity to remove from the table entries * whose weak references have been cleared. */ while ((entry = (LoaderEntry) refQueue.poll()) != null) { if (!entry.removed) { // ignore entries removed below loaderTable.remove(entry.key); } } /* * Look up the codebase URL path and parent class loader pair * in the table of RMI class loaders. */ LoaderKey key = new LoaderKey(urls, parent); entry = loaderTable.get(key); if (entry == null || (loader = entry.get()) == null) { /* * If entry was in table but it's weak reference was cleared, * remove it from the table and mark it as explicitly cleared, * so that new matching entry that we put in the table will * not be erroneously removed when this entry is processed * from the weak reference queue. */ if (entry != null) { loaderTable.remove(key); entry.removed = true; } /* * A matching loader was not found, so create a new class * loader instance for the requested codebase URL path and * parent class loader. The instance is created within an * access control context retricted to the permissions * necessary to load classes from its codebase URL path. */ AccessControlContext acc = getLoaderAccessControlContext(urls); loader = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Loader>() { public Loader run() { return new Loader(urls, parent); } }, acc); /* * Finally, create an entry to hold the new loader with a * weak reference and store it in the table with the key. */ entry = new LoaderEntry(key, loader); loaderTable.put(key, entry); } } return loader; } /** * LoaderKey holds a codebase URL path and parent class loader pair * used to look up RMI class loader instances in its class loader cache. */ private static class LoaderKey { private URL[] urls; private ClassLoader parent; private int hashValue; public LoaderKey(URL[] urls, ClassLoader parent) { this.urls = urls; this.parent = parent; if (parent != null) { hashValue = parent.hashCode(); } for (int i = 0; i < urls.length; i++) { hashValue ^= urls[i].hashCode(); } } public int hashCode() { return hashValue; } public boolean equals(Object obj) { if (obj instanceof LoaderKey) { LoaderKey other = (LoaderKey) obj; if (parent != other.parent) { return false; } if (urls == other.urls) { return true; } if (urls.length != other.urls.length) { return false; } for (int i = 0; i < urls.length; i++) { if (!urls[i].equals(other.urls[i])) { return false; } } return true; } else { return false; } } } /** * LoaderEntry contains a weak reference to an RMIClassLoader. The * weak reference is registered with the private static "refQueue" * queue. The entry contains the codebase URL path and parent class * loader key for the loader so that the mapping can be removed from * the table efficiently when the weak reference is cleared. */ private static class LoaderEntry extends WeakReference<Loader> { public LoaderKey key; /** * set to true if the entry has been removed from the table * because it has been replaced, so it should not be attempted * to be removed again */ public boolean removed = false; public LoaderEntry(LoaderKey key, Loader loader) { super(loader, refQueue); this.key = key; } } /** * Return the access control context that a loader for the given * codebase URL path should execute with. */ private static AccessControlContext getLoaderAccessControlContext( URL[] urls) { /* * The approach used here is taken from the similar method * getAccessControlContext() in the sun.applet.AppletPanel class. */ // begin with permissions granted to all code in current policy PermissionCollection perms = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<PermissionCollection>() { public PermissionCollection run() { CodeSource codesource = new CodeSource(null, (java.security.cert.Certificate[]) null); Policy p = java.security.Policy.getPolicy(); if (p != null) { return p.getPermissions(codesource); } else { return new Permissions(); }Lines 501–1000 of 1201. Previous lines Load more
* define the proxy class in the default loader. * * If the interface classes can not be loaded from the default * loader or the default loader is null, try to load them from * the RMI class loader. Then try to define the proxy class * in the RMI class loader. * * Additionally, if any of the proxy interface classes are not * public, all of the non-public interfaces must reside in the * same class loader or it will be impossible to define the * proxy class (an IllegalAccessError will be thrown). An * attempt to load the interfaces from the default loader is * made. If the attempt fails, a second attempt will be made * to load the interfaces from the RMI loader. If all of the * non-public interfaces classes do reside in the same class * loader, then we attempt to define the proxy class in the * class loader of the non-public interfaces. No other * attempt to define the proxy class will be made. */ ClassLoader parent = getRMIContextClassLoader(); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "(thread context class loader: " + parent + ")"); } URL[] urls; if (codebase != null) { urls = pathToURLs(codebase); } else { urls = getDefaultCodebaseURLs(); } /* * If no security manager is set, disable access to RMI class * loaders and use the would-de parent instead. */ SecurityManager sm = System.getSecurityManager(); if (sm == null) { try { Class c = loadProxyClass(interfaces, defaultLoader, parent, false); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "(no security manager: codebase disabled) " + "proxy class defined by " + c.getClassLoader()); } return c; } catch (ClassNotFoundException e) { if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "(no security manager: codebase disabled) " + "proxy class resolution failed", e); } throw new ClassNotFoundException(e.getMessage() + " (no security manager: RMI class loader disabled)", e.getException()); } } /* * Get or create the RMI class loader for this codebase URL path * and parent class loader pair. */ Loader loader = lookupLoader(urls, parent); try { if (loader != null) { /* * Verify that the caller has permission to access this loader. */ loader.checkPermissions(); } } catch (SecurityException e) { /* * If the current access control context does not have permission * to access all of the URLs in the codebase path, wrap the * resulting security exception in a ClassNotFoundException, so * the caller can handle this outcome just like any other class * loading failure (see bugid 4146529). */ try { /* * But first, check to see if the proxy class could have been * resolved without the security-offending codebase anyway; * if so, return successfully (see bugids 4191926 & 4349670). */ Class c = loadProxyClass(interfaces, defaultLoader, parent, false); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "(access to codebase denied) " + "proxy class defined by " + c.getClassLoader()); } return c; } catch (ClassNotFoundException unimportant) { /* * Presumably the security exception is the more important * exception to report in this case. */ if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "(access to codebase denied) " + "proxy class resolution failed", e); } throw new ClassNotFoundException( "access to class loader denied", e); } } try { Class c = loadProxyClass(interfaces, defaultLoader, loader, true); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "proxy class defined by " + c.getClassLoader()); } return c; } catch (ClassNotFoundException e) { if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "proxy class resolution failed", e); } throw e; } } /** * Define a proxy class in the default loader if appropriate. * Define the class in an RMI class loader otherwise. The proxy * class will implement classes which are named in the supplied * interfaceNames. */ private static Class loadProxyClass(String[] interfaceNames, ClassLoader defaultLoader, ClassLoader codebaseLoader, boolean preferCodebase) throws ClassNotFoundException { ClassLoader proxyLoader = null; Class[] classObjs = new Class[interfaceNames.length]; boolean[] nonpublic = { false }; defaultLoaderCase: if (defaultLoader != null) { try { proxyLoader = loadProxyInterfaces(interfaceNames, defaultLoader, classObjs, nonpublic); if (loaderLog.isLoggable(Log.VERBOSE)) { ClassLoader[] definingLoaders = new ClassLoader[classObjs.length]; for (int i = 0; i < definingLoaders.length; i++) { definingLoaders[i] = classObjs[i].getClassLoader(); } loaderLog.log(Log.VERBOSE, "proxy interfaces found via defaultLoader, " + "defined by " + Arrays.asList(definingLoaders)); } } catch (ClassNotFoundException e) { break defaultLoaderCase; } if (!nonpublic[0]) { if (preferCodebase) { try { return Proxy.getProxyClass(codebaseLoader, classObjs); } catch (IllegalArgumentException e) { } } proxyLoader = defaultLoader; } return loadProxyClass(proxyLoader, classObjs); } nonpublic[0] = false; proxyLoader = loadProxyInterfaces(interfaceNames, codebaseLoader, classObjs, nonpublic); if (loaderLog.isLoggable(Log.VERBOSE)) { ClassLoader[] definingLoaders = new ClassLoader[classObjs.length]; for (int i = 0; i < definingLoaders.length; i++) { definingLoaders[i] = classObjs[i].getClassLoader(); } loaderLog.log(Log.VERBOSE, "proxy interfaces found via codebase, " + "defined by " + Arrays.asList(definingLoaders)); } if (!nonpublic[0]) { proxyLoader = codebaseLoader; } return loadProxyClass(proxyLoader, classObjs); } /** * Define a proxy class in the given class loader. The proxy * class will implement the given interfaces Classes. */ private static Class loadProxyClass(ClassLoader loader, Class[] interfaces) throws ClassNotFoundException { try { return Proxy.getProxyClass(loader, interfaces); } catch (IllegalArgumentException e) { throw new ClassNotFoundException( "error creating dynamic proxy class", e); } } /* * Load Class objects for the names in the interfaces array fron * the given class loader. * * We pass classObjs and nonpublic arrays to avoid needing a * multi-element return value. nonpublic is an array to enable * the method to take a boolean argument by reference. * * nonpublic array is needed to signal when the return value of * this method should be used as the proxy class loader. Because * null represents a valid class loader, that value is * insufficient to signal that the return value should not be used * as the proxy class loader. */ private static ClassLoader loadProxyInterfaces(String[] interfaces, ClassLoader loader, Class[] classObjs, boolean[] nonpublic) throws ClassNotFoundException { /* loader of a non-public interface class */ ClassLoader nonpublicLoader = null; for (int i = 0; i < interfaces.length; i++) { Class cl = (classObjs[i] = Class.forName(interfaces[i], false, loader)); if (!Modifier.isPublic(cl.getModifiers())) { ClassLoader current = cl.getClassLoader(); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "non-public interface \"" + interfaces[i] + "\" defined by " + current); } if (!nonpublic[0]) { nonpublicLoader = current; nonpublic[0] = true; } else if (current != nonpublicLoader) { throw new IllegalAccessError( "non-public interfaces defined in different " + "class loaders"); } } } return nonpublicLoader; } /** * Convert a string containing a space-separated list of URLs into a * corresponding array of URL objects, throwing a MalformedURLException * if any of the URLs are invalid. */ private static URL[] pathToURLs(String path) throws MalformedURLException { synchronized (pathToURLsCache) { Object[] v = pathToURLsCache.get(path); if (v != null) { return ((URL[])v[0]); } } StringTokenizer st = new StringTokenizer(path); // divide by spaces URL[] urls = new URL[st.countTokens()]; for (int i = 0; st.hasMoreTokens(); i++) { urls[i] = new URL(st.nextToken()); } synchronized (pathToURLsCache) { pathToURLsCache.put(path, new Object[] {urls, new SoftReference<String>(path)}); } return urls; } /** map from weak(key=string) to [URL[], soft(key)] */ private static final Map<String, Object[]> pathToURLsCache = new WeakHashMap<String, Object[]>(5); /** * Convert an array of URL objects into a corresponding string * containing a space-separated list of URLs. * * Note that if the array has zero elements, the return value is * null, not the empty string. */ private static String urlsToPath(URL[] urls) { if (urls.length == 0) { return null; } else if (urls.length == 1) { return urls[0].toExternalForm(); } else { StringBuffer path = new StringBuffer(urls[0].toExternalForm()); for (int i = 1; i < urls.length; i++) { path.append(' '); path.append(urls[i].toExternalForm()); } return path.toString(); } } /** * Return the class loader to be used as the parent for an RMI class * loader used in the current execution context. */ private static ClassLoader getRMIContextClassLoader() { /* * The current implementation simply uses the current thread's * context class loader. */ return Thread.currentThread().getContextClassLoader(); } /** * Look up the RMI class loader for the given codebase URL path * and the given parent class loader. A new class loader instance * will be created and returned if no match is found. */ private static Loader lookupLoader(final URL[] urls, final ClassLoader parent) { /* * If the requested codebase URL path is empty, the supplied * parent class loader will be sufficient. * * REMIND: To be conservative, this optimization is commented out * for now so that it does not open a security hole in the future * by providing untrusted code with direct access to the public * loadClass() method of a class loader instance that it cannot * get a reference to. (It's an unlikely optimization anyway.) * * if (urls.length == 0) { * return parent; * } */ LoaderEntry entry; Loader loader; synchronized (LoaderHandler.class) { /* * Take this opportunity to remove from the table entries * whose weak references have been cleared. */ while ((entry = (LoaderEntry) refQueue.poll()) != null) { if (!entry.removed) { // ignore entries removed below loaderTable.remove(entry.key); } } /* * Look up the codebase URL path and parent class loader pair * in the table of RMI class loaders. */ LoaderKey key = new LoaderKey(urls, parent); entry = loaderTable.get(key); if (entry == null || (loader = entry.get()) == null) { /* * If entry was in table but it's weak reference was cleared, * remove it from the table and mark it as explicitly cleared, * so that new matching entry that we put in the table will * not be erroneously removed when this entry is processed * from the weak reference queue. */ if (entry != null) { loaderTable.remove(key); entry.removed = true; } /* * A matching loader was not found, so create a new class * loader instance for the requested codebase URL path and * parent class loader. The instance is created within an * access control context retricted to the permissions * necessary to load classes from its codebase URL path. */ AccessControlContext acc = getLoaderAccessControlContext(urls); loader = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Loader>() { public Loader run() { return new Loader(urls, parent); } }, acc); /* * Finally, create an entry to hold the new loader with a * weak reference and store it in the table with the key. */ entry = new LoaderEntry(key, loader); loaderTable.put(key, entry); } } return loader; } /** * LoaderKey holds a codebase URL path and parent class loader pair * used to look up RMI class loader instances in its class loader cache. */ private static class LoaderKey { private URL[] urls; private ClassLoader parent; private int hashValue; public LoaderKey(URL[] urls, ClassLoader parent) { this.urls = urls; this.parent = parent; if (parent != null) { hashValue = parent.hashCode(); } for (int i = 0; i < urls.length; i++) { hashValue ^= urls[i].hashCode(); } } public int hashCode() { return hashValue; } public boolean equals(Object obj) { if (obj instanceof LoaderKey) { LoaderKey other = (LoaderKey) obj; if (parent != other.parent) { return false; } if (urls == other.urls) { return true; } if (urls.length != other.urls.length) { return false; } for (int i = 0; i < urls.length; i++) { if (!urls[i].equals(other.urls[i])) { return false; } } return true; } else { return false; } } } /** * LoaderEntry contains a weak reference to an RMIClassLoader. The * weak reference is registered with the private static "refQueue" * queue. The entry contains the codebase URL path and parent class * loader key for the loader so that the mapping can be removed from * the table efficiently when the weak reference is cleared. */ private static class LoaderEntry extends WeakReference<Loader> { public LoaderKey key; /** * set to true if the entry has been removed from the table * because it has been replaced, so it should not be attempted * to be removed again */ public boolean removed = false; public LoaderEntry(LoaderKey key, Loader loader) { super(loader, refQueue); this.key = key; } } /** * Return the access control context that a loader for the given * codebase URL path should execute with. */ private static AccessControlContext getLoaderAccessControlContext( URL[] urls) { /* * The approach used here is taken from the similar method * getAccessControlContext() in the sun.applet.AppletPanel class. */ // begin with permissions granted to all code in current policy PermissionCollection perms = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<PermissionCollection>() { public PermissionCollection run() { CodeSource codesource = new CodeSource(null, (java.security.cert.Certificate[]) null); Policy p = java.security.Policy.getPolicy(); if (p != null) { return p.getPermissions(codesource); } else { return new Permissions(); }