2 Copyright (c) 1996, 1997, 1998, 1999, 2002, 2003
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
58 static private class MyClassLoader
extends URLClassLoader
60 private MyClassLoader (URL
[] urls
, ClassLoader parent
, String annotation
)
63 this.annotation
= annotation
;
66 private MyClassLoader (URL
[] urls
, ClassLoader parent
)
69 this.annotation
= urlToAnnotation (urls
);
72 public static String
urlToAnnotation (URL
[] urls
)
77 StringBuffer annotation
= new StringBuffer (64 * urls
.length
);
79 for (int i
= 0; i
< urls
.length
; i
++)
81 annotation
.append (urls
[i
].toExternalForm());
82 annotation
.append (' ');
85 return annotation
.toString();
88 public final String
getClassAnnotation()
93 private final String annotation
;
97 * This class is used to identify a cached classloader by its codebase and
98 * the context classloader that is its parent.
100 private static class CacheKey
102 private String mCodeBase
;
103 private ClassLoader mContextClassLoader
;
105 public CacheKey (String theCodebase
, ClassLoader theContextClassLoader
)
107 mCodeBase
= theCodebase
;
108 mContextClassLoader
= theContextClassLoader
;
112 * @return true if the codebase and the context classloader are equal
114 public boolean equals (Object theOther
)
116 if (theOther
instanceof CacheKey
)
118 CacheKey key
= (CacheKey
) theOther
;
120 return (equals (this.mCodeBase
,key
.mCodeBase
)
121 && equals (this.mContextClassLoader
, key
.mContextClassLoader
));
127 * Test if the two objects are equal or both null.
132 private boolean equals (Object theOne
, Object theOther
)
134 return theOne
!= null ? theOne
.equals (theOther
) : theOther
== null;
140 public int hashCode()
142 return ((mCodeBase
!= null ? mCodeBase
.hashCode() : 0)
143 ^
(mContextClassLoader
!= null ? mContextClassLoader
.hashCode() : -1));
146 public String
toString()
148 return "[" + mCodeBase
+ "," + mContextClassLoader
+ "]";
153 private static Map cacheLoaders
; //map annotations to loaders
154 private static Map cacheAnnotations
; //map loaders to annotations
156 //defaultAnnotation is got from system property
157 // "java.rmi.server.defaultAnnotation"
158 private static String defaultAnnotation
;
160 //URL object for defaultAnnotation
161 private static URL defaultCodebase
;
163 //class loader for defaultAnnotation
164 private static MyClassLoader defaultLoader
;
168 // 89 is a nice prime number for Hashtable initial capacity
169 cacheLoaders
= new Hashtable (89);
170 cacheAnnotations
= new Hashtable (89);
172 defaultAnnotation
= System
.getProperty ("java.rmi.server.defaultAnnotation");
176 if (defaultAnnotation
!= null)
177 defaultCodebase
= new URL (defaultAnnotation
);
181 defaultCodebase
= null;
184 if (defaultCodebase
!= null)
186 defaultLoader
= new MyClassLoader (new URL
[] { defaultCodebase
}, null,
188 cacheLoaders
.put (new CacheKey (defaultAnnotation
,
189 Thread
.currentThread().getContextClassLoader()),
197 public static Class
loadClass (String name
)
198 throws MalformedURLException
, ClassNotFoundException
200 return loadClass ("", name
);
203 public static Class
loadClass (String codebases
, String name
)
204 throws MalformedURLException
, ClassNotFoundException
206 ClassLoader loader
= Thread
.currentThread().getContextClassLoader();
208 //try context class loader first
211 return loader
.loadClass (name
);
213 catch (ClassNotFoundException e
)
215 // class not found in the local classpath
218 if (codebases
.length() == 0) //==""
220 loader
= defaultLoader
;
224 loader
= getClassLoader(codebases
);
229 //do not throw NullPointerException
230 throw new ClassNotFoundException ("Could not find class (" + name
+
231 ") at codebase (" + codebases
+ ")");
234 return loader
.loadClass (name
);
238 * Gets a classloader for the given codebase and with the current
239 * context classloader as parent.
243 * @return a classloader for the given codebase
245 * @throws MalformedURLException if the codebase contains a malformed URL
247 private static ClassLoader
getClassLoader (String codebases
)
248 throws MalformedURLException
251 CacheKey loaderKey
= new CacheKey
252 (codebases
, Thread
.currentThread().getContextClassLoader());
253 loader
= (ClassLoader
) cacheLoaders
.get (loaderKey
);
257 //create an entry in cacheLoaders mapping a loader to codebases.
258 // codebases are separated by " "
259 StringTokenizer tok
= new StringTokenizer (codebases
, " ");
260 ArrayList urls
= new ArrayList();
262 while (tok
.hasMoreTokens())
263 urls
.add (new URL (tok
.nextToken()));
265 loader
= new MyClassLoader ((URL
[]) urls
.toArray (new URL
[urls
.size()]),
266 Thread
.currentThread().getContextClassLoader(),
268 cacheLoaders
.put (loaderKey
, loader
);
275 * Returns a string representation of the network location where a remote
276 * endpoint can get the class-definition of the given class.
280 * @return a space seperated list of URLs where the class-definition
283 public static String
getClassAnnotation (Class cl
)
285 ClassLoader loader
= cl
.getClassLoader();
288 || loader
== ClassLoader
.getSystemClassLoader())
290 return System
.getProperty ("java.rmi.server.codebase");
293 if (loader
instanceof MyClassLoader
)
295 return ((MyClassLoader
) loader
).getClassAnnotation();
298 String s
= (String
) cacheAnnotations
.get (loader
);
303 if (loader
instanceof URLClassLoader
)
305 URL
[] urls
= ((URLClassLoader
) loader
).getURLs();
307 if (urls
.length
== 0)
310 StringBuffer annotation
= new StringBuffer (64 * urls
.length
);
312 for (int i
= 0; i
< urls
.length
; i
++)
314 annotation
.append (urls
[i
].toExternalForm());
315 annotation
.append (' ');
318 s
= annotation
.toString();
319 cacheAnnotations
.put (loader
, s
);
323 return System
.getProperty ("java.rmi.server.codebase");
329 public static Object
getSecurityContext (ClassLoader loader
)
331 throw new Error ("Not implemented");