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
* 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 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. |