/* * Copyright (c) 1996, 2008, 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 * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.rmi.server; import java.io.File;import java.io.FilePermission;import java.io.IOException;import java.lang.ref.ReferenceQueue;import java.lang.ref.SoftReference;import java.lang.ref.WeakReference;import java.lang.reflect.Modifier;import java.lang.reflect.Proxy;import java.net.JarURLConnection;import java.net.MalformedURLException;import java.net.SocketPermission;import java.net.URL;import java.net.URLClassLoader;import java.net.URLConnection;import java.security.AccessControlContext;import java.security.CodeSource;import java.security.Permission;import java.security.Permissions;import java.security.PermissionCollection;import java.security.Policy;import java.security.ProtectionDomain;import java.rmi.server.LogStream;import java.util.Arrays;import java.util.Collections;import java.util.Enumeration;import java.util.HashMap;import java.util.IdentityHashMap;import java.util.Map;import java.util.StringTokenizer;import java.util.WeakHashMap;import sun.rmi.runtime.Log;import sun.security.action.GetPropertyAction; /** * <code>LoaderHandler</code> provides the implementation of the static * methods of the <code>java.rmi.server.RMIClassLoader</code> class. * * @author Ann Wollrath * @author Peter Jones * @author Laird Dornin */public final class LoaderHandler { /** RMI class loader log level */ static final int logLevel = LogStream.parseLevel( java.security.AccessController.doPrivileged( new GetPropertyAction("sun.rmi.loader.logLevel"))); /* loader system log */ static final Log loaderLog = Log.getLog("sun.rmi.loader", "loader", LoaderHandler.logLevel); /** * value of "java.rmi.server.codebase" property, as cached at class * initialization time. It may contain malformed URLs. */ private static String codebaseProperty = null; static { String prop = java.security.AccessController.doPrivileged( new GetPropertyAction("java.rmi.server.codebase")); if (prop != null && prop.trim().length() > 0) { codebaseProperty = prop; } } /** list of URLs represented by the codebase property, if valid */ private static URL[] codebaseURLs = null; /** table of class loaders that use codebase property for annotation */ private static final Map<ClassLoader, Void> codebaseLoaders = Collections.synchronizedMap(new IdentityHashMap<ClassLoader, Void>(5)); static { for (ClassLoader codebaseLoader = ClassLoader.getSystemClassLoader(); codebaseLoader != null; codebaseLoader = codebaseLoader.getParent()) { codebaseLoaders.put(codebaseLoader, null); } } /** * table mapping codebase URL path and context class loader pairs * to class loader instances. Entries hold class loaders with weak * references, so this table does not prevent loaders from being * garbage collected. */ private static final HashMap<LoaderKey, LoaderEntry> loaderTable = new HashMap<LoaderKey, LoaderEntry>(5); /** reference queue for cleared class loader entries */ private static final ReferenceQueue<Loader> refQueue = new ReferenceQueue<Loader>(); /* * Disallow anyone from creating one of these. */ private LoaderHandler() {} /** * Returns an array of URLs initialized with the value of the * java.rmi.server.codebase property as the URL path. */ private static synchronized URL[] getDefaultCodebaseURLs() throws MalformedURLException { /* * If it hasn't already been done, convert the codebase property * into an array of URLs; this may throw a MalformedURLException. */ if (codebaseURLs == null) { if (codebaseProperty != null) { codebaseURLs = pathToURLs(codebaseProperty); } else { codebaseURLs = new URL[0]; } } return codebaseURLs; } /** * Load a class from a network location (one or more URLs), * but first try to resolve the named class through the given * "default loader". */ public static Class loadClass(String codebase, String name, ClassLoader defaultLoader) throws MalformedURLException, ClassNotFoundException { if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "name = \"" + name + "\", " + "codebase = \"" + (codebase != null ? codebase : "") + "\"" + (defaultLoader != null ? ", defaultLoader = " + defaultLoader : "")); } URL[] urls; if (codebase != null) { urls = pathToURLs(codebase); } else { urls = getDefaultCodebaseURLs(); } if (defaultLoader != null) { try { Class c = Class.forName(name, false, defaultLoader); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "class \"" + name + "\" found via defaultLoader, " + "defined by " + c.getClassLoader()); } return c; } catch (ClassNotFoundException e) { } } return loadClass(urls, name); } /** * Returns the class annotation (representing the location for * a class) that RMI will use to annotate the call stream when * marshalling objects of the given class. */ public static String getClassAnnotation(Class cl) { String name = cl.getName(); /* * Class objects for arrays of primitive types never need an * annotation, because they never need to be (or can be) downloaded. * * REMIND: should we (not) be annotating classes that are in * "java.*" packages? */ int nameLength = name.length(); if (nameLength > 0 && name.charAt(0) == '[') { // skip past all '[' characters (see bugid 4211906) int i = 1; while (nameLength > i && name.charAt(i) == '[') { i++; } if (nameLength > i && name.charAt(i) != 'L') { return null; } } /* * Get the class's class loader. If it is null, the system class * loader, an ancestor of the base class loader (such as the loader * for installed extensions), return the value of the * "java.rmi.server.codebase" property. */ ClassLoader loader = cl.getClassLoader(); if (loader == null || codebaseLoaders.containsKey(loader)) { return codebaseProperty; } /* * Get the codebase URL path for the class loader, if it supports * such a notion (i.e., if it is a URLClassLoader or subclass). */ String annotation = null; if (loader instanceof Loader) { /* * If the class loader is one of our RMI class loaders, we have * already computed the class annotation string, and no * permissions are required to know the URLs. */ annotation = ((Loader) loader).getClassAnnotation(); } else if (loader instanceof URLClassLoader) { try { URL[] urls = ((URLClassLoader) loader).getURLs(); if (urls != null) { /* * If the class loader is not one of our RMI class loaders, * we must verify that the current access control context * has permission to know all of these URLs. */ SecurityManager sm = System.getSecurityManager(); if (sm != null) { Permissions perms = new Permissions(); for (int i = 0; i < urls.length; i++) { Permission p = urls[i].openConnection().getPermission(); if (p != null) { if (!perms.implies(p)) { sm.checkPermission(p); perms.add(p); } } } } annotation = urlsToPath(urls); } } catch (SecurityException e) { /* * If access was denied to the knowledge of the class * loader's URLs, fall back to the default behavior. */ } catch (IOException e) { /* * This shouldn't happen, although it is declared to be * thrown by openConnection() and getPermission(). If it * does happen, forget about this class loader's URLs and * fall back to the default behavior. */ } } if (annotation != null) { return annotation; } else { return codebaseProperty; // REMIND: does this make sense?? } } /** * Returns a classloader that loads classes from the given codebase URL * path. The parent classloader of the returned classloader is the * context class loader. */ public static ClassLoader getClassLoader(String codebase) throws MalformedURLException { ClassLoader parent = getRMIContextClassLoader(); URL[] urls; if (codebase != null) { urls = pathToURLs(codebase); } else { urls = getDefaultCodebaseURLs(); } /* * If there is a security manager, the current access control * context must have the "getClassLoader" RuntimePermission. */ SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("getClassLoader")); } else { /* * But if no security manager is set, disable access to * RMI class loaders and simply return the parent loader. */ return parent; } Loader loader = lookupLoader(urls, parent); /* * Verify that the caller has permission to access this loader. */ if (loader != null) { loader.checkPermissions(); } return loader; } /** * Return the security context of the given class loader. */ public static Object getSecurityContext(ClassLoader loader) { /* * REMIND: This is a bogus JDK1.1-compatible implementation. * This method should never be called by application code anyway * (hence the deprecation), but should it do something different * and perhaps more useful, like return a String or a URL[]? */ if (loader instanceof Loader) { URL[] urls = ((Loader) loader).getURLs(); if (urls.length > 0) { return urls[0]; } } return null; } /** * Register a class loader as one whose classes should always be * annotated with the value of the "java.rmi.server.codebase" property. */ public static void registerCodebaseLoader(ClassLoader loader) { codebaseLoaders.put(loader, null); } /** * Load a class from the RMI class loader corresponding to the given * codebase URL path in the current execution context. */ private static Class loadClass(URL[] urls, String name) throws ClassNotFoundException { ClassLoader parent = getRMIContextClassLoader(); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "(thread context class loader: " + parent + ")"); } /* * If no security manager is set, disable access to RMI class * loaders and simply delegate request to the parent loader * (see bugid 4140511). */ SecurityManager sm = System.getSecurityManager(); if (sm == null) { try { Class c = Class.forName(name, false, parent); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "class \"" + name + "\" found via " + "thread context class loader " + "(no security manager: codebase disabled), " + "defined by " + c.getClassLoader()); } return c; } catch (ClassNotFoundException e) { if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "class \"" + name + "\" not found via " + "thread context class loader " + "(no security manager: codebase disabled)", 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 named class could have been * resolved without the security-offending codebase anyway; * if so, return successfully (see bugids 4191926 & 4349670). */ Class c = Class.forName(name, false, parent); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "class \"" + name + "\" found via " + "thread context class loader " + "(access to codebase denied), " + "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, "class \"" + name + "\" not found via " + "thread context class loader " + "(access to codebase denied)", e); } throw new ClassNotFoundException( "access to class loader denied", e); } } try { Class c = Class.forName(name, false, loader); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "class \"" + name + "\" " + "found via codebase, " + "defined by " + c.getClassLoader()); } return c; } catch (ClassNotFoundException e) { if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "class \"" + name + "\" not found via codebase", e); } throw e; } } /** * Define and return a dynamic proxy class in a class loader with * URLs supplied in the given location. The proxy class will * implement interface classes named by the given array of * interface names. */ public static Class loadProxyClass(String codebase, String[] interfaces, ClassLoader defaultLoader) throws MalformedURLException, ClassNotFoundException { if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "interfaces = " + Arrays.asList(interfaces) + ", " + "codebase = \"" + (codebase != null ? codebase : "") + "\"" + (defaultLoader != null ? ", defaultLoader = " + defaultLoader : "")); } /* * This method uses a fairly complex algorithm to load the * proxy class and its interface classes in order to maximize * the likelihood that the proxy's codebase annotation will be * preserved. The algorithm is (assuming that all of the * proxy interface classes are public): * * If the default loader is not null, try to load the proxy * interfaces through that loader. If the interfaces can be * loaded in that loader, try to define the proxy class in an * RMI class loader (child of the context class loader) before * trying to define the proxy in the default loader. If the * attempt to define the proxy class succeeds, the codebase * annotation is preserved. If the attempt fails, try toLines 1–500 of 1201. Load more
/* * Copyright (c) 1996, 2008, 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 * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.rmi.server; import java.io.File; import java.io.FilePermission; import java.io.IOException; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; import java.net.JarURLConnection; import java.net.MalformedURLException; import java.net.SocketPermission; import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; import java.security.AccessControlContext; import java.security.CodeSource; import java.security.Permission; import java.security.Permissions; import java.security.PermissionCollection; import java.security.Policy; import java.security.ProtectionDomain; import java.rmi.server.LogStream; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Map; import java.util.StringTokenizer; import java.util.WeakHashMap; import sun.rmi.runtime.Log; import sun.security.action.GetPropertyAction; /** * <code>LoaderHandler</code> provides the implementation of the static * methods of the <code>java.rmi.server.RMIClassLoader</code> class. * * @author Ann Wollrath * @author Peter Jones * @author Laird Dornin */ public final class LoaderHandler { /** RMI class loader log level */ static final int logLevel = LogStream.parseLevel( java.security.AccessController.doPrivileged( new GetPropertyAction("sun.rmi.loader.logLevel"))); /* loader system log */ static final Log loaderLog = Log.getLog("sun.rmi.loader", "loader", LoaderHandler.logLevel); /** * value of "java.rmi.server.codebase" property, as cached at class * initialization time. It may contain malformed URLs. */ private static String codebaseProperty = null; static { String prop = java.security.AccessController.doPrivileged( new GetPropertyAction("java.rmi.server.codebase")); if (prop != null && prop.trim().length() > 0) { codebaseProperty = prop; } } /** list of URLs represented by the codebase property, if valid */ private static URL[] codebaseURLs = null; /** table of class loaders that use codebase property for annotation */ private static final Map<ClassLoader, Void> codebaseLoaders = Collections.synchronizedMap(new IdentityHashMap<ClassLoader, Void>(5)); static { for (ClassLoader codebaseLoader = ClassLoader.getSystemClassLoader(); codebaseLoader != null; codebaseLoader = codebaseLoader.getParent()) { codebaseLoaders.put(codebaseLoader, null); } } /** * table mapping codebase URL path and context class loader pairs * to class loader instances. Entries hold class loaders with weak * references, so this table does not prevent loaders from being * garbage collected. */ private static final HashMap<LoaderKey, LoaderEntry> loaderTable = new HashMap<LoaderKey, LoaderEntry>(5); /** reference queue for cleared class loader entries */ private static final ReferenceQueue<Loader> refQueue = new ReferenceQueue<Loader>(); /* * Disallow anyone from creating one of these. */ private LoaderHandler() {} /** * Returns an array of URLs initialized with the value of the * java.rmi.server.codebase property as the URL path. */ private static synchronized URL[] getDefaultCodebaseURLs() throws MalformedURLException { /* * If it hasn't already been done, convert the codebase property * into an array of URLs; this may throw a MalformedURLException. */ if (codebaseURLs == null) { if (codebaseProperty != null) { codebaseURLs = pathToURLs(codebaseProperty); } else { codebaseURLs = new URL[0]; } } return codebaseURLs; } /** * Load a class from a network location (one or more URLs), * but first try to resolve the named class through the given * "default loader". */ public static Class loadClass(String codebase, String name, ClassLoader defaultLoader) throws MalformedURLException, ClassNotFoundException { if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "name = \"" + name + "\", " + "codebase = \"" + (codebase != null ? codebase : "") + "\"" + (defaultLoader != null ? ", defaultLoader = " + defaultLoader : "")); } URL[] urls; if (codebase != null) { urls = pathToURLs(codebase); } else { urls = getDefaultCodebaseURLs(); } if (defaultLoader != null) { try { Class c = Class.forName(name, false, defaultLoader); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "class \"" + name + "\" found via defaultLoader, " + "defined by " + c.getClassLoader()); } return c; } catch (ClassNotFoundException e) { } } return loadClass(urls, name); } /** * Returns the class annotation (representing the location for * a class) that RMI will use to annotate the call stream when * marshalling objects of the given class. */ public static String getClassAnnotation(Class cl) { String name = cl.getName(); /* * Class objects for arrays of primitive types never need an * annotation, because they never need to be (or can be) downloaded. * * REMIND: should we (not) be annotating classes that are in * "java.*" packages? */ int nameLength = name.length(); if (nameLength > 0 && name.charAt(0) == '[') { // skip past all '[' characters (see bugid 4211906) int i = 1; while (nameLength > i && name.charAt(i) == '[') { i++; } if (nameLength > i && name.charAt(i) != 'L') { return null; } } /* * Get the class's class loader. If it is null, the system class * loader, an ancestor of the base class loader (such as the loader * for installed extensions), return the value of the * "java.rmi.server.codebase" property. */ ClassLoader loader = cl.getClassLoader(); if (loader == null || codebaseLoaders.containsKey(loader)) { return codebaseProperty; } /* * Get the codebase URL path for the class loader, if it supports * such a notion (i.e., if it is a URLClassLoader or subclass). */ String annotation = null; if (loader instanceof Loader) { /* * If the class loader is one of our RMI class loaders, we have * already computed the class annotation string, and no * permissions are required to know the URLs. */ annotation = ((Loader) loader).getClassAnnotation(); } else if (loader instanceof URLClassLoader) { try { URL[] urls = ((URLClassLoader) loader).getURLs(); if (urls != null) { /* * If the class loader is not one of our RMI class loaders, * we must verify that the current access control context * has permission to know all of these URLs. */ SecurityManager sm = System.getSecurityManager(); if (sm != null) { Permissions perms = new Permissions(); for (int i = 0; i < urls.length; i++) { Permission p = urls[i].openConnection().getPermission(); if (p != null) { if (!perms.implies(p)) { sm.checkPermission(p); perms.add(p); } } } } annotation = urlsToPath(urls); } } catch (SecurityException e) { /* * If access was denied to the knowledge of the class * loader's URLs, fall back to the default behavior. */ } catch (IOException e) { /* * This shouldn't happen, although it is declared to be * thrown by openConnection() and getPermission(). If it * does happen, forget about this class loader's URLs and * fall back to the default behavior. */ } } if (annotation != null) { return annotation; } else { return codebaseProperty; // REMIND: does this make sense?? } } /** * Returns a classloader that loads classes from the given codebase URL * path. The parent classloader of the returned classloader is the * context class loader. */ public static ClassLoader getClassLoader(String codebase) throws MalformedURLException { ClassLoader parent = getRMIContextClassLoader(); URL[] urls; if (codebase != null) { urls = pathToURLs(codebase); } else { urls = getDefaultCodebaseURLs(); } /* * If there is a security manager, the current access control * context must have the "getClassLoader" RuntimePermission. */ SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("getClassLoader")); } else { /* * But if no security manager is set, disable access to * RMI class loaders and simply return the parent loader. */ return parent; } Loader loader = lookupLoader(urls, parent); /* * Verify that the caller has permission to access this loader. */ if (loader != null) { loader.checkPermissions(); } return loader; } /** * Return the security context of the given class loader. */ public static Object getSecurityContext(ClassLoader loader) { /* * REMIND: This is a bogus JDK1.1-compatible implementation. * This method should never be called by application code anyway * (hence the deprecation), but should it do something different * and perhaps more useful, like return a String or a URL[]? */ if (loader instanceof Loader) { URL[] urls = ((Loader) loader).getURLs(); if (urls.length > 0) { return urls[0]; } } return null; } /** * Register a class loader as one whose classes should always be * annotated with the value of the "java.rmi.server.codebase" property. */ public static void registerCodebaseLoader(ClassLoader loader) { codebaseLoaders.put(loader, null); } /** * Load a class from the RMI class loader corresponding to the given * codebase URL path in the current execution context. */ private static Class loadClass(URL[] urls, String name) throws ClassNotFoundException { ClassLoader parent = getRMIContextClassLoader(); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "(thread context class loader: " + parent + ")"); } /* * If no security manager is set, disable access to RMI class * loaders and simply delegate request to the parent loader * (see bugid 4140511). */ SecurityManager sm = System.getSecurityManager(); if (sm == null) { try { Class c = Class.forName(name, false, parent); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "class \"" + name + "\" found via " + "thread context class loader " + "(no security manager: codebase disabled), " + "defined by " + c.getClassLoader()); } return c; } catch (ClassNotFoundException e) { if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "class \"" + name + "\" not found via " + "thread context class loader " + "(no security manager: codebase disabled)", 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 named class could have been * resolved without the security-offending codebase anyway; * if so, return successfully (see bugids 4191926 & 4349670). */ Class c = Class.forName(name, false, parent); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "class \"" + name + "\" found via " + "thread context class loader " + "(access to codebase denied), " + "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, "class \"" + name + "\" not found via " + "thread context class loader " + "(access to codebase denied)", e); } throw new ClassNotFoundException( "access to class loader denied", e); } } try { Class c = Class.forName(name, false, loader); if (loaderLog.isLoggable(Log.VERBOSE)) { loaderLog.log(Log.VERBOSE, "class \"" + name + "\" " + "found via codebase, " + "defined by " + c.getClassLoader()); } return c; } catch (ClassNotFoundException e) { if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "class \"" + name + "\" not found via codebase", e); } throw e; } } /** * Define and return a dynamic proxy class in a class loader with * URLs supplied in the given location. The proxy class will * implement interface classes named by the given array of * interface names. */ public static Class loadProxyClass(String codebase, String[] interfaces, ClassLoader defaultLoader) throws MalformedURLException, ClassNotFoundException { if (loaderLog.isLoggable(Log.BRIEF)) { loaderLog.log(Log.BRIEF, "interfaces = " + Arrays.asList(interfaces) + ", " + "codebase = \"" + (codebase != null ? codebase : "") + "\"" + (defaultLoader != null ? ", defaultLoader = " + defaultLoader : "")); } /* * This method uses a fairly complex algorithm to load the * proxy class and its interface classes in order to maximize * the likelihood that the proxy's codebase annotation will be * preserved. The algorithm is (assuming that all of the * proxy interface classes are public): * * If the default loader is not null, try to load the proxy * interfaces through that loader. If the interfaces can be * loaded in that loader, try to define the proxy class in an * RMI class loader (child of the context class loader) before * trying to define the proxy in the default loader. If the * attempt to define the proxy class succeeds, the codebase * annotation is preserved. If the attempt fails, try to