1 /* RMIClassLoader.java --
2 Copyright (c) 1996, 1997, 1998, 1999, 2002, 2003, 2004
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
39 package java
.rmi
.server
;
41 import java
.net
.MalformedURLException
;
43 import java
.net
.URLClassLoader
;
44 import java
.util
.ArrayList
;
45 import java
.util
.Hashtable
;
47 import java
.util
.StringTokenizer
;
51 * This class provides a set of public static utility methods for supporting
52 * network-based class loading in RMI. These methods are called by RMI's
53 * internal marshal streams to implement the dynamic class loading of types for
54 * RMI parameters and return values.
56 public class RMIClassLoader
59 * This class isn't intended to be instantiated.
61 private RMIClassLoader() {}
63 private static class MyClassLoader
extends URLClassLoader
65 // Package-private to avoid a trampoline constructor.
66 MyClassLoader (URL
[] urls
, ClassLoader parent
, String annotation
)
69 this.annotation
= annotation
;
72 private MyClassLoader (URL
[] urls
, ClassLoader parent
)
75 this.annotation
= urlToAnnotation (urls
);
78 public static String
urlToAnnotation (URL
[] urls
)
83 StringBuffer annotation
= new StringBuffer (64 * urls
.length
);
85 for (int i
= 0; i
< urls
.length
; i
++)
87 annotation
.append (urls
[i
].toExternalForm());
88 annotation
.append (' ');
91 return annotation
.toString();
94 public final String
getClassAnnotation()
99 private final String annotation
;
103 * This class is used to identify a cached classloader by its codebase and
104 * the context classloader that is its parent.
106 private static class CacheKey
108 private String mCodeBase
;
109 private ClassLoader mContextClassLoader
;
111 public CacheKey (String theCodebase
, ClassLoader theContextClassLoader
)
113 mCodeBase
= theCodebase
;
114 mContextClassLoader
= theContextClassLoader
;
118 * @return true if the codebase and the context classloader are equal
120 public boolean equals (Object theOther
)
122 if (theOther
instanceof CacheKey
)
124 CacheKey key
= (CacheKey
) theOther
;
126 return (equals (this.mCodeBase
,key
.mCodeBase
)
127 && equals (this.mContextClassLoader
, key
.mContextClassLoader
));
133 * Test if the two objects are equal or both null.
138 private boolean equals (Object theOne
, Object theOther
)
140 return theOne
!= null ? theOne
.equals (theOther
) : theOther
== null;
146 public int hashCode()
148 return ((mCodeBase
!= null ? mCodeBase
.hashCode() : 0)
149 ^
(mContextClassLoader
!= null ? mContextClassLoader
.hashCode() : -1));
152 public String
toString()
154 return "[" + mCodeBase
+ "," + mContextClassLoader
+ "]";
159 private static Map cacheLoaders
; //map annotations to loaders
160 private static Map cacheAnnotations
; //map loaders to annotations
162 //defaultAnnotation is got from system property
163 // "java.rmi.server.defaultAnnotation"
164 private static String defaultAnnotation
;
166 //URL object for defaultAnnotation
167 private static URL defaultCodebase
;
169 //class loader for defaultAnnotation
170 private static MyClassLoader defaultLoader
;
174 // 89 is a nice prime number for Hashtable initial capacity
175 cacheLoaders
= new Hashtable (89);
176 cacheAnnotations
= new Hashtable (89);
178 defaultAnnotation
= System
.getProperty ("java.rmi.server.defaultAnnotation");
182 if (defaultAnnotation
!= null)
183 defaultCodebase
= new URL (defaultAnnotation
);
187 defaultCodebase
= null;
190 if (defaultCodebase
!= null)
192 defaultLoader
= new MyClassLoader (new URL
[] { defaultCodebase
}, null,
194 cacheLoaders
.put (new CacheKey (defaultAnnotation
,
195 Thread
.currentThread().getContextClassLoader()),
203 public static Class
loadClass (String name
)
204 throws MalformedURLException
, ClassNotFoundException
206 return loadClass ("", name
);
209 public static Class
loadClass (String codebases
, String name
)
210 throws MalformedURLException
, ClassNotFoundException
212 ClassLoader loader
= Thread
.currentThread().getContextClassLoader();
214 //try context class loader first
217 return loader
.loadClass (name
);
219 catch (ClassNotFoundException e
)
221 // class not found in the local classpath
224 if (codebases
.length() == 0) //==""
226 loader
= defaultLoader
;
230 loader
= getClassLoader(codebases
);
235 //do not throw NullPointerException
236 throw new ClassNotFoundException ("Could not find class (" + name
+
237 ") at codebase (" + codebases
+ ")");
240 return loader
.loadClass (name
);
244 * Gets a classloader for the given codebase and with the current
245 * context classloader as parent.
249 * @return a classloader for the given codebase
251 * @throws MalformedURLException if the codebase contains a malformed URL
253 private static ClassLoader
getClassLoader (String codebases
)
254 throws MalformedURLException
257 CacheKey loaderKey
= new CacheKey
258 (codebases
, Thread
.currentThread().getContextClassLoader());
259 loader
= (ClassLoader
) cacheLoaders
.get (loaderKey
);
263 //create an entry in cacheLoaders mapping a loader to codebases.
264 // codebases are separated by " "
265 StringTokenizer tok
= new StringTokenizer (codebases
, " ");
266 ArrayList urls
= new ArrayList();
268 while (tok
.hasMoreTokens())
269 urls
.add (new URL (tok
.nextToken()));
271 loader
= new MyClassLoader ((URL
[]) urls
.toArray (new URL
[urls
.size()]),
272 Thread
.currentThread().getContextClassLoader(),
274 cacheLoaders
.put (loaderKey
, loader
);
281 * Returns a string representation of the network location where a remote
282 * endpoint can get the class-definition of the given class.
286 * @return a space seperated list of URLs where the class-definition
289 public static String
getClassAnnotation (Class cl
)
291 ClassLoader loader
= cl
.getClassLoader();
294 || loader
== ClassLoader
.getSystemClassLoader())
296 return System
.getProperty ("java.rmi.server.codebase");
299 if (loader
instanceof MyClassLoader
)
301 return ((MyClassLoader
) loader
).getClassAnnotation();
304 String s
= (String
) cacheAnnotations
.get (loader
);
309 if (loader
instanceof URLClassLoader
)
311 URL
[] urls
= ((URLClassLoader
) loader
).getURLs();
313 if (urls
.length
== 0)
316 StringBuffer annotation
= new StringBuffer (64 * urls
.length
);
318 for (int i
= 0; i
< urls
.length
; i
++)
320 annotation
.append (urls
[i
].toExternalForm());
321 annotation
.append (' ');
324 s
= annotation
.toString();
325 cacheAnnotations
.put (loader
, s
);
329 return System
.getProperty ("java.rmi.server.codebase");
335 public static Object
getSecurityContext (ClassLoader loader
)
337 throw new Error ("Not implemented");