RMIClassLoaderpublic class RMIClassLoader extends Object RMIClassLoader comprises static methods to support
dynamic class loading with RMI. Included are methods for loading
classes from a network location (one or more URLs) and obtaining
the location from which an existing class should be loaded by
remote parties. These methods are used by the RMI runtime when
marshalling and unmarshalling classes contained in the arguments
and return values of remote method calls, and they also may be
invoked directly by applications in order to mimic RMI's dynamic
class loading behavior.
The implementation of the following static methods
- {@link #loadClass(URL,String)}
- {@link #loadClass(String,String)}
- {@link #loadClass(String,String,ClassLoader)}
- {@link #loadProxyClass(String,String[],ClassLoader)}
- {@link #getClassLoader(String)}
- {@link #getClassAnnotation(Class)}
is provided by an instance of {@link RMIClassLoaderSpi}, the
service provider interface for those methods. When one of the
methods is invoked, its behavior is to delegate to a corresponding
method on the service provider instance. The details of how each
method delegates to the provider instance is described in the
documentation for each particular method.
The service provider instance is chosen as follows:
- If the system property
java.rmi.server.RMIClassLoaderSpi is defined, then if
its value equals the string "default" , the provider
instance will be the value returned by an invocation of the {@link
#getDefaultProviderInstance()} method, and for any other value, if
a class named with the value of the property can be loaded by the
system class loader (see {@link ClassLoader#getSystemClassLoader})
and that class is assignable to {@link RMIClassLoaderSpi} and has a
public no-argument constructor, then that constructor will be
invoked to create the provider instance. If the property is
defined but any other of those conditions are not true, then an
unspecified Error will be thrown to code that attempts
to use RMIClassLoader , indicating the failure to
obtain a provider instance.
- If a resource named
META-INF/services/java.rmi.server.RMIClassLoaderSpi is
visible to the system class loader, then the contents of that
resource are interpreted as a provider-configuration file, and the
first class name specified in that file is used as the provider
class name. If a class with that name can be loaded by the system
class loader and that class is assignable to {@link
RMIClassLoaderSpi} and has a public no-argument constructor, then
that constructor will be invoked to create the provider instance.
If the resource is found but a provider cannot be instantiated as
described, then an unspecified Error will be thrown to
code that attempts to use RMIClassLoader , indicating
the failure to obtain a provider instance.
- Otherwise, the provider instance will be the value returned by
an invocation of the {@link #getDefaultProviderInstance()} method.
|
Fields Summary |
---|
private static final RMIClassLoaderSpi | defaultProvider"default" provider instance | private static final RMIClassLoaderSpi | providerprovider instance |
Constructors Summary |
---|
private RMIClassLoader()
/*
* Disallow anyone from creating one of these.
*/
|
Methods Summary |
---|
public static java.lang.String | getClassAnnotation(java.lang.Class cl)Returns the annotation string (representing a location for
the class definition) that RMI will use to annotate the class
descriptor when marshalling objects of the given class.
This method delegates to the
{@link RMIClassLoaderSpi#getClassAnnotation(Class)} method
of the provider instance, passing cl as the argument.
return provider.getClassAnnotation(cl);
| public static java.lang.ClassLoader | getClassLoader(java.lang.String codebase)Returns a class loader that loads classes from the given codebase
URL path.
The class loader returned is the class loader that the
{@link #loadClass(String,String)} method would use to load classes
for the same codebase argument.
This method delegates to the
{@link RMIClassLoaderSpi#getClassLoader(String)} method
of the provider instance, passing codebase as the argument.
If there is a security manger, its checkPermission
method will be invoked with a
RuntimePermission("getClassLoader") permission;
this could result in a SecurityException .
The provider implementation of this method may also perform further
security checks to verify that the calling context has permission to
connect to all of the URLs in the codebase URL path.
return provider.getClassLoader(codebase);
| public static java.rmi.server.RMIClassLoaderSpi | getDefaultProviderInstance()Returns the canonical instance of the default provider
for the service provider interface {@link RMIClassLoaderSpi}.
If the system property java.rmi.server.RMIClassLoaderSpi
is not defined, then the RMIClassLoader static
methods
- {@link #loadClass(URL,String)}
- {@link #loadClass(String,String)}
- {@link #loadClass(String,String,ClassLoader)}
- {@link #loadProxyClass(String,String[],ClassLoader)}
- {@link #getClassLoader(String)}
- {@link #getClassAnnotation(Class)}
will use the canonical instance of the default provider
as the service provider instance.
If there is a security manager, its
checkPermission method will be invoked with a
RuntimePermission("setFactory") permission; this
could result in a SecurityException .
The default service provider instance implements
{@link RMIClassLoaderSpi} as follows:
The {@link RMIClassLoaderSpi#getClassAnnotation(Class)
getClassAnnotation} method returns a String
representing the codebase URL path that a remote party should
use to download the definition for the specified class. The
format of the returned string is a path of URLs separated by
spaces.
The codebase string returned depends on the defining class
loader of the specified class:
- If the class loader is the system class loader (see
{@link ClassLoader#getSystemClassLoader}), a parent of the
system class loader such as the loader used for installed
extensions, or the bootstrap class loader (which may be
represented by
null ), then the value of the
java.rmi.server.codebase property (or possibly an
earlier cached value) is returned, or
null is returned if that property is not set.
- Otherwise, if the class loader is an instance of
URLClassLoader , then the returned string is a
space-separated list of the external forms of the URLs returned
by invoking the getURLs methods of the loader. If
the URLClassLoader was created by this provider to
service an invocation of its loadClass or
loadProxyClass methods, then no permissions are
required to get the associated codebase string. If it is an
arbitrary other URLClassLoader instance, then if
there is a security manager, its checkPermission
method will be invoked once for each URL returned by the
getURLs method, with the permission returned by
invoking openConnection().getPermission() on each
URL; if any of those invocations throws a
SecurityException or an IOException ,
then the value of the java.rmi.server.codebase
property (or possibly an earlier cached value) is returned, or
null is returned if that property is not set.
- Finally, if the class loader is not an instance of
URLClassLoader , then the value of the
java.rmi.server.codebase property (or possibly an
earlier cached value) is returned, or
null is returned if that property is not set.
For the implementations of the methods described below,
which all take a String parameter named
codebase that is a space-separated list of URLs,
each invocation has an associated codebase loader that
is identified using the codebase argument in
conjunction with the current thread's context class loader (see
{@link Thread#getContextClassLoader()}). When there is a
security manager, this provider maintains an internal table of
class loader instances (which are at least instances of {@link
java.net.URLClassLoader}) keyed by the pair of their parent
class loader and their codebase URL path (an ordered list of
URLs). If the codebase argument is null ,
the codebase URL path is the value of the system property
java.rmi.server.codebase or possibly an
earlier cached value. For a given codebase URL path passed as the
codebase argument to an invocation of one of the
below methods in a given context, the codebase loader is the
loader in the table with the specified codebase URL path and
the current thread's context class loader as its parent. If no
such loader exists, then one is created and added to the table.
The table does not maintain strong references to its contained
loaders, in order to allow them and their defined classes to be
garbage collected when not otherwise reachable. In order to
prevent arbitrary untrusted code from being implicitly loaded
into a virtual machine with no security manager, if there is no
security manager set, the codebase loader is just the current
thread's context class loader (the supplied codebase URL path
is ignored, so remote class loading is disabled).
The {@link RMIClassLoaderSpi#getClassLoader(String)
getClassLoader} method returns the codebase loader for the
specified codebase URL path. If there is a security manager,
then if the calling context does not have permission to connect
to all of the URLs in the codebase URL path, a
SecurityException will be thrown.
The {@link
RMIClassLoaderSpi#loadClass(String,String,ClassLoader)
loadClass} method attempts to load the class with the
specified name as follows:
If the defaultLoader argument is
non-null , it first attempts to load the class with the
specified name using the
defaultLoader , such as by evaluating
Class.forName(name, false, defaultLoader)
If the class is successfully loaded from the
defaultLoader , that class is returned. If an
exception other than ClassNotFoundException is
thrown, that exception is thrown to the caller.
Next, the loadClass method attempts to load the
class with the specified name using the codebase
loader for the specified codebase URL path.
If there is a security manager, then the calling context
must have permission to connect to all of the URLs in the
codebase URL path; otherwise, the current thread's context
class loader will be used instead of the codebase loader.
The {@link
RMIClassLoaderSpi#loadProxyClass(String,String[],ClassLoader)
loadProxyClass} method attempts to return a dynamic proxy
class with the named interface as follows:
If the defaultLoader argument is
non-null and all of the named interfaces can be
resolved through that loader, then,
- if all of the resolved interfaces are
public ,
then it first attempts to obtain a dynamic proxy class (using
{@link
java.lang.reflect.Proxy#getProxyClass(ClassLoader,Class[])
Proxy.getProxyClass}) for the resolved interfaces defined in
the codebase loader; if that attempt throws an
IllegalArgumentException , it then attempts to
obtain a dynamic proxy class for the resolved interfaces
defined in the defaultLoader . If both attempts
throw IllegalArgumentException , then this method
throws a ClassNotFoundException . If any other
exception is thrown, that exception is thrown to the caller.
- if all of the non-
public resolved interfaces
are defined in the same class loader, then it attempts to
obtain a dynamic proxy class for the resolved interfaces
defined in that loader.
- otherwise, a
LinkageError is thrown (because a
class that implements all of the specified interfaces cannot be
defined in any loader).
Otherwise, if all of the named interfaces can be resolved
through the codebase loader, then,
- if all of the resolved interfaces are
public ,
then it attempts to obtain a dynamic proxy class for the
resolved interfaces in the codebase loader. If the attempt
throws an IllegalArgumentException , then this
method throws a ClassNotFoundException .
- if all of the non-
public resolved interfaces
are defined in the same class loader, then it attempts to
obtain a dynamic proxy class for the resolved interfaces
defined in that loader.
- otherwise, a
LinkageError is thrown (because a
class that implements all of the specified interfaces cannot be
defined in any loader).
Otherwise, a ClassNotFoundException is thrown
for one of the named interfaces that could not be resolved.
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setFactory"));
}
return defaultProvider;
| public static java.lang.Object | getSecurityContext(java.lang.ClassLoader loader)Returns the security context of the given class loader.
return sun.rmi.server.LoaderHandler.getSecurityContext(loader);
| private static java.rmi.server.RMIClassLoaderSpi | initializeProvider()Chooses provider instance, following above documentation.
This method assumes that it has been invoked in a privileged block.
/*
* First check for the system property being set:
*/
String providerClassName =
System.getProperty("java.rmi.server.RMIClassLoaderSpi");
if (providerClassName != null) {
if (providerClassName.equals("default")) {
return defaultProvider;
}
try {
Class providerClass =
Class.forName(providerClassName, false,
ClassLoader.getSystemClassLoader());
return (RMIClassLoaderSpi) providerClass.newInstance();
} catch (ClassNotFoundException e) {
throw new NoClassDefFoundError(e.getMessage());
} catch (IllegalAccessException e) {
throw new IllegalAccessError(e.getMessage());
} catch (InstantiationException e) {
throw new InstantiationError(e.getMessage());
} catch (ClassCastException e) {
Error error = new LinkageError(
"provider class not assignable to RMIClassLoaderSpi");
error.initCause(e);
throw error;
}
}
/*
* Next look for a provider configuration file intalled:
*/
Iterator iter = Service.providers(RMIClassLoaderSpi.class,
ClassLoader.getSystemClassLoader());
if (iter.hasNext()) {
try {
return (RMIClassLoaderSpi) iter.next();
} catch (ClassCastException e) {
Error error = new LinkageError(
"provider class not assignable to RMIClassLoaderSpi");
error.initCause(e);
throw error;
}
}
/*
* Finally, return the canonical instance of the default provider.
*/
return defaultProvider;
| public static java.lang.Class | loadClass(java.lang.String name)Loads the class with the specified name .
This method delegates to {@link #loadClass(String,String)},
passing null as the first argument and
name as the second argument.
return loadClass((String) null, name);
| public static java.lang.Class | loadClass(java.net.URL codebase, java.lang.String name)Loads a class from a codebase URL.
If codebase is null , then this method
will behave the same as {@link #loadClass(String,String)} with a
null codebase and the given class name.
This method delegates to the
{@link RMIClassLoaderSpi#loadClass(String,String,ClassLoader)}
method of the provider instance, passing the result of invoking
{@link URL#toString} on the given URL (or null if
codebase is null) as the first argument,
name as the second argument,
and null as the third argument.
return provider.loadClass(
codebase != null ? codebase.toString() : null, name, null);
| public static java.lang.Class | loadClass(java.lang.String codebase, java.lang.String name)Loads a class from a codebase URL path.
This method delegates to the
{@link RMIClassLoaderSpi#loadClass(String,String,ClassLoader)}
method of the provider instance, passing codebase
as the first argument, name as the second argument,
and null as the third argument.
return provider.loadClass(codebase, name, null);
| public static java.lang.Class | loadClass(java.lang.String codebase, java.lang.String name, java.lang.ClassLoader defaultLoader)Loads a class from a codebase URL path, optionally using the
supplied loader.
This method should be used when the caller would like to make
available to the provider implementation an additional contextual
class loader to consider, such as the loader of a caller on the
stack. Typically, a provider implementation will attempt to
resolve the named class using the given defaultLoader ,
if specified, before attempting to resolve the class from the
codebase URL path.
This method delegates to the
{@link RMIClassLoaderSpi#loadClass(String,String,ClassLoader)}
method of the provider instance, passing codebase
as the first argument, name as the second argument,
and defaultLoader as the third argument.
return provider.loadClass(codebase, name, defaultLoader);
| public static java.lang.Class | loadProxyClass(java.lang.String codebase, java.lang.String[] interfaces, java.lang.ClassLoader defaultLoader)Loads a dynamic proxy class (see {@link java.lang.reflect.Proxy})
that implements a set of interfaces with the given names
from a codebase URL path.
The interfaces will be resolved similar to classes loaded via
the {@link #loadClass(String,String)} method using the given
codebase .
This method delegates to the
{@link RMIClassLoaderSpi#loadProxyClass(String,String[],ClassLoader)}
method of the provider instance, passing codebase
as the first argument, interfaces as the second argument,
and defaultLoader as the third argument.
return provider.loadProxyClass(codebase, interfaces, defaultLoader);
| private static java.rmi.server.RMIClassLoaderSpi | newDefaultProviderInstance()Creates an instance of the default provider class.
return new RMIClassLoaderSpi() {
public Class loadClass(String codebase, String name,
ClassLoader defaultLoader)
throws MalformedURLException, ClassNotFoundException
{
return sun.rmi.server.LoaderHandler.loadClass(
codebase, name, defaultLoader);
}
public Class loadProxyClass(String codebase, String[] interfaces,
ClassLoader defaultLoader)
throws MalformedURLException, ClassNotFoundException
{
return sun.rmi.server.LoaderHandler.loadProxyClass(
codebase, interfaces, defaultLoader);
}
public ClassLoader getClassLoader(String codebase)
throws MalformedURLException
{
return sun.rmi.server.LoaderHandler.getClassLoader(codebase);
}
public String getClassAnnotation(Class<?> cl) {
return sun.rmi.server.LoaderHandler.getClassAnnotation(cl);
}
};
|
|