Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: java/rmi/server/RMIClassLoader.java


1   /* RMIClassLoader.java --
2      Copyright (c) 1996, 1997, 1998, 1999, 2002, 2003, 2004
3      Free Software Foundation, Inc.
4   
5   This file is part of GNU Classpath.
6   
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)
10  any later version.
11  
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.
16  
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., 51 Franklin Street, Fifth Floor, Boston, MA
20  02110-1301 USA.
21  
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
25  combination.
26  
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. */
38  
39  package java.rmi.server;
40  
41  import java.net.MalformedURLException;
42  import java.net.URL;
43  import java.net.URLClassLoader;
44  import java.util.ArrayList;
45  import java.util.Hashtable;
46  import java.util.Map;
47  import java.util.StringTokenizer;
48  
49  
50  /**
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.
55   */
56  public class RMIClassLoader
57  {
58    /**
59     * This class isn't intended to be instantiated.
60     */
61    private RMIClassLoader() {}
62  
63    private static class MyClassLoader extends URLClassLoader
64    {
65      // Package-private to avoid a trampoline constructor.
66      MyClassLoader (URL[] urls, ClassLoader parent, String annotation)
67      {
68        super (urls, parent);
69        this.annotation = annotation;
70      }
71  
72      private MyClassLoader (URL[] urls, ClassLoader parent)
73      {
74        super (urls, parent);
75        this.annotation = urlToAnnotation (urls);
76      }
77  
78      public static String urlToAnnotation (URL[] urls)
79      {
80        if (urls.length == 0)
81          return null;
82  
83        StringBuffer annotation = new StringBuffer (64 * urls.length);
84  
85        for (int i = 0; i < urls.length; i++)
86        {
87          annotation.append (urls [i].toExternalForm());
88          annotation.append (' ');
89        }
90  
91        return annotation.toString();
92      }
93  
94      public final String getClassAnnotation()
95      {
96        return annotation;
97      }
98  
99      private final String annotation;
100   }
101   
102   /** 
103    * This class is used to identify a cached classloader by its codebase and 
104    * the context classloader that is its parent.
105    */  
106   private static class CacheKey
107   {
108      private String mCodeBase;
109      private ClassLoader mContextClassLoader;
110     
111      public CacheKey (String theCodebase, ClassLoader theContextClassLoader)
112      {
113        mCodeBase = theCodebase;
114        mContextClassLoader = theContextClassLoader;
115      }
116     
117     /**
118      * @return true if the codebase and the context classloader are equal
119      */
120     public boolean equals (Object theOther)
121     {
122       if (theOther instanceof CacheKey)
123       {
124         CacheKey key = (CacheKey) theOther;
125   
126         return (equals (this.mCodeBase,key.mCodeBase)
127                 && equals (this.mContextClassLoader, key.mContextClassLoader));
128         }
129       return false;
130     }
131     
132     /**
133      * Test if the two objects are equal or both null.
134      * @param theOne
135      * @param theOther
136      * @return
137      */
138     private boolean equals (Object theOne, Object theOther)
139     {
140       return theOne != null ? theOne.equals (theOther) : theOther == null;
141     }
142 
143     /**
144      * @return hashCode  
145      */
146     public int hashCode()
147     {
148       return ((mCodeBase != null           ? mCodeBase.hashCode()           :  0) 
149               ^(mContextClassLoader != null ? mContextClassLoader.hashCode() : -1));
150     }
151 
152     public String toString()
153     {
154       return "[" + mCodeBase + "," + mContextClassLoader + "]"; 
155     }
156 
157   }
158 
159   private static Map cacheLoaders; //map annotations to loaders
160   private static Map cacheAnnotations; //map loaders to annotations
161 
162   //defaultAnnotation is got from system property
163   // "java.rmi.server.defaultAnnotation"
164   private static String defaultAnnotation;
165 
166   //URL object for defaultAnnotation
167   private static URL defaultCodebase;
168 
169   //class loader for defaultAnnotation
170   private static MyClassLoader defaultLoader;
171 
172   static
173   {
174     // 89 is a nice prime number for Hashtable initial capacity
175     cacheLoaders = new Hashtable (89);
176     cacheAnnotations = new Hashtable (89);
177 
178     defaultAnnotation = System.getProperty ("java.rmi.server.defaultAnnotation");
179 
180     try
181       {
182         if (defaultAnnotation != null)
183           defaultCodebase = new URL (defaultAnnotation);
184       }
185     catch (Exception _)
186       {
187         defaultCodebase = null;
188       }
189 
190     if (defaultCodebase != null)
191       {
192         defaultLoader = new MyClassLoader (new URL[] { defaultCodebase }, null,
193                                            defaultAnnotation);
194         cacheLoaders.put (new CacheKey (defaultAnnotation,
195                                         Thread.currentThread().getContextClassLoader()),
196                                         defaultLoader);
197       }
198     }
199 
200   /**
201    * @deprecated
202    */
203   public static Class loadClass (String name)
204     throws MalformedURLException, ClassNotFoundException
205   {
206     return loadClass ("", name);
207   }
208 
209   public static Class loadClass (String codebases, String name)
210     throws MalformedURLException, ClassNotFoundException
211   {
212     ClassLoader loader = Thread.currentThread().getContextClassLoader();
213 
214     //try context class loader first
215     try 
216       {
217         return Class.forName(name, false, loader);
218       }
219     catch (ClassNotFoundException e)
220       {
221         // class not found in the local classpath
222       }
223 
224     if (codebases.length() == 0) //==""
225       {
226         loader = defaultLoader;
227       }
228     else
229       {
230         loader = getClassLoader(codebases);
231       }
232 
233     if (loader == null)
234       {
235         //do not throw NullPointerException
236         throw new ClassNotFoundException ("Could not find class (" + name +
237                                           ") at codebase (" + codebases + ")");
238       }
239       
240     return Class.forName(name, false, loader);
241   }
242 
243   /**
244    * Gets a classloader for the given codebase and with the current
245    * context classloader as parent.
246    * 
247    * @param codebases
248    * 
249    * @return a classloader for the given codebase
250    * 
251    * @throws MalformedURLException if the codebase contains a malformed URL
252    */
253   public static ClassLoader getClassLoader (String codebases) 
254     throws MalformedURLException
255   {
256     ClassLoader loader;
257     CacheKey loaderKey = new CacheKey
258       (codebases, Thread.currentThread().getContextClassLoader());
259     loader = (ClassLoader) cacheLoaders.get (loaderKey);
260       
261     if (loader == null)
262       {
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();
267       
268         while (tok.hasMoreTokens())
269           urls.add (new URL (tok.nextToken()));
270       
271         loader = new MyClassLoader ((URL[]) urls.toArray (new URL [urls.size()]),
272                                     Thread.currentThread().getContextClassLoader(),
273                                     codebases);
274         cacheLoaders.put (loaderKey, loader);
275       }
276            
277     return loader;
278   }
279  
280   /**
281    * Returns a string representation of the network location where a remote
282    * endpoint can get the class-definition of the given class.
283    *
284    * @param cl
285    *
286    * @return a space seperated list of URLs where the class-definition
287    * of cl may be found
288    */
289   public static String getClassAnnotation (Class cl)
290   {
291     ClassLoader loader = cl.getClassLoader();
292     
293     if (loader == null
294         || loader == ClassLoader.getSystemClassLoader())
295       {
296         return System.getProperty ("java.rmi.server.codebase");
297       }
298 
299     if (loader instanceof MyClassLoader)
300       {
301         return ((MyClassLoader) loader).getClassAnnotation();
302       }
303 
304     String s = (String) cacheAnnotations.get (loader);
305 
306     if (s != null)
307       return s;
308 
309     if (loader instanceof URLClassLoader)
310       {
311         URL[] urls = ((URLClassLoader) loader).getURLs();
312 
313         if (urls.length == 0)
314           return null;
315 
316         StringBuffer annotation = new StringBuffer (64 * urls.length);
317 
318         for (int i = 0; i < urls.length; i++)
319           {
320             annotation.append (urls [i].toExternalForm());
321             annotation.append (' ');
322           }
323 
324         s = annotation.toString();
325         cacheAnnotations.put (loader, s);
326         return s;
327       }
328 
329     return System.getProperty ("java.rmi.server.codebase");
330   }
331 
332   /**
333    * @deprecated
334    */
335   public static Object getSecurityContext (ClassLoader loader)
336   {
337     throw new Error ("Not implemented");
338   }
339 }