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.
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.
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.
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.
22
package org.jboss.remoting.loading;
24
import org.jboss.logging.Logger;
25
import org.jboss.remoting.Client;
26
import org.jboss.remoting.util.SecurityUtility;
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;
47
* ClassByteClassLoader is a classloader that will allow dynamic adding of classes from a remote machine
48
* to be added and visible locally.
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 $
54
public class ClassByteClassLoader extends ClassLoader
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();
61
private Client loaderClient = null;
63
public ClassByteClassLoader()
68
public ClassByteClassLoader(ClassLoader parent)
73
public void setClientInvoker(Client loaderClient)
75
this.loaderClient = loaderClient;
79
* Will disconnect loader client if is present.
83
if(loaderClient != null && loaderClient.isConnected())
85
loaderClient.disconnect();
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
94
private final class MyRef extends WeakReference
96
private final String key;
98
MyRef(String key, Object obj)
106
* clean an individual reference and delete any remaining
107
* resources that are still being referenced by it
109
private void clean(MyRef myref)
111
loadedClasses.remove(myref.key);
112
File f = (File) loadedResources.remove(myref.key);
122
* will walk through all objects (if any) in the ReferenceQueue and
123
* make sure we've cleaned up our released class references
125
private void performMaintenance()
128
Reference ref = null;
129
while((ref = queue.poll()) != null)
132
MyRef myref = (MyRef) ref;
136
if(count > 0 && log.isTraceEnabled())
138
log.trace("ClassByteClassLoader reclaimed " + count + " objects");
143
public String toString()
145
return "ClassByteClassLoader [" + loadedClasses + "]";
148
protected void finalize() throws Throwable
150
// make sure we're OK on the reference queue
151
performMaintenance();
153
java.util.Iterator iter = loadedResources.values().iterator();
154
while(iter.hasNext())
156
((java.io.File) iter.next()).delete();
158
loadedResources.clear();
159
loadedClasses.clear();
163
public Class loadClass(final String className, ClassBytes bytes[])
164
throws ClassNotFoundException, java.io.IOException
166
// make sure we're OK on the reference queue
167
performMaintenance();
169
if(log.isTraceEnabled())
171
log.trace("loadClass: " + className + ", bytes: " + bytes);
175
for(int c = 0; c < bytes.length; c++)
180
Class cl = lookupCachedClass(className);
185
cl = findLoadedClass(className);
190
cl = Class.forName(className, false, getSystemClassLoaderPrivate());
195
cl = Class.forName(className, false, getParent());
200
cl = loadFromNetwork(className);
205
throw new ClassNotFoundException("Could not load class " + className);
208
private void addClassResource(String name, byte buf[])
211
// make sure we're OK on the reference queue
212
performMaintenance();
214
OutputStream out = null;
218
file = createTempFile("cbc", ".class", true);
219
if(log.isTraceEnabled())
221
log.trace("adding resource at: " + name + " to file: " + file);
223
out = getFileOutputStream(file);
227
catch(java.io.IOException ex)
247
loadedResources.put(name, file);
252
public java.io.InputStream getResourceAsStream(String name)
254
// make sure we're OK on the reference queue
255
performMaintenance();
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())
261
log.trace("getResourceAsStream =>" + denormalized + " = " + file);
263
if(file != null && fileExists(file))
267
InputStream is = getFileInputStream(file);
268
return new java.io.BufferedInputStream(is);
272
log.debug("file doesn't exist", ex);
275
return super.getResourceAsStream(name);
278
public Class addClass(ClassBytes classBytes)
279
throws java.io.IOException
281
// make sure we're OK on the reference queue
282
performMaintenance();
285
String name = classBytes.getClassName();
286
if(loadedClasses.containsKey(name) == false)
288
byte buf[] = classBytes.getClassBytes();
289
boolean array = ClassUtil.isArrayClass(name);
290
String cn = (array) ? ClassUtil.getArrayClassPart(name) : name;
291
if(log.isTraceEnabled())
293
log.trace(" add class: " + name + ", array?" + array + ", using as: " + cn);
295
cl = defineClass(cn, buf, 0, buf.length);
297
addClassResource(cn, buf);
298
loadedClasses.put(cn, new MyRef(cn, cl));
304
* lookup a cached class and return null if not found
306
private Class lookupCachedClass(String cn)
309
MyRef ref = (MyRef) loadedClasses.get(cn);
312
// make sure we've not gotten cleared
313
cl = (Class) ref.get();
316
// oops, we've been cleared
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>.
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
335
protected Class findClass(String name) throws ClassNotFoundException
337
// make sure we're OK on the reference queue
338
performMaintenance();
340
boolean array = ClassUtil.isArrayClass(name);
341
String cn = (array) ? ClassUtil.getArrayClassPart(name) : name;
342
if(log.isTraceEnabled())
344
log.trace("++ loadClass: " + name + ", array?" + array + ", normalized: [" + cn + "]");
346
Class cl = lookupCachedClass(cn);
347
// search the mapped classes first
350
// search already loaded classes
351
cl = findLoadedClass(cn);
357
// we have to create an instance from the Class Part and return the
359
Object obj = java.lang.reflect.Array.newInstance(cl, 1);
360
return obj.getClass();
365
cl = loadFromNetwork(cn);
368
if(log.isTraceEnabled())
370
log.trace("Loaded " + cn + " can class is " + cl);
376
if(log.isTraceEnabled())
378
log.trace("++ findClass: " + name + " not found, throwing ClassNotFoundException");
380
throw new ClassNotFoundException(name);
383
private Class loadFromNetwork(String className)
385
Class loadedClass = null;
387
if(loaderClient != null)
389
String marshallerMethodName = "load_class";
390
Map metadata = new HashMap();
391
metadata.put("classname", className);
395
if(!loaderClient.isConnected())
397
loaderClient.connect();
399
log.debug("attempting to load from network: " + className);
400
Object obj = loaderClient.invoke(marshallerMethodName, metadata);
401
log.debug("loaded from network: " + obj);
405
if(obj instanceof ClassBytes)
407
ClassBytes classBytes = (ClassBytes) obj;
408
String name = classBytes.getClassName();
410
loadedClass = addClass(classBytes);
414
log.error("Can not load remote class bytes. Returned object (" + obj + ") is not ClassBytes.");
419
log.error("Can not load remote class bytes.");
422
catch(Throwable throwable)
424
log.error("Error loading remote class.", throwable);
429
log.trace("Remoting Client for ClassByteClassLoader is null. Can not load class remotely.");
435
static private File createTempFile(final String prefix, final String suffix, final boolean deleteOnExit) throws IOException
437
if (SecurityUtility.skipAccessControl())
439
File file = File.createTempFile(prefix, suffix);
440
if (deleteOnExit) file.deleteOnExit();
446
return (File)AccessController.doPrivileged( new PrivilegedExceptionAction()
448
public Object run() throws IOException
450
File file = File.createTempFile(prefix, suffix);
451
if (deleteOnExit) file.deleteOnExit();
456
catch (PrivilegedActionException e)
458
throw (IOException) e.getCause();
462
static private boolean fileExists(final File file)
467
if (SecurityUtility.skipAccessControl())
469
return file.exists();
472
return ((Boolean)AccessController.doPrivileged( new PrivilegedAction()
476
return new Boolean(file.exists());
481
static private FileInputStream getFileInputStream(final File file) throws FileNotFoundException
483
if (SecurityUtility.skipAccessControl())
485
return new FileInputStream(file);
490
return (FileInputStream)AccessController.doPrivileged( new PrivilegedExceptionAction()
492
public Object run() throws FileNotFoundException
494
return new FileInputStream(file);
498
catch (PrivilegedActionException e)
500
throw (FileNotFoundException) e.getCause();
504
static private FileOutputStream getFileOutputStream(final File file)
505
throws FileNotFoundException
507
if (SecurityUtility.skipAccessControl())
509
return new FileOutputStream(file);
514
return (FileOutputStream)AccessController.doPrivileged( new PrivilegedExceptionAction()
516
public Object run() throws FileNotFoundException
518
return new FileOutputStream(file);
522
catch (PrivilegedActionException e)
524
throw (FileNotFoundException) e.getCause();
528
static private ClassLoader getSystemClassLoaderPrivate()
530
if (SecurityUtility.skipAccessControl())
532
return ClassLoader.getSystemClassLoader();
535
return (ClassLoader)AccessController.doPrivileged( new PrivilegedAction()
539
return ClassLoader.getSystemClassLoader();