public class PreferredClassProvider extends RMIClassLoaderSpi
RMIClassLoader provider that supports preferred
classes.
See the RMIClassLoader specification for information
about how to install and configure the RMIClassLoader
service provider.
PreferredClassProvider uses instances of PreferredClassLoader to load classes from codebase URI paths
supplied to RMIClassLoader.loadClass methods. In
previous releases only codebase URL paths were permitted.
PreferredClassProvider does not enforce DownloadPermission by default, but a subclass can configure it to
do so by passing true as the argument to the
protected constructor.
By overriding the getClassAnnotation(ClassLoader) method, a subclass can also
configure the class annotations to be used for classes defined by
the system class loader, its ancestor class loaders, and any class
loader that is not an instance of ClassAnnotation or URLClassLoader.
PreferredClassProvider implements the abstract
methods of RMIClassLoaderSpi. Where applicable, these
definitions and descriptions are relative to the instance of
PreferredClassProvider on which a method is invoked
and the context in which it is invoked.
The annotation string for a class loader is determined by the following procedure:
getClassAnnotation(ClassLoader)
with the loader.
ClassAnnotation, the annotation string is the result of invoking
getClassAnnotation on
the loader.
URLClassLoader, the annotation string is a space-separated list of
the URLs returned by an invocation of getURLs on the loader.
getClassAnnotation(ClassLoader) with the loader.
URL(String) constructor; if such
parsing would result in a MalformedURLException, then the
annotation URL path for the loader is only defined to the extent
that it is not equal to any other path of URLs.
A PreferredClassProvider maintains an internal
table of class loader instances indexed by keys that comprise a
path of URIs and a parent class loader. In previous releases keys utilised
URL, but now utilise Uri by default. The following property
-Dnet.jini.loader.codebaseAnnotation=URL
may be set from the command line to revert to URL. The table does not
strongly reference the class loader instances, in order to allow
them (and the classes they have defined) to be garbage collected
when they are not otherwise reachable.
The behavioural difference between Uri and URL when used
in ClassLoader index keys is subtle, URL remote links rely on DNS to resolve
domain names to IP addresses, for this reason, when using strict URL
codebase annotations, the IP address of each codebase at the time they're resolved
is part of the codebase annotations identity. Uri identity on the other hand is
determined by RFC3986 normalization and is more flexible the codebase server
to change its IP address or be replicated by other codebase servers
different IP addresses, provided they can be reached by their domain name
address.
The methods loadClass, loadProxyClass, and getClassLoader, which
each have a String parameter named
codebase, have the following behaviors in common:
codebase may be null. If it is not
null, it is interpreted as a path of URLs by parsing
it as a list of URLs separated by spaces. It is recommended that
URLs be compliant with RFC3986 Syntax. Prior to parsing, any file path
separators converted to '/' and any illegal characters are percentage escaped,
Uri is used to parse each URL
in compliance with RFC3986, in addition file URL paths are
converted to upper case for case insensitive file systems. The array of
RFC3986 normalised Uris along with the current threads context ClassLoader
is used to locate the correct ClassLoader. After normalisation is complete,
each URL is parsed with the URL(String) constructor; this could
result in a MalformedURLException. This path of URLs is the
codebase URL path for the invocation.
codebase and the current thread's context
class loader as follows. If codebase is
null, then the codebase loader is the current thread's
context class loader. Otherwise, for each non-null
loader starting with the current thread's context class loader and
continuing with each successive parent class loader, if the
codebase Uri RFC3986 normalised path is equal to the loader's annotation
Uri RFC3986 normalised path, then the codebase loader is that loader.
If no such matching loader is found, then the codebase loader is the loader
in this PreferredClassProvider's internal table with the
codebase Uri RFC3986 normalised path as the key's path of URLs and the current
thread's context class loader as the key's parent class loader. If
no such entry exists in the table, then one is created by invoking
createClassLoader with the codebase URL
path, the current thread's context class loader, and the
boolean requireDlPerm value that this
PreferredClassProvider was constructed with; the
created loader is added to the table, and it is chosen as the
codebase loader.
openConnection().getPermission() on the URL object is not a FilePermission or if it is a FilePermission whose
name does not contain a directory separator, then that permission
is the appropriate permission. If it is a
FilePermission whose name contains a directory
separator, then the appropriate permission is a
FilePermission with action "read" and the
same name except with the last path segment replaced with
"-" (that is, permission to read all files in the same
directory and all subdirectories).
When PreferredClassProvider attempts to load a
class (or interface) named N using class loader
L, it does so in a manner equivalent to
evaluating the following expression:
Class.forName(N, false, L)
In particular, the case of N being the binary
name of an array class is supported.This implementation uses the Logger named
net.jini.loader.pref.PreferredClassProvider to log
information at the following levels:
| Level | Description |
|---|---|
FAILED | class loading failures |
HANDLED | exceptions caught during class loading operations |
FINE | invocations of loadClass and loadProxyClass
|
FINEST | detailed activity of
loadClass and loadProxyClass
implementations
|
| Modifier | Constructor and Description |
|---|---|
|
PreferredClassProvider()
Creates a new
PreferredClassProvider. |
protected |
PreferredClassProvider(boolean requireDlPerm)
Creates a new
PreferredClassProvider. |
| Modifier and Type | Method and Description |
|---|---|
protected ClassLoader |
createClassLoader(URL[] urls,
ClassLoader parent,
boolean requireDlPerm)
Creates the class loader for this
PreferredClassProvider to use to load classes from
the specified path of URLs with the specified delegation
parent. |
String |
getClassAnnotation(Class cl)
Provides the implementation for
RMIClassLoaderSpi.getClassAnnotation(Class). |
protected String |
getClassAnnotation(ClassLoader loader)
Returns the annotation string for the specified class loader.
|
ClassLoader |
getClassLoader(String codebase)
Provides the implementation for
RMIClassLoaderSpi.getClassLoader(String). |
Class |
loadClass(String codebase,
String name,
ClassLoader defaultLoader)
Provides the implementation for
RMIClassLoaderSpi.loadClass(String,String,ClassLoader). |
Class |
loadProxyClass(String codebase,
String[] interfaceNames,
ClassLoader defaultLoader)
Provides the implementation of
RMIClassLoaderSpi.loadProxyClass(String,String[],ClassLoader). |
public PreferredClassProvider()
PreferredClassProvider.
This constructor is used by the RMIClassLoader
service provider location mechanism when
PreferredClassProvider is configured as the
RMIClassLoader provider class.
If there is a security manager, its checkCreateClassLoader
method is invoked; this could result in a
SecurityException.
DownloadPermission is not enforced by the created
provider.
SecurityException - if there is a security manager and
the invocation of its checkCreateClassLoader
method failsprotected PreferredClassProvider(boolean requireDlPerm)
PreferredClassProvider.
This constructor is used by subclasses to control whether
or not DownloadPermission is enforced.
If there is a security manager, its checkCreateClassLoader
method is invoked; this could result in a
SecurityException.
requireDlPerm - if true, the class loaders
created by the provider will only define classes with a CodeSource that is granted DownloadPermissionSecurityException - if there is a security manager and
the invocation of its checkCreateClassLoader
method failspublic Class loadClass(String codebase, String name, ClassLoader defaultLoader) throws MalformedURLException, ClassNotFoundException
RMIClassLoaderSpi.loadClass(String,String,ClassLoader).
PreferredClassProvider implements this method
as follows:
If name is the binary name of an array class
(of one or more dimensions) with a primitive element type, this
method returns the Class for that array class.
Otherwise, if defaultLoader is not
null and any of the following conditions are true:
codebase is null.
defaultLoader.
PreferredClassLoader.
PreferredClassLoader and an invocation of isPreferredResource
on the codebase loader with the class name described below as
the first argument and true as the second argument
returns false. If name is the binary
name of an array class (of one or more dimensions) with a
element type that is a reference type, the class name passed to
isPreferredResource is the binary name of that
element type; otherwise, the class name passed to
isPreferredResource is name. This
invocation is only done if none of the previous conditions are
true. If isPreferredResource throws an
IOException, this method throws a
ClassNotFoundException.
defaultLoader. If this attempt
succeeds, this method returns the resulting Class;
if it throws a ClassNotFoundException, this method
proceeds as follows.
Otherwise, this method attempts to load the class with the
specified name using the codebase loader, if there is a
security manager and the current security context has
permission to access the codebase loader, or using the current
thread's context class loader otherwise. If this attempt
succeeds, this method returns the resulting Class;
if it throws a ClassNotFoundException, this method
throws a ClassNotFoundException.
loadClass in class RMIClassLoaderSpicodebase - the codebase URL path as a space-separated list
of URLs, or nullname - the binary name of the class to loaddefaultLoader - additional contextual class loader
to use, or nullClass object representing the loaded classMalformedURLException - if codebase is
non-null and contains an invalid URLClassNotFoundException - if a definition for the class
could not be loadedpublic String getClassAnnotation(Class cl)
RMIClassLoaderSpi.getClassAnnotation(Class).
PreferredClassProvider implements this method
as follows:
If cl is an array class (of one or more
dimensions) with a primitive element type, this method returns
null.
Otherwise, this method returns the annotation string for the
defining class loader of cl, except that if the
annotation string would be determined by an invocation of
URLClassLoader.getURLs on that
loader and the current security context does not have the
permissions necessary to connect to each URL returned by that
invocation (where the permission to connect to a URL is
determined by invoking openConnection().getPermission() on the URL object), this method
returns the result of invoking getClassAnnotation(ClassLoader) with the loader instead.
getClassAnnotation in class RMIClassLoaderSpicl - the class to obtain the annotation string fornullprotected String getClassAnnotation(ClassLoader loader)
This method is invoked in order to determine the annotation
string for the system class loader, an ancestor of the system
class loader, any class loader that is not an instance of
ClassAnnotation or URLClassLoader, or (for an
invocation of getClassAnnotation(Class)) a URLClassLoader for
which the current security context does not have the
permissions necessary to connect to all of its URLs.
PreferredClassProvider implements this method
as follows:
This method returns the value of the system property
"java.rmi.server.codebase" (or possibly an earlier
cached value).
loader - the class loader to obtain the annotation string
fornullpublic ClassLoader getClassLoader(String codebase) throws MalformedURLException
RMIClassLoaderSpi.getClassLoader(String).
PreferredClassProvider implements this method
as follows:
If there is a security manager, its
checkPermission method is invoked with a
RuntimePermission("getClassLoader") permission;
this could result in a SecurityException. Also,
if there is a security manager, the codebase loader is not the
current thread's context class loader, and the current security
context does not have permission to access the codebase loader,
this method throws a SecurityException.
This method returns the codebase loader if there is a security manager, or the current thread's context class loader otherwise.
getClassLoader in class RMIClassLoaderSpicodebase - the codebase URL path as a space-separated list
of URLs, or nullMalformedURLException - if codebase is
non-null and contains an invalid URLSecurityException - if there is a security manager and
the invocation of its checkPermission method
fails, or if the current security context does not have the
permissions necessary to connect to all of the URLs in the
codebase URL pathpublic Class loadProxyClass(String codebase, String[] interfaceNames, ClassLoader defaultLoader) throws MalformedURLException, ClassNotFoundException
RMIClassLoaderSpi.loadProxyClass(String,String[],ClassLoader).
PreferredClassProvider implements this method
as follows:
If defaultLoader is not null and
any of the following conditions are true:
codebase is null.
defaultLoader.
PreferredClassLoader.
PreferredClassLoader and an invocation of isPreferredResource
on the codebase loader for each element of
interfaces, with the element as the first argument
and true as the second argument, all return
false. These invocations are only done if none of
the previous conditions are true. If any invocation of
isPreferredResource throws an
IOException, this method throws a
ClassNotFoundException.
interfaces using
defaultLoader. If all of the interfaces are
loaded successfully, then
public: if
there is a security manager, the codebase loader is the current
thread's context class loader or the current security context
has permission to access the codebase loader, and the
annotation URL path for the codebase loader is not equal to the
annotation URL path for defaultLoader, this method
first attempts to get a dynamic proxy class (using Proxy.getProxyClass) that is defined by
the codebase loader and that implements all of the interfaces,
and if this attempt succeeds, this method returns the resulting
Class. Otherwise, this method attempts to get a
dynamic proxy class that is defined by
defaultLoader and that implements all of the
interfaces. If that attempt succeeds, this method returns the
resulting Class; if it throws an
IllegalArgumentException, this method throws a
ClassNotFoundException.
public interfaces are
defined by the same class loader: this method attempts to get a
dynamic proxy class that is defined by that loader and that
implements all of the interfaces. If this attempt succeeds,
this method returns the resulting Class; if it
throws an IllegalArgumentException, this method
throws a ClassNotFoundException.
public
interfaces defined by different class loaders): this method
throws a LinkageError.
ClassNotFoundException, this method proceeds as
follows.
Otherwise, this method attempts to load all of the
interfaces named by the elements of interfaces
using the codebase loader, if there is a security manager and
the current security context has permission to access the
codebase loader, or using the current thread's context class
loader otherwise. If all of the interfaces are loaded
successfully, then
public:
this method attempts to get a dynamic proxy class that is
defined by the loader used to load the interfaces and that
implements all of the interfaces. If this attempt succeeds,
this method returns the resulting Class; if it
throws an IllegalArgumentException, this method
throws a ClassNotFoundException.
public interfaces are
defined by the same class loader: this method attempts to get a
dynamic proxy class that is defined by that loader and that
implements all of the interfaces. If this attempt succeeds,
this method returns the resulting Class; if it
throws an IllegalArgumentException, this method
throws a ClassNotFoundException.
public
interfaces defined by different class loaders): this method
throws a LinkageError.
ClassNotFoundException, this method throws a
ClassNotFoundException.loadProxyClass in class RMIClassLoaderSpicodebase - the codebase URL path as a space-separated list
of URLs, or nullinterfaceNames - the binary names of the interfaces for
the proxy class to implementdefaultLoader - additional contextual class loader to use,
or nullMalformedURLException - if codebase is
non-null and contains an invalid URLClassNotFoundException - if a definition for one of the
named interfaces could not be loaded, or if creation of the
dynamic proxy class failed (such as if
Proxy.getProxyClass would throw an
IllegalArgumentException for the given interface
list)protected ClassLoader createClassLoader(URL[] urls, ClassLoader parent, boolean requireDlPerm)
PreferredClassProvider to use to load classes from
the specified path of URLs with the specified delegation
parent.
PreferredClassProvider implements this method
as follows:
This method creates a new instance of PreferredClassLoader that loads classes and resources from
urls, delegates to parent, and
enforces DownloadPermission if
requireDlPerm is true. The created
loader uses a restricted security context to ensure that the
URL retrieval operations undertaken by the loader cannot
exercise a permission that is not implied by the permissions
necessary to access the loader as a codebase loader for the
specified path of URLs.
urls - the path of URLs to load classes and resources fromparent - the parent class loader for delegationrequireDlPerm - if true, the loader must only
define classes with a CodeSource that is granted
DownloadPermissionCopyright 2007-2013, multiple authors.
Licensed under the Apache License, Version 2.0, see the NOTICE file for attributions.