1 /* RMIClassLoaderImpl.java -- FIXME: briefly describe file purpose
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu
.java
.rmi
.server
;
41 import java
.net
.MalformedURLException
;
43 import java
.net
.URLClassLoader
;
44 import java
.rmi
.server
.RMIClassLoaderSpi
;
45 import java
.util
.ArrayList
;
46 import java
.util
.Hashtable
;
48 import java
.util
.StringTokenizer
;
51 * The default implementation of {@link java.rmi.server.RMIClassLoaderSpi}.
53 * @author Roman Kennke (kennke@aicas.com)
55 public class RMIClassLoaderImpl
extends RMIClassLoaderSpi
57 private static class MyClassLoader
extends URLClassLoader
59 // Package-private to avoid a trampoline constructor.
60 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 RMIClassLoaderImpl instance
= null;
155 private static Map cacheLoaders
; //map annotations to loaders
156 private static Map cacheAnnotations
; //map loaders to annotations
157 //class loader for defaultAnnotation
158 private static MyClassLoader defaultClassLoader
;
160 //defaultAnnotation is got from system property
161 // "java.rmi.server.defaultAnnotation"
162 private static String defaultAnnotation
;
164 //URL object for defaultAnnotation
165 private static URL defaultCodebase
;
169 // 89 is a nice prime number for Hashtable initial capacity
170 cacheLoaders
= new Hashtable (89);
171 cacheAnnotations
= new Hashtable (89);
173 defaultAnnotation
= System
.getProperty ("java.rmi.server.defaultAnnotation");
177 if (defaultAnnotation
!= null)
178 defaultCodebase
= new URL (defaultAnnotation
);
182 defaultCodebase
= null;
185 if (defaultCodebase
!= null)
187 defaultClassLoader
= new MyClassLoader (new URL
[] { defaultCodebase
}, null,
189 cacheLoaders
.put (new CacheKey (defaultAnnotation
,
190 Thread
.currentThread().getContextClassLoader()),
196 * This is a singleton class and may only be instantiated once from within
197 * the {@link #getInstance} method.
199 private RMIClassLoaderImpl()
204 * Returns an instance of RMIClassLoaderImpl.
206 * @return an instance of RMIClassLoaderImpl
208 public static RMIClassLoaderSpi
getInstance()
210 if (instance
== null)
211 instance
= new RMIClassLoaderImpl();
215 public Class
loadClass(String codeBase
, String name
,
216 ClassLoader defaultLoader
)
217 throws MalformedURLException
, ClassNotFoundException
220 if (defaultLoader
== null)
221 loader
= Thread
.currentThread().getContextClassLoader();
223 loader
= defaultLoader
;
225 //try context class loader first
228 return Class
.forName(name
, false, loader
);
230 catch (ClassNotFoundException e
)
232 // class not found in the local classpath
235 if (codeBase
.length() == 0) //==""
237 loader
= defaultClassLoader
;
241 loader
= getClassLoader(codeBase
);
246 //do not throw NullPointerException
247 throw new ClassNotFoundException ("Could not find class (" + name
+
248 ") at codebase (" + codeBase
+ ")");
251 return Class
.forName(name
, false, loader
);
254 public Class
loadProxyClass(String codeBase
, String
[] interfaces
,
255 ClassLoader defaultLoader
)
256 throws MalformedURLException
, ClassNotFoundException
258 // FIXME: Implement this.
263 * Gets a classloader for the given codebase and with the current
264 * context classloader as parent.
268 * @return a classloader for the given codebase
270 * @throws MalformedURLException if the codebase contains a malformed URL
272 public ClassLoader
getClassLoader(String codebase
)
273 throws MalformedURLException
276 CacheKey loaderKey
= new CacheKey
277 (codebase
, Thread
.currentThread().getContextClassLoader());
278 loader
= (ClassLoader
) cacheLoaders
.get (loaderKey
);
282 //create an entry in cacheLoaders mapping a loader to codebases.
283 // codebases are separated by " "
284 StringTokenizer tok
= new StringTokenizer (codebase
, " ");
285 ArrayList urls
= new ArrayList();
287 while (tok
.hasMoreTokens())
288 urls
.add (new URL(tok
.nextToken()));
290 loader
= new MyClassLoader((URL
[]) urls
.toArray(new URL
[urls
.size()]),
291 Thread
.currentThread().getContextClassLoader(),
293 cacheLoaders
.put (loaderKey
, loader
);
300 * Returns a string representation of the network location where a remote
301 * endpoint can get the class-definition of the given class.
305 * @return a space seperated list of URLs where the class-definition
308 public String
getClassAnnotation(Class cl
)
310 ClassLoader loader
= cl
.getClassLoader();
313 || loader
== ClassLoader
.getSystemClassLoader())
315 return System
.getProperty ("java.rmi.server.codebase");
318 if (loader
instanceof MyClassLoader
)
320 return ((MyClassLoader
) loader
).getClassAnnotation();
323 String s
= (String
) cacheAnnotations
.get (loader
);
328 if (loader
instanceof URLClassLoader
)
330 URL
[] urls
= ((URLClassLoader
) loader
).getURLs();
332 if (urls
.length
== 0)
335 StringBuffer annotation
= new StringBuffer (64 * urls
.length
);
337 for (int i
= 0; i
< urls
.length
; i
++)
339 annotation
.append (urls
[i
].toExternalForm());
340 annotation
.append (' ');
343 s
= annotation
.toString();
344 cacheAnnotations
.put (loader
, s
);
348 return System
.getProperty ("java.rmi.server.codebase");