KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > remoting > loading > ClassByteClassLoader


1 /***************************************
2  * *
3  * JBoss: The OpenSource J2EE WebOS *
4  * *
5  * Distributable under LGPL license. *
6  * See terms of license at gnu.org. *
7  * *
8  ***************************************/

9 package org.jboss.remoting.loading;
10
11 import java.io.File JavaDoc;
12 import java.io.FileOutputStream JavaDoc;
13 import java.io.IOException JavaDoc;
14 import java.io.OutputStream JavaDoc;
15 import java.lang.ref.Reference JavaDoc;
16 import java.lang.ref.ReferenceQueue JavaDoc;
17 import java.lang.ref.WeakReference JavaDoc;
18 import java.util.Collections JavaDoc;
19 import java.util.HashMap JavaDoc;
20 import java.util.Map JavaDoc;
21 import org.jboss.logging.Logger;
22 import org.jboss.remoting.Client;
23
24 /**
25  * ClassByteClassLoader is a classloader that will allow dynamic adding of classes from a remote machine
26  * to be added and visible locally.
27  *
28  * @author <a HREF="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>
29  * @author <a HREF="mailto:tom@jboss.org">Tom Elrod</a>
30  * @version $Revision: 1.2 $
31  */

32 public class ClassByteClassLoader extends ClassLoader JavaDoc
33 {
34    private static final Logger log = Logger.getLogger(ClassByteClassLoader.class);
35    private final Map JavaDoc loadedClasses = Collections.synchronizedMap(new java.util.HashMap JavaDoc());
36    private final Map JavaDoc loadedResources = Collections.synchronizedMap(new java.util.HashMap JavaDoc());
37    private final ReferenceQueue JavaDoc queue = new ReferenceQueue JavaDoc();
38
39    private Client loaderClient = null;
40
41    public ClassByteClassLoader()
42    {
43       super();
44    }
45
46    public ClassByteClassLoader(ClassLoader JavaDoc parent)
47    {
48       super(parent);
49    }
50
51    public void setClientInvoker(Client loaderClient)
52    {
53       this.loaderClient = loaderClient;
54    }
55
56    /**
57     * Will disconnect loader client if is present.
58     */

59    public void destroy()
60    {
61       if(loaderClient != null && loaderClient.isConnected())
62       {
63          loaderClient.disconnect();
64       }
65    }
66
67    /**
68     * inner class will keep an local reference to the key
69     * so we can lookup the resource File that we are using
70     * on deletion to ensure we've cleaned it up
71     */

72    private final class MyRef extends WeakReference JavaDoc
73    {
74       private final String JavaDoc key;
75
76       MyRef(String JavaDoc key, Object JavaDoc obj)
77       {
78          super(obj);
79          this.key = key;
80       }
81    }
82
83    /**
84     * clean an individual reference and delete any remaining
85     * resources that are still being referenced by it
86     */

87    private void clean(MyRef myref)
88    {
89       loadedClasses.remove(myref.key);
90       File JavaDoc f = (File JavaDoc) loadedResources.remove(myref.key);
91       if(f != null)
92       {
93          f.delete();
94       }
95       myref.clear();
96       myref = null;
97    }
98
99    /**
100     * will walk through all objects (if any) in the ReferenceQueue and
101     * make sure we've cleaned up our released class references
102     */

103    private void performMaintenance()
104    {
105       int count = 0;
106       Reference JavaDoc ref = null;
107       while((ref = queue.poll()) != null)
108       {
109          count++;
110          MyRef myref = (MyRef) ref;
111          clean(myref);
112       }
113
114       if(count > 0 && log.isTraceEnabled())
115       {
116          log.trace("ClassByteClassLoader reclaimed " + count + " objects");
117       }
118    }
119
120
121    public String JavaDoc toString()
122    {
123       return "ClassByteClassLoader [" + loadedClasses + "]";
124    }
125
126    protected void finalize() throws Throwable JavaDoc
127    {
128       // make sure we're OK on the reference queue
129
performMaintenance();
130
131       java.util.Iterator JavaDoc iter = loadedResources.values().iterator();
132       while(iter.hasNext())
133       {
134          ((java.io.File JavaDoc) iter.next()).delete();
135       }
136       loadedResources.clear();
137       loadedClasses.clear();
138       super.finalize();
139    }
140
141    public Class JavaDoc loadClass(String JavaDoc className, ClassBytes bytes[])
142          throws ClassNotFoundException JavaDoc, java.io.IOException JavaDoc
143    {
144       // make sure we're OK on the reference queue
145
performMaintenance();
146
147       if(log.isTraceEnabled())
148       {
149          log.trace("loadClass: " + className + ", bytes: " + bytes);
150       }
151       if(bytes != null)
152       {
153          for(int c = 0; c < bytes.length; c++)
154          {
155             addClass(bytes[c]);
156          }
157       }
158       Class JavaDoc cl = lookupCachedClass(className);
159       if(cl != null)
160       {
161          return cl;
162       }
163       cl = findLoadedClass(className);
164       if(cl != null)
165       {
166          return cl;
167       }
168       cl = ClassLoader.getSystemClassLoader().loadClass(className);
169       if(cl != null)
170       {
171          return cl;
172       }
173       cl = super.loadClass(className, true);
174       if(cl != null)
175       {
176          return cl;
177       }
178       cl = loadFromNetwork(className);
179       if(cl != null)
180       {
181          return cl;
182       }
183       throw new ClassNotFoundException JavaDoc("Could not load class " + className);
184    }
185
186    private void addClassResource(String JavaDoc name, byte buf[])
187          throws IOException JavaDoc
188    {
189       // make sure we're OK on the reference queue
190
performMaintenance();
191
192       OutputStream JavaDoc out = null;
193       File JavaDoc file = null;
194       try
195       {
196          file = File.createTempFile("cbc", ".class");
197          file.deleteOnExit();
198          if(log.isTraceEnabled())
199          {
200             log.trace("adding resource at: " + name + " to file: " + file);
201          }
202          out = new FileOutputStream JavaDoc(file);
203          out.write(buf);
204          out.flush();
205       }
206       catch(java.io.IOException JavaDoc ex)
207       {
208          file = null;
209          throw ex;
210       }
211       finally
212       {
213          if(out != null)
214          {
215             try
216             {
217                out.close();
218             }
219             catch(Exception JavaDoc ig)
220             {
221             }
222             out = null;
223          }
224          if(file != null)
225          {
226             loadedResources.put(name, file);
227          }
228       }
229    }
230
231    public java.io.InputStream JavaDoc getResourceAsStream(String JavaDoc name)
232    {
233       // make sure we're OK on the reference queue
234
performMaintenance();
235
236       String JavaDoc denormalized = name.replace('/', '.').substring(0, name.length() - 6);
237       java.io.File JavaDoc file = (java.io.File JavaDoc) loadedResources.get(denormalized);
238       if(log.isTraceEnabled())
239       {
240          log.trace("getResourceAsStream =>" + denormalized + " = " + file);
241       }
242       if(file != null && file.exists())
243       {
244          try
245          {
246             return new java.io.BufferedInputStream JavaDoc(new java.io.FileInputStream JavaDoc(file));
247          }
248          catch(Exception JavaDoc ex)
249          {
250
251          }
252       }
253       return super.getResourceAsStream(name);
254    }
255
256    public Class JavaDoc addClass(ClassBytes classBytes)
257          throws java.io.IOException JavaDoc
258    {
259       // make sure we're OK on the reference queue
260
performMaintenance();
261
262       Class JavaDoc cl = null;
263       String JavaDoc name = classBytes.getClassName();
264       if(loadedClasses.containsKey(name) == false)
265       {
266          byte buf[] = classBytes.getClassBytes();
267          boolean array = ClassUtil.isArrayClass(name);
268          String JavaDoc cn = (array) ? ClassUtil.getArrayClassPart(name) : name;
269          if(log.isTraceEnabled())
270          {
271             log.trace(" add class: " + name + ", array?" + array + ", using as: " + cn);
272          }
273          cl = defineClass(cn, buf, 0, buf.length);
274          resolveClass(cl);
275          addClassResource(cn, buf);
276          loadedClasses.put(cn, new MyRef(cn, cl));
277       }
278       return cl;
279    }
280
281    /**
282     * lookup a cached class and return null if not found
283     */

284    private Class JavaDoc lookupCachedClass(String JavaDoc cn)
285    {
286       Class JavaDoc cl = null;
287       MyRef ref = (MyRef) loadedClasses.get(cn);
288       if(ref != null)
289       {
290          // make sure we've not gotten cleared
291
cl = (Class JavaDoc) ref.get();
292          if(cl == null)
293          {
294             // oops, we've been cleared
295
clean(ref);
296          }
297       }
298       return cl;
299    }
300
301    /**
302     * Finds the specified class. This method should be overridden
303     * by class loader implementations that follow the new delegation model
304     * for loading classes, and will be called by the <code>loadClass</code>
305     * method after checking the parent class loader for the requested class.
306     * The default implementation throws <code>ClassNotFoundException</code>.
307     *
308     * @param name the name of the class
309     * @return the resulting <code>Class</code> object
310     * @throws ClassNotFoundException if the class could not be found
311     * @since 1.2
312     */

313    protected Class JavaDoc findClass(String JavaDoc name) throws ClassNotFoundException JavaDoc
314    {
315       // make sure we're OK on the reference queue
316
performMaintenance();
317
318       boolean array = ClassUtil.isArrayClass(name);
319       String JavaDoc cn = (array) ? ClassUtil.getArrayClassPart(name) : name;
320       if(log.isTraceEnabled())
321       {
322          log.trace("++ loadClass: " + name + ", array?" + array + ", normalized: [" + cn + "]");
323       }
324       Class JavaDoc cl = lookupCachedClass(cn);
325       // search the mapped classes first
326
if(cl == null)
327       {
328          // search already loaded classes
329
cl = findLoadedClass(cn);
330       }
331       if(cl != null)
332       {
333          if(array)
334          {
335             // we have to create an instance from the Class Part and return the
336
// class ref from it
337
Object JavaDoc obj = java.lang.reflect.Array.newInstance(cl, 1);
338             return obj.getClass();
339          }
340          return cl;
341       }
342
343       cl = loadFromNetwork(cn);
344       if(cl != null)
345       {
346          if(log.isTraceEnabled())
347          {
348             log.trace("Loaded " + cn + " can class is " + cl);
349          }
350          return cl;
351       }
352
353
354       if(log.isTraceEnabled())
355       {
356          log.trace("++ findClass: " + name + " not found, throwing ClassNotFoundException");
357       }
358       throw new ClassNotFoundException JavaDoc(name);
359    }
360
361    private Class JavaDoc loadFromNetwork(String JavaDoc className)
362    {
363       Class JavaDoc loadedClass = null;
364
365       if(loaderClient != null)
366       {
367          String JavaDoc marshallerMethodName = "load_class";
368          Map JavaDoc metadata = new HashMap JavaDoc();
369          metadata.put("classname", className);
370
371          try
372          {
373             Object JavaDoc obj = loaderClient.invoke(marshallerMethodName, metadata);
374
375             if(obj != null)
376             {
377                if(obj instanceof ClassBytes)
378                {
379                   ClassBytes classBytes = (ClassBytes) obj;
380                   String JavaDoc name = classBytes.getClassName();
381
382                   loadedClass = addClass(classBytes);
383                }
384                else
385                {
386                   log.error("Can not load remote class bytes. Returned object (" + obj + ") is not ClassBytes.");
387                }
388             }
389             else
390             {
391                log.error("Can not load remote class bytes.");
392             }
393          }
394          catch(Throwable JavaDoc throwable)
395          {
396             log.error("Error loading remote class.", throwable);
397          }
398       }
399       else
400       {
401          log.trace("Remoting Client for ClassByteClassLoader is null. Can not load class remotely.");
402       }
403
404       return loadedClass;
405    }
406 }
407
Popular Tags