Merge from mainline.
[official-gcc.git] / libjava / classpath / gnu / java / rmi / server / RMIClassLoaderImpl.java
blob2e1e7805531b9b1341bdbc94bf3eb5c9ef89adf0
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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;
42 import java.net.URL;
43 import java.net.URLClassLoader;
44 import java.rmi.server.RMIClassLoaderSpi;
45 import java.util.ArrayList;
46 import java.util.Hashtable;
47 import java.util.Map;
48 import java.util.StringTokenizer;
50 /**
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)
62 super (urls, parent);
63 this.annotation = annotation;
66 private MyClassLoader (URL[] urls, ClassLoader parent)
68 super (urls, parent);
69 this.annotation = urlToAnnotation (urls);
72 public static String urlToAnnotation (URL[] urls)
74 if (urls.length == 0)
75 return null;
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()
90 return annotation;
93 private final String annotation;
96 /**
97 * This class is used to identify a cached classloader by its codebase and
98 * the context classloader that is its parent.
99 */
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));
123 return false;
127 * Test if the two objects are equal or both null.
128 * @param theOne
129 * @param theOther
130 * @return
132 private boolean equals (Object theOne, Object theOther)
134 return theOne != null ? theOne.equals (theOther) : theOther == null;
138 * @return hashCode
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;
167 static
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);
180 catch (Exception _)
182 defaultCodebase = null;
185 if (defaultCodebase != null)
187 defaultClassLoader = new MyClassLoader (new URL[] { defaultCodebase }, null,
188 defaultAnnotation);
189 cacheLoaders.put (new CacheKey (defaultAnnotation,
190 Thread.currentThread().getContextClassLoader()),
191 defaultClassLoader);
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();
212 return instance;
215 public Class loadClass(String codeBase, String name,
216 ClassLoader defaultLoader)
217 throws MalformedURLException, ClassNotFoundException
219 ClassLoader loader;
220 if (defaultLoader == null)
221 loader = Thread.currentThread().getContextClassLoader();
222 else
223 loader = defaultLoader;
225 //try context class loader first
226 try
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;
239 else
241 loader = getClassLoader(codeBase);
244 if (loader == null)
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.
259 return null;
263 * Gets a classloader for the given codebase and with the current
264 * context classloader as parent.
266 * @param codebase
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
275 ClassLoader loader;
276 CacheKey loaderKey = new CacheKey
277 (codebase, Thread.currentThread().getContextClassLoader());
278 loader = (ClassLoader) cacheLoaders.get (loaderKey);
280 if (loader == null)
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(),
292 codebase);
293 cacheLoaders.put (loaderKey, loader);
296 return loader;
300 * Returns a string representation of the network location where a remote
301 * endpoint can get the class-definition of the given class.
303 * @param cl
305 * @return a space seperated list of URLs where the class-definition
306 * of cl may be found
308 public String getClassAnnotation(Class cl)
310 ClassLoader loader = cl.getClassLoader();
312 if (loader == null
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);
325 if (s != null)
326 return s;
328 if (loader instanceof URLClassLoader)
330 URL[] urls = ((URLClassLoader) loader).getURLs();
332 if (urls.length == 0)
333 return null;
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);
345 return s;
348 return System.getProperty ("java.rmi.server.codebase");