38 |
|
|
39 |
package java.rmi.server; |
package java.rmi.server; |
40 |
|
|
41 |
import java.net.MalformedURLException; |
import gnu.java.rmi.server.RMIClassLoaderImpl; |
|
import java.net.URL; |
|
|
import java.net.URLClassLoader; |
|
|
import java.util.ArrayList; |
|
|
import java.util.Hashtable; |
|
|
import java.util.Map; |
|
|
import java.util.StringTokenizer; |
|
42 |
|
|
43 |
|
import java.net.MalformedURLException; |
44 |
|
|
45 |
/** |
/** |
46 |
* This class provides a set of public static utility methods for supporting |
* This class provides a set of public static utility methods for supporting |
55 |
*/ |
*/ |
56 |
private RMIClassLoader() {} |
private RMIClassLoader() {} |
57 |
|
|
|
private static class MyClassLoader extends URLClassLoader |
|
|
{ |
|
|
// Package-private to avoid a trampoline constructor. |
|
|
MyClassLoader (URL[] urls, ClassLoader parent, String annotation) |
|
|
{ |
|
|
super (urls, parent); |
|
|
this.annotation = annotation; |
|
|
} |
|
|
|
|
|
private MyClassLoader (URL[] urls, ClassLoader parent) |
|
|
{ |
|
|
super (urls, parent); |
|
|
this.annotation = urlToAnnotation (urls); |
|
|
} |
|
|
|
|
|
public static String urlToAnnotation (URL[] urls) |
|
|
{ |
|
|
if (urls.length == 0) |
|
|
return null; |
|
|
|
|
|
StringBuffer annotation = new StringBuffer (64 * urls.length); |
|
|
|
|
|
for (int i = 0; i < urls.length; i++) |
|
|
{ |
|
|
annotation.append (urls [i].toExternalForm()); |
|
|
annotation.append (' '); |
|
|
} |
|
|
|
|
|
return annotation.toString(); |
|
|
} |
|
|
|
|
|
public final String getClassAnnotation() |
|
|
{ |
|
|
return annotation; |
|
|
} |
|
|
|
|
|
private final String annotation; |
|
|
} |
|
|
|
|
|
/** |
|
|
* This class is used to identify a cached classloader by its codebase and |
|
|
* the context classloader that is its parent. |
|
|
*/ |
|
|
private static class CacheKey |
|
|
{ |
|
|
private String mCodeBase; |
|
|
private ClassLoader mContextClassLoader; |
|
|
|
|
|
public CacheKey (String theCodebase, ClassLoader theContextClassLoader) |
|
|
{ |
|
|
mCodeBase = theCodebase; |
|
|
mContextClassLoader = theContextClassLoader; |
|
|
} |
|
|
|
|
|
/** |
|
|
* @return true if the codebase and the context classloader are equal |
|
|
*/ |
|
|
public boolean equals (Object theOther) |
|
|
{ |
|
|
if (theOther instanceof CacheKey) |
|
|
{ |
|
|
CacheKey key = (CacheKey) theOther; |
|
|
|
|
|
return (equals (this.mCodeBase,key.mCodeBase) |
|
|
&& equals (this.mContextClassLoader, key.mContextClassLoader)); |
|
|
} |
|
|
return false; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Test if the two objects are equal or both null. |
|
|
* @param theOne |
|
|
* @param theOther |
|
|
* @return |
|
|
*/ |
|
|
private boolean equals (Object theOne, Object theOther) |
|
|
{ |
|
|
return theOne != null ? theOne.equals (theOther) : theOther == null; |
|
|
} |
|
|
|
|
|
/** |
|
|
* @return hashCode |
|
|
*/ |
|
|
public int hashCode() |
|
|
{ |
|
|
return ((mCodeBase != null ? mCodeBase.hashCode() : 0) |
|
|
^(mContextClassLoader != null ? mContextClassLoader.hashCode() : -1)); |
|
|
} |
|
|
|
|
|
public String toString() |
|
|
{ |
|
|
return "[" + mCodeBase + "," + mContextClassLoader + "]"; |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
private static Map cacheLoaders; //map annotations to loaders |
|
|
private static Map cacheAnnotations; //map loaders to annotations |
|
|
|
|
|
//defaultAnnotation is got from system property |
|
|
// "java.rmi.server.defaultAnnotation" |
|
|
private static String defaultAnnotation; |
|
|
|
|
|
//URL object for defaultAnnotation |
|
|
private static URL defaultCodebase; |
|
|
|
|
|
//class loader for defaultAnnotation |
|
|
private static MyClassLoader defaultLoader; |
|
|
|
|
|
static |
|
|
{ |
|
|
// 89 is a nice prime number for Hashtable initial capacity |
|
|
cacheLoaders = new Hashtable (89); |
|
|
cacheAnnotations = new Hashtable (89); |
|
|
|
|
|
defaultAnnotation = System.getProperty ("java.rmi.server.defaultAnnotation"); |
|
|
|
|
|
try |
|
|
{ |
|
|
if (defaultAnnotation != null) |
|
|
defaultCodebase = new URL (defaultAnnotation); |
|
|
} |
|
|
catch (Exception _) |
|
|
{ |
|
|
defaultCodebase = null; |
|
|
} |
|
|
|
|
|
if (defaultCodebase != null) |
|
|
{ |
|
|
defaultLoader = new MyClassLoader (new URL[] { defaultCodebase }, null, |
|
|
defaultAnnotation); |
|
|
cacheLoaders.put (new CacheKey (defaultAnnotation, |
|
|
Thread.currentThread().getContextClassLoader()), |
|
|
defaultLoader); |
|
|
} |
|
|
} |
|
|
|
|
58 |
/** |
/** |
59 |
* @deprecated |
* @deprecated |
60 |
*/ |
*/ |
61 |
public static Class loadClass (String name) |
public static Class loadClass(String name) |
62 |
throws MalformedURLException, ClassNotFoundException |
throws MalformedURLException, ClassNotFoundException |
63 |
{ |
{ |
64 |
return loadClass ("", name); |
return loadClass("", name); |
65 |
} |
} |
66 |
|
|
67 |
public static Class loadClass (String codebases, String name) |
public static Class loadClass(String codebase, String name) |
68 |
throws MalformedURLException, ClassNotFoundException |
throws MalformedURLException, ClassNotFoundException |
69 |
{ |
{ |
70 |
ClassLoader loader = Thread.currentThread().getContextClassLoader(); |
RMIClassLoaderSpi spi = getProviderInstance(); |
71 |
|
if (spi == null) |
72 |
|
spi = getDefaultProviderInstance(); |
73 |
|
return spi.loadClass(codebase, name, null); |
74 |
|
} |
75 |
|
|
76 |
//try context class loader first |
public static Class loadClass(String codebase, String name, |
77 |
try |
ClassLoader defaultLoader) |
78 |
{ |
throws MalformedURLException, ClassNotFoundException |
79 |
return Class.forName(name, false, loader); |
{ |
80 |
} |
RMIClassLoaderSpi spi = getProviderInstance(); |
81 |
catch (ClassNotFoundException e) |
if (spi == null) |
82 |
{ |
spi = getDefaultProviderInstance(); |
83 |
// class not found in the local classpath |
return spi.loadClass(codebase, name, defaultLoader); |
|
} |
|
|
|
|
|
if (codebases.length() == 0) //=="" |
|
|
{ |
|
|
loader = defaultLoader; |
|
|
} |
|
|
else |
|
|
{ |
|
|
loader = getClassLoader(codebases); |
|
|
} |
|
|
|
|
|
if (loader == null) |
|
|
{ |
|
|
//do not throw NullPointerException |
|
|
throw new ClassNotFoundException ("Could not find class (" + name + |
|
|
") at codebase (" + codebases + ")"); |
|
|
} |
|
|
|
|
|
return Class.forName(name, false, loader); |
|
84 |
} |
} |
85 |
|
|
86 |
/** |
/** |
87 |
* Gets a classloader for the given codebase and with the current |
* Gets a classloader for the given codebase and with the current |
88 |
* context classloader as parent. |
* context classloader as parent. |
89 |
* |
* |
90 |
* @param codebases |
* @param codebase |
91 |
* |
* |
92 |
* @return a classloader for the given codebase |
* @return a classloader for the given codebase |
93 |
* |
* |
94 |
* @throws MalformedURLException if the codebase contains a malformed URL |
* @throws MalformedURLException if the codebase contains a malformed URL |
95 |
*/ |
*/ |
96 |
public static ClassLoader getClassLoader (String codebases) |
public static ClassLoader getClassLoader(String codebase) |
97 |
throws MalformedURLException |
throws MalformedURLException |
98 |
{ |
{ |
99 |
ClassLoader loader; |
RMIClassLoaderSpi spi = getProviderInstance(); |
100 |
CacheKey loaderKey = new CacheKey |
if (spi == null) |
101 |
(codebases, Thread.currentThread().getContextClassLoader()); |
spi = getDefaultProviderInstance(); |
102 |
loader = (ClassLoader) cacheLoaders.get (loaderKey); |
return spi.getClassLoader(codebase); |
|
|
|
|
if (loader == null) |
|
|
{ |
|
|
//create an entry in cacheLoaders mapping a loader to codebases. |
|
|
// codebases are separated by " " |
|
|
StringTokenizer tok = new StringTokenizer (codebases, " "); |
|
|
ArrayList urls = new ArrayList(); |
|
|
|
|
|
while (tok.hasMoreTokens()) |
|
|
urls.add (new URL (tok.nextToken())); |
|
|
|
|
|
loader = new MyClassLoader ((URL[]) urls.toArray (new URL [urls.size()]), |
|
|
Thread.currentThread().getContextClassLoader(), |
|
|
codebases); |
|
|
cacheLoaders.put (loaderKey, loader); |
|
|
} |
|
|
|
|
|
return loader; |
|
103 |
} |
} |
104 |
|
|
105 |
/** |
/** |
111 |
* @return a space seperated list of URLs where the class-definition |
* @return a space seperated list of URLs where the class-definition |
112 |
* of cl may be found |
* of cl may be found |
113 |
*/ |
*/ |
114 |
public static String getClassAnnotation (Class cl) |
public static String getClassAnnotation(Class cl) |
115 |
{ |
{ |
116 |
ClassLoader loader = cl.getClassLoader(); |
RMIClassLoaderSpi spi = getProviderInstance(); |
117 |
|
if (spi == null) |
118 |
if (loader == null |
spi = getDefaultProviderInstance(); |
119 |
|| loader == ClassLoader.getSystemClassLoader()) |
return spi.getClassAnnotation(cl); |
|
{ |
|
|
return System.getProperty ("java.rmi.server.codebase"); |
|
|
} |
|
|
|
|
|
if (loader instanceof MyClassLoader) |
|
|
{ |
|
|
return ((MyClassLoader) loader).getClassAnnotation(); |
|
|
} |
|
|
|
|
|
String s = (String) cacheAnnotations.get (loader); |
|
|
|
|
|
if (s != null) |
|
|
return s; |
|
|
|
|
|
if (loader instanceof URLClassLoader) |
|
|
{ |
|
|
URL[] urls = ((URLClassLoader) loader).getURLs(); |
|
|
|
|
|
if (urls.length == 0) |
|
|
return null; |
|
|
|
|
|
StringBuffer annotation = new StringBuffer (64 * urls.length); |
|
|
|
|
|
for (int i = 0; i < urls.length; i++) |
|
|
{ |
|
|
annotation.append (urls [i].toExternalForm()); |
|
|
annotation.append (' '); |
|
|
} |
|
|
|
|
|
s = annotation.toString(); |
|
|
cacheAnnotations.put (loader, s); |
|
|
return s; |
|
|
} |
|
|
|
|
|
return System.getProperty ("java.rmi.server.codebase"); |
|
120 |
} |
} |
121 |
|
|
122 |
/** |
/** |
126 |
{ |
{ |
127 |
throw new Error ("Not implemented"); |
throw new Error ("Not implemented"); |
128 |
} |
} |
129 |
|
|
130 |
|
/** |
131 |
|
* Returns the default service provider for <code>RMIClassLoader</code>. |
132 |
|
* |
133 |
|
* @return the default provider for <code>RMIClassLoader</code> |
134 |
|
*/ |
135 |
|
public static RMIClassLoaderSpi getDefaultProviderInstance() |
136 |
|
{ |
137 |
|
return RMIClassLoaderImpl.getInstance(); |
138 |
|
} |
139 |
|
|
140 |
|
/** |
141 |
|
* Chooses, instantiates and returns a service provider. |
142 |
|
* |
143 |
|
* @return a service provider |
144 |
|
*/ |
145 |
|
private static RMIClassLoaderSpi getProviderInstance() |
146 |
|
{ |
147 |
|
// TODO: Do something more useful here. |
148 |
|
return null; |
149 |
|
} |
150 |
} |
} |