~ubuntu-branches/ubuntu/raring/libjboss-remoting-java/raring

« back to all changes in this revision

Viewing changes to src/org/jboss/remoting/loading/ClassByteClassLoader.java

  • Committer: Package Import Robot
  • Author(s): Torsten Werner
  • Date: 2011-09-09 14:01:03 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: package-import@ubuntu.com-20110909140103-hqokx61534tas9rg
Tags: 2.5.3.SP1-1
* Newer but not newest upstream release. Do not build samples.
* Change debian/watch to upstream's svn repo.
* Add patch to fix compile error caused by tomcat update.
  (Closes: #628303)
* Switch to source format 3.0.
* Switch to debhelper level 7.
* Remove useless Depends.
* Update Standards-Version: 3.9.2.
* Update README.source.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
* JBoss, Home of Professional Open Source
3
 
* Copyright 2005, JBoss Inc., and individual contributors as indicated
4
 
* by the @authors tag. See the copyright.txt in the distribution for a
5
 
* full listing of individual contributors.
6
 
*
7
 
* This is free software; you can redistribute it and/or modify it
8
 
* under the terms of the GNU Lesser General Public License as
9
 
* published by the Free Software Foundation; either version 2.1 of
10
 
* the License, or (at your option) any later version.
11
 
*
12
 
* This software is distributed in the hope that it will be useful,
13
 
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
 
* Lesser General Public License for more details.
16
 
*
17
 
* You should have received a copy of the GNU Lesser General Public
18
 
* License along with this software; if not, write to the Free
19
 
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20
 
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21
 
*/
22
 
package org.jboss.remoting.loading;
23
 
 
24
 
import org.jboss.logging.Logger;
25
 
import org.jboss.remoting.Client;
26
 
import org.jboss.remoting.util.SecurityUtility;
27
 
 
28
 
import java.io.File;
29
 
import java.io.FileInputStream;
30
 
import java.io.FileNotFoundException;
31
 
import java.io.FileOutputStream;
32
 
import java.io.IOException;
33
 
import java.io.InputStream;
34
 
import java.io.OutputStream;
35
 
import java.lang.ref.Reference;
36
 
import java.lang.ref.ReferenceQueue;
37
 
import java.lang.ref.WeakReference;
38
 
import java.security.AccessController;
39
 
import java.security.PrivilegedAction;
40
 
import java.security.PrivilegedActionException;
41
 
import java.security.PrivilegedExceptionAction;
42
 
import java.util.Collections;
43
 
import java.util.HashMap;
44
 
import java.util.Map;
45
 
 
46
 
/**
47
 
 * ClassByteClassLoader is a classloader that will allow dynamic adding of classes from a remote machine
48
 
 * to be added and visible locally.
49
 
 *
50
 
 * @author <a href="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>
51
 
 * @author <a href="mailto:tom@jboss.org">Tom Elrod</a>
52
 
 * @version $Revision: 5003 $
53
 
 */
54
 
public class ClassByteClassLoader extends ClassLoader
55
 
{
56
 
   private static final Logger log = Logger.getLogger(ClassByteClassLoader.class);
57
 
   private final Map loadedClasses = Collections.synchronizedMap(new java.util.HashMap());
58
 
   private final Map loadedResources = Collections.synchronizedMap(new java.util.HashMap());
59
 
   private final ReferenceQueue queue = new ReferenceQueue();
60
 
 
61
 
   private Client loaderClient = null;
62
 
 
63
 
   public ClassByteClassLoader()
64
 
   {
65
 
      super();
66
 
   }
67
 
 
68
 
   public ClassByteClassLoader(ClassLoader parent)
69
 
   {
70
 
      super(parent);
71
 
   }
72
 
 
73
 
   public void setClientInvoker(Client loaderClient)
74
 
   {
75
 
      this.loaderClient = loaderClient;
76
 
   }
77
 
 
78
 
   /**
79
 
    * Will disconnect loader client if is present.
80
 
    */
81
 
   public void destroy()
82
 
   {
83
 
      if(loaderClient != null && loaderClient.isConnected())
84
 
      {
85
 
         loaderClient.disconnect();
86
 
      }
87
 
   }
88
 
 
89
 
   /**
90
 
    * inner class will keep an local reference to the key
91
 
    * so we can lookup the resource File that we are using
92
 
    * on deletion to ensure we've cleaned it up
93
 
    */
94
 
   private final class MyRef extends WeakReference
95
 
   {
96
 
      private final String key;
97
 
 
98
 
      MyRef(String key, Object obj)
99
 
      {
100
 
         super(obj);
101
 
         this.key = key;
102
 
      }
103
 
   }
104
 
 
105
 
   /**
106
 
    * clean an individual reference and delete any remaining
107
 
    * resources that are still being referenced by it
108
 
    */
109
 
   private void clean(MyRef myref)
110
 
   {
111
 
      loadedClasses.remove(myref.key);
112
 
      File f = (File) loadedResources.remove(myref.key);
113
 
      if(f != null)
114
 
      {
115
 
         f.delete();
116
 
      }
117
 
      myref.clear();
118
 
      myref = null;
119
 
   }
120
 
 
121
 
   /**
122
 
    * will walk through all objects (if any) in the ReferenceQueue and
123
 
    * make sure we've cleaned up our released class references
124
 
    */
125
 
   private void performMaintenance()
126
 
   {
127
 
      int count = 0;
128
 
      Reference ref = null;
129
 
      while((ref = queue.poll()) != null)
130
 
      {
131
 
         count++;
132
 
         MyRef myref = (MyRef) ref;
133
 
         clean(myref);
134
 
      }
135
 
 
136
 
      if(count > 0 && log.isTraceEnabled())
137
 
      {
138
 
         log.trace("ClassByteClassLoader reclaimed " + count + " objects");
139
 
      }
140
 
   }
141
 
 
142
 
 
143
 
   public String toString()
144
 
   {
145
 
      return "ClassByteClassLoader [" + loadedClasses + "]";
146
 
   }
147
 
 
148
 
   protected void finalize() throws Throwable
149
 
   {
150
 
      // make sure we're OK on the reference queue
151
 
      performMaintenance();
152
 
 
153
 
      java.util.Iterator iter = loadedResources.values().iterator();
154
 
      while(iter.hasNext())
155
 
      {
156
 
         ((java.io.File) iter.next()).delete();
157
 
      }
158
 
      loadedResources.clear();
159
 
      loadedClasses.clear();
160
 
      super.finalize();
161
 
   }
162
 
 
163
 
   public Class loadClass(final String className, ClassBytes bytes[])
164
 
         throws ClassNotFoundException, java.io.IOException
165
 
   {
166
 
      // make sure we're OK on the reference queue
167
 
      performMaintenance();
168
 
 
169
 
      if(log.isTraceEnabled())
170
 
      {
171
 
         log.trace("loadClass: " + className + ", bytes: " + bytes);
172
 
      }
173
 
      if(bytes != null)
174
 
      {
175
 
         for(int c = 0; c < bytes.length; c++)
176
 
         {
177
 
            addClass(bytes[c]);
178
 
         }
179
 
      }
180
 
      Class cl = lookupCachedClass(className);
181
 
      if(cl != null)
182
 
      {
183
 
         return cl;
184
 
      }
185
 
      cl = findLoadedClass(className);
186
 
      if(cl != null)
187
 
      {
188
 
         return cl;
189
 
      }
190
 
      cl = Class.forName(className, false, getSystemClassLoaderPrivate());
191
 
      if(cl != null)
192
 
      {
193
 
         return cl;
194
 
      }
195
 
      cl = Class.forName(className, false, getParent());
196
 
      if(cl != null)
197
 
      {
198
 
         return cl;
199
 
      }
200
 
      cl = loadFromNetwork(className);
201
 
      if(cl != null)
202
 
      {
203
 
         return cl;
204
 
      }
205
 
      throw new ClassNotFoundException("Could not load class " + className);
206
 
   }
207
 
 
208
 
   private void addClassResource(String name, byte buf[])
209
 
         throws IOException
210
 
   {
211
 
      // make sure we're OK on the reference queue
212
 
      performMaintenance();
213
 
 
214
 
      OutputStream out = null;
215
 
      File file = null;
216
 
      try
217
 
      {
218
 
         file = createTempFile("cbc", ".class", true);
219
 
         if(log.isTraceEnabled())
220
 
         {
221
 
            log.trace("adding resource at: " + name + " to file: " + file);
222
 
         }
223
 
         out = getFileOutputStream(file);
224
 
         out.write(buf);
225
 
         out.flush();
226
 
      }
227
 
      catch(java.io.IOException ex)
228
 
      {
229
 
         file = null;
230
 
         throw ex;
231
 
      }
232
 
      finally
233
 
      {
234
 
         if(out != null)
235
 
         {
236
 
            try
237
 
            {
238
 
               out.close();
239
 
            }
240
 
            catch(Exception ig)
241
 
            {
242
 
            }
243
 
            out = null;
244
 
         }
245
 
         if(file != null)
246
 
         {
247
 
            loadedResources.put(name, file);
248
 
         }
249
 
      }
250
 
   }
251
 
 
252
 
   public java.io.InputStream getResourceAsStream(String name)
253
 
   {
254
 
      // make sure we're OK on the reference queue
255
 
      performMaintenance();
256
 
 
257
 
      String denormalized = name.replace('/', '.').substring(0, name.length() - 6);
258
 
      java.io.File file = (java.io.File) loadedResources.get(denormalized);
259
 
      if(log.isTraceEnabled())
260
 
      {
261
 
         log.trace("getResourceAsStream =>" + denormalized + " = " + file);
262
 
      }
263
 
      if(file != null && fileExists(file))
264
 
      {
265
 
         try
266
 
         {
267
 
            InputStream is = getFileInputStream(file);
268
 
            return new java.io.BufferedInputStream(is);
269
 
         }
270
 
         catch(Exception ex)
271
 
         {
272
 
            log.debug("file doesn't exist", ex);
273
 
         }
274
 
      }
275
 
      return super.getResourceAsStream(name);
276
 
   }
277
 
 
278
 
   public Class addClass(ClassBytes classBytes)
279
 
         throws java.io.IOException
280
 
   {
281
 
      // make sure we're OK on the reference queue
282
 
      performMaintenance();
283
 
 
284
 
      Class cl = null;
285
 
      String name = classBytes.getClassName();
286
 
      if(loadedClasses.containsKey(name) == false)
287
 
      {
288
 
         byte buf[] = classBytes.getClassBytes();
289
 
         boolean array = ClassUtil.isArrayClass(name);
290
 
         String cn = (array) ? ClassUtil.getArrayClassPart(name) : name;
291
 
         if(log.isTraceEnabled())
292
 
         {
293
 
            log.trace("  add class: " + name + ", array?" + array + ", using as: " + cn);
294
 
         }
295
 
         cl = defineClass(cn, buf, 0, buf.length);
296
 
         resolveClass(cl);
297
 
         addClassResource(cn, buf);
298
 
         loadedClasses.put(cn, new MyRef(cn, cl));
299
 
      }
300
 
      return cl;
301
 
   }
302
 
 
303
 
   /**
304
 
    * lookup a cached class and return null if not found
305
 
    */
306
 
   private Class lookupCachedClass(String cn)
307
 
   {
308
 
      Class cl = null;
309
 
      MyRef ref = (MyRef) loadedClasses.get(cn);
310
 
      if(ref != null)
311
 
      {
312
 
         // make sure we've not gotten cleared
313
 
         cl = (Class) ref.get();
314
 
         if(cl == null)
315
 
         {
316
 
            // oops, we've been cleared
317
 
            clean(ref);
318
 
         }
319
 
      }
320
 
      return cl;
321
 
   }
322
 
 
323
 
   /**
324
 
    * Finds the specified class. This method should be overridden
325
 
    * by class loader implementations that follow the new delegation model
326
 
    * for loading classes, and will be called by the <code>loadClass</code>
327
 
    * method after checking the parent class loader for the requested class.
328
 
    * The default implementation throws <code>ClassNotFoundException</code>.
329
 
    *
330
 
    * @param name the name of the class
331
 
    * @return the resulting <code>Class</code> object
332
 
    * @throws ClassNotFoundException if the class could not be found
333
 
    * @since 1.2
334
 
    */
335
 
   protected Class findClass(String name) throws ClassNotFoundException
336
 
   {
337
 
      // make sure we're OK on the reference queue
338
 
      performMaintenance();
339
 
 
340
 
      boolean array = ClassUtil.isArrayClass(name);
341
 
      String cn = (array) ? ClassUtil.getArrayClassPart(name) : name;
342
 
      if(log.isTraceEnabled())
343
 
      {
344
 
         log.trace("++ loadClass: " + name + ", array?" + array + ", normalized: [" + cn + "]");
345
 
      }
346
 
      Class cl = lookupCachedClass(cn);
347
 
      // search the mapped classes first
348
 
      if(cl == null)
349
 
      {
350
 
         // search already loaded classes
351
 
         cl = findLoadedClass(cn);
352
 
      }
353
 
      if(cl != null)
354
 
      {
355
 
         if(array)
356
 
         {
357
 
            // we have to create an instance from the Class Part and return the
358
 
            // class ref from it
359
 
            Object obj = java.lang.reflect.Array.newInstance(cl, 1);
360
 
            return obj.getClass();
361
 
         }
362
 
         return cl;
363
 
      }
364
 
 
365
 
      cl = loadFromNetwork(cn);
366
 
      if(cl != null)
367
 
      {
368
 
         if(log.isTraceEnabled())
369
 
         {
370
 
            log.trace("Loaded " + cn + " can class is " + cl);
371
 
         }
372
 
         return cl;
373
 
      }
374
 
 
375
 
 
376
 
      if(log.isTraceEnabled())
377
 
      {
378
 
         log.trace("++ findClass: " + name + " not found, throwing ClassNotFoundException");
379
 
      }
380
 
      throw new ClassNotFoundException(name);
381
 
   }
382
 
 
383
 
   private Class loadFromNetwork(String className)
384
 
   {
385
 
      Class loadedClass = null;
386
 
 
387
 
      if(loaderClient != null)
388
 
      {
389
 
         String marshallerMethodName = "load_class";
390
 
         Map metadata = new HashMap();
391
 
         metadata.put("classname", className);
392
 
 
393
 
         try
394
 
         {
395
 
            if(!loaderClient.isConnected())
396
 
            {
397
 
                loaderClient.connect();
398
 
            }
399
 
            log.debug("attempting to load from network: " + className);
400
 
            Object obj = loaderClient.invoke(marshallerMethodName, metadata);
401
 
            log.debug("loaded from network: " + obj);
402
 
 
403
 
            if(obj != null)
404
 
            {
405
 
               if(obj instanceof ClassBytes)
406
 
               {
407
 
                  ClassBytes classBytes = (ClassBytes) obj;
408
 
                  String name = classBytes.getClassName();
409
 
 
410
 
                  loadedClass = addClass(classBytes);
411
 
               }
412
 
               else
413
 
               {
414
 
                  log.error("Can not load remote class bytes.  Returned object (" + obj + ") is not ClassBytes.");
415
 
               }
416
 
            }
417
 
            else
418
 
            {
419
 
               log.error("Can not load remote class bytes.");
420
 
            }
421
 
         }
422
 
         catch(Throwable throwable)
423
 
         {
424
 
            log.error("Error loading remote class.", throwable);
425
 
         }
426
 
      }
427
 
      else
428
 
      {
429
 
         log.trace("Remoting Client for ClassByteClassLoader is null.  Can not load class remotely.");
430
 
      }
431
 
 
432
 
      return loadedClass;
433
 
   }
434
 
   
435
 
   static private File createTempFile(final String prefix, final String suffix, final boolean deleteOnExit) throws IOException
436
 
   {
437
 
      if (SecurityUtility.skipAccessControl())
438
 
      {
439
 
         File file =  File.createTempFile(prefix, suffix);
440
 
         if (deleteOnExit) file.deleteOnExit();
441
 
         return file;
442
 
      }
443
 
      
444
 
      try
445
 
      {
446
 
         return (File)AccessController.doPrivileged( new PrivilegedExceptionAction()
447
 
         {
448
 
            public Object run() throws IOException
449
 
            {
450
 
               File file =  File.createTempFile(prefix, suffix);
451
 
               if (deleteOnExit) file.deleteOnExit();
452
 
               return file;
453
 
            }
454
 
         });
455
 
      }
456
 
      catch (PrivilegedActionException e)
457
 
      {
458
 
         throw (IOException) e.getCause();
459
 
      }
460
 
   }
461
 
   
462
 
   static private boolean fileExists(final File file)
463
 
   {
464
 
      if (file == null)
465
 
         return false;
466
 
      
467
 
      if (SecurityUtility.skipAccessControl())
468
 
      {
469
 
         return file.exists();
470
 
      }
471
 
 
472
 
      return ((Boolean)AccessController.doPrivileged( new PrivilegedAction()
473
 
      {
474
 
         public Object run()
475
 
         {
476
 
            return new Boolean(file.exists());
477
 
         }
478
 
      })).booleanValue();
479
 
   }
480
 
   
481
 
   static private FileInputStream getFileInputStream(final File file) throws FileNotFoundException
482
 
   {
483
 
      if (SecurityUtility.skipAccessControl())
484
 
      {
485
 
         return new FileInputStream(file);
486
 
      }
487
 
      
488
 
      try
489
 
      {
490
 
         return (FileInputStream)AccessController.doPrivileged( new PrivilegedExceptionAction()
491
 
         {
492
 
            public Object run() throws FileNotFoundException
493
 
            {
494
 
               return new FileInputStream(file);
495
 
            }
496
 
         });
497
 
      }
498
 
      catch (PrivilegedActionException e)
499
 
      {
500
 
         throw (FileNotFoundException) e.getCause();
501
 
      }
502
 
   }
503
 
   
504
 
   static private FileOutputStream getFileOutputStream(final File file)
505
 
   throws FileNotFoundException
506
 
   {
507
 
      if (SecurityUtility.skipAccessControl())
508
 
      {
509
 
         return new FileOutputStream(file);
510
 
      }
511
 
      
512
 
      try
513
 
      {
514
 
         return (FileOutputStream)AccessController.doPrivileged( new PrivilegedExceptionAction()
515
 
         {
516
 
            public Object run() throws FileNotFoundException
517
 
            {
518
 
               return new FileOutputStream(file);
519
 
            }
520
 
         });
521
 
      }
522
 
      catch (PrivilegedActionException e)
523
 
      {
524
 
         throw (FileNotFoundException) e.getCause();
525
 
      }
526
 
   }
527
 
   
528
 
   static private ClassLoader getSystemClassLoaderPrivate()
529
 
   {
530
 
      if (SecurityUtility.skipAccessControl())
531
 
      {
532
 
         return ClassLoader.getSystemClassLoader();
533
 
      }
534
 
 
535
 
      return (ClassLoader)AccessController.doPrivileged( new PrivilegedAction()
536
 
      {
537
 
         public Object run()
538
 
         {
539
 
            return ClassLoader.getSystemClassLoader();
540
 
         }
541
 
      });
542
 
   }
543
 
}