43 |
import java.io.IOException; |
import java.io.IOException; |
44 |
import java.io.DataInputStream; |
import java.io.DataInputStream; |
45 |
import java.net.MalformedURLException; |
import java.net.MalformedURLException; |
46 |
import java.util.StringTokenizer; |
import java.util.ArrayList; |
47 |
import java.util.Collection; |
import java.util.Collection; |
48 |
import java.util.Collections; |
import java.util.Collections; |
49 |
|
import java.util.Hashtable; |
50 |
import java.util.Map; |
import java.util.Map; |
51 |
|
import java.util.StringTokenizer; |
52 |
import java.util.WeakHashMap; |
import java.util.WeakHashMap; |
|
import java.util.ArrayList; |
|
53 |
|
|
54 |
public class RMIClassLoader |
public class RMIClassLoader |
55 |
{ |
{ |
56 |
|
|
57 |
static private class MyClassLoader extends URLClassLoader |
static private class MyClassLoader extends URLClassLoader |
58 |
{ |
{ |
59 |
|
|
60 |
|
private MyClassLoader(URL[] urls, ClassLoader parent, String annotation) |
61 |
|
{ |
62 |
|
super(urls, parent); |
63 |
|
this.annotation = annotation; |
64 |
|
} |
65 |
|
|
66 |
private MyClassLoader(URL[] urls, ClassLoader parent) |
private MyClassLoader(URL[] urls, ClassLoader parent) |
67 |
{ |
{ |
68 |
super (urls, parent); |
super (urls, parent); |
69 |
|
this.annotation = urlToAnnotation(urls); |
70 |
} |
} |
71 |
|
|
72 |
Class defineClass(String name, byte[] data) |
public static String urlToAnnotation(URL[] urls) |
73 |
{ |
{ |
74 |
return defineClass(name, data, 0, data.length); |
if (urls.length == 0) |
75 |
|
return null; |
76 |
|
|
77 |
|
StringBuffer annotation = new StringBuffer(64*urls.length); |
78 |
|
for(int i = 0; i < urls.length; i++) |
79 |
|
{ |
80 |
|
annotation.append(urls[i].toExternalForm()); |
81 |
|
annotation.append(' '); |
82 |
|
} |
83 |
|
|
84 |
|
return annotation.toString(); |
85 |
|
} |
86 |
|
|
87 |
|
public final String getClassAnnotation(){ |
88 |
|
return annotation; |
89 |
} |
} |
90 |
|
|
91 |
|
private final String annotation; |
92 |
|
|
93 |
} |
} |
94 |
|
|
95 |
private static Map cacheLoaders; //map annotations to loaders |
private static Map cacheLoaders; //map annotations to loaders |
96 |
private static Map cacheClasses; //map loader to classes that the loader loaded+ |
private static Map cacheAnnotations; //map loaders to annotations |
97 |
|
|
98 |
|
//defaultAnnotation is got from system property |
99 |
|
// "java.rmi.server.defaultAnnotation" |
100 |
private static String defaultAnnotation; |
private static String defaultAnnotation; |
101 |
|
//URL object for defaultAnnotation |
102 |
private static URL defaultCodebase; |
private static URL defaultCodebase; |
103 |
|
//class loader for defaultAnnotation |
104 |
private static MyClassLoader defaultLoader; |
private static MyClassLoader defaultLoader; |
105 |
|
|
106 |
static |
static |
107 |
{ |
{ |
108 |
cacheLoaders = Collections.synchronizedMap(new WeakHashMap(5)); |
// 89 is a nice prime number for Hashtable initial capacity |
109 |
cacheClasses = Collections.synchronizedMap(new WeakHashMap(5)); |
cacheLoaders = new Hashtable(89); |
110 |
|
cacheAnnotations = new Hashtable(89); |
111 |
|
|
112 |
defaultAnnotation = System.getProperty("java.rmi.server.defaultAnnotation"); |
defaultAnnotation = System.getProperty("java.rmi.server.defaultAnnotation"); |
113 |
try |
try |
114 |
{ |
{ |
122 |
if (defaultCodebase != null) |
if (defaultCodebase != null) |
123 |
{ |
{ |
124 |
defaultLoader = new MyClassLoader(new URL[]{ defaultCodebase }, |
defaultLoader = new MyClassLoader(new URL[]{ defaultCodebase }, |
125 |
Thread.currentThread().getContextClassLoader()); |
null, defaultAnnotation); |
126 |
cacheLoaders.put(defaultAnnotation, defaultLoader); |
cacheLoaders.put(defaultAnnotation, defaultLoader); |
|
cacheClasses.put(defaultLoader, Collections.synchronizedMap(new WeakHashMap())); |
|
127 |
} |
} |
128 |
} |
} |
129 |
|
|
136 |
return (loadClass("", name)); |
return (loadClass("", name)); |
137 |
} |
} |
138 |
|
|
139 |
public static Class loadClass(URL codebase, String name) |
public static Class loadClass(String codebases, String name) |
140 |
throws MalformedURLException, ClassNotFoundException |
throws MalformedURLException, ClassNotFoundException |
141 |
{ |
{ |
142 |
URL u = new URL(codebase, name + ".class"); |
Class c = null; |
143 |
|
ClassLoader loader = Thread.currentThread().getContextClassLoader(); |
144 |
|
//try context class loader first |
145 |
try |
try |
146 |
{ |
{ |
147 |
URLConnection conn = u.openConnection(); |
c = loader.loadClass(name); |
|
DataInputStream strm = new DataInputStream(conn.getInputStream()); |
|
|
byte data[] = new byte[conn.getContentLength()]; |
|
|
strm.readFully(data); |
|
|
return (defaultLoader.defineClass(name, data)); |
|
|
} |
|
|
catch (IOException _) |
|
|
{ |
|
|
throw new ClassNotFoundException(name); |
|
148 |
} |
} |
149 |
} |
catch(ClassNotFoundException e) {} |
150 |
|
|
151 |
public static Class loadClass(String codebases, String name) |
if (c != null) |
152 |
throws MalformedURLException, ClassNotFoundException |
return c; |
153 |
{ |
|
154 |
ClassLoader loader = (ClassLoader)cacheLoaders.get(codebases); |
if (codebases.length() == 0) //=="" |
155 |
if (loader == null) |
loader = defaultLoader; |
156 |
|
else |
157 |
{ |
{ |
158 |
if (codebases != "") |
loader = (ClassLoader)cacheLoaders.get(codebases); |
159 |
|
if (loader == null) |
160 |
{ |
{ |
161 |
//codebases are separated by " " |
//create an entry in cacheLoaders mapping a loader to codebases. |
162 |
|
|
163 |
|
// codebases are separated by " " |
164 |
StringTokenizer tok = new StringTokenizer(codebases, " "); |
StringTokenizer tok = new StringTokenizer(codebases, " "); |
165 |
ArrayList urls = new ArrayList(); |
ArrayList urls = new ArrayList(); |
166 |
while (tok.hasMoreTokens()) |
while (tok.hasMoreTokens()) |
167 |
urls.add(new URL(tok.nextToken())); |
urls.add(new URL(tok.nextToken())); |
168 |
|
|
169 |
loader = new MyClassLoader((URL[])urls.toArray(new URL[urls.size()]), |
loader = new MyClassLoader((URL[])urls.toArray(new URL[urls.size()]), |
170 |
Thread.currentThread().getContextClassLoader()); |
null, codebases); |
171 |
cacheLoaders.put(codebases, loader); |
cacheLoaders.put(codebases, loader); |
|
cacheClasses.put(loader, Collections.synchronizedMap(new WeakHashMap())); |
|
|
} |
|
|
else |
|
|
{ |
|
|
//if codebases is empty, construct a classloader |
|
|
// based on current context classloader, |
|
|
// and we won't cache classloader for empty codebases |
|
|
loader = new MyClassLoader(new URL[]{ defaultCodebase }, |
|
|
Thread.currentThread().getContextClassLoader()); |
|
172 |
} |
} |
173 |
} |
} |
174 |
|
|
175 |
Class c = null; |
return loader.loadClass(name); |
|
Map classes = (Map)cacheClasses.get(loader); |
|
|
if (classes != null) |
|
|
{ |
|
|
c = (Class)classes.get(name); |
|
|
if (c == null) |
|
|
{ |
|
|
c = loader.loadClass(name); |
|
|
classes.put(name, c); |
|
|
} |
|
|
}else |
|
|
c = loader.loadClass(name); |
|
|
|
|
|
return c; |
|
176 |
} |
} |
177 |
|
|
178 |
public static String getClassAnnotation(Class cl) |
public static String getClassAnnotation(Class cl) |
179 |
{ |
{ |
180 |
ClassLoader loader = cl.getClassLoader(); |
ClassLoader loader = cl.getClassLoader(); |
181 |
if (loader == null) |
if (loader == null || loader == ClassLoader.getSystemClassLoader()) |
182 |
{ |
{ |
183 |
if (defaultCodebase != null) |
return null; //?? |
184 |
return defaultCodebase.toExternalForm(); |
} |
185 |
else |
|
186 |
return null; |
if (loader instanceof MyClassLoader) |
187 |
|
{ |
188 |
|
return ((MyClassLoader)loader).getClassAnnotation(); |
189 |
} |
} |
190 |
|
|
191 |
|
String s = (String)cacheAnnotations.get(loader); |
192 |
|
if (s != null) |
193 |
|
return s; |
194 |
|
|
195 |
if (loader instanceof URLClassLoader) |
if (loader instanceof URLClassLoader) |
196 |
{ |
{ |
197 |
URL[] urls = ((URLClassLoader)loader).getURLs(); |
URL[] urls = ((URLClassLoader)loader).getURLs(); |
198 |
if(urls.length == 0) |
if(urls.length == 0) |
199 |
return null; |
return null; |
200 |
StringBuffer annotation = new StringBuffer(urls[0].toExternalForm()); |
|
201 |
for(int i = 1; i < urls.length; i++) |
StringBuffer annotation = new StringBuffer(64*urls.length); |
202 |
|
for(int i = 0; i < urls.length; i++) |
203 |
{ |
{ |
|
annotation.append(' '); |
|
204 |
annotation.append(urls[i].toExternalForm()); |
annotation.append(urls[i].toExternalForm()); |
205 |
|
annotation.append(' '); |
206 |
} |
} |
207 |
return annotation.toString(); |
s = annotation.toString(); |
208 |
|
cacheAnnotations.put(loader, s); |
209 |
} |
} |
210 |
return null; |
return null; |
211 |
} |
} |