1 17 package org.apache.geronimo.kernel.config; 18 19 import java.beans.Introspector ; 20 import java.io.IOException ; 21 import java.io.ObjectInputStream ; 22 import java.io.ObjectOutputStream ; 23 import java.io.ObjectStreamClass ; 24 import java.lang.reflect.Field ; 25 import java.net.URL ; 26 import java.net.URLClassLoader ; 27 import java.net.URLStreamHandlerFactory ; 28 import java.util.ArrayList ; 29 import java.util.Collection ; 30 import java.util.Collections ; 31 import java.util.Enumeration ; 32 import java.util.List ; 33 import java.util.Map ; 34 35 import org.apache.commons.logging.LogFactory; 36 import org.apache.geronimo.kernel.repository.Artifact; 37 38 47 public class MultiParentClassLoader extends URLClassLoader { 48 private final Artifact id; 49 private final ClassLoader [] parents; 50 private final boolean inverseClassLoading; 51 private final String [] hiddenClasses; 52 private final String [] nonOverridableClasses; 53 private final String [] hiddenResources; 54 private final String [] nonOverridableResources; 55 private boolean destroyed = false; 56 57 63 public MultiParentClassLoader(Artifact id, URL [] urls) { 64 super(urls); 65 this.id = id; 66 parents = new ClassLoader []{ClassLoader.getSystemClassLoader()}; 67 inverseClassLoading = false; 68 hiddenClasses = new String [0]; 69 nonOverridableClasses = new String [0]; 70 hiddenResources = new String [0]; 71 nonOverridableResources = new String [0]; 72 } 73 74 75 82 public MultiParentClassLoader(Artifact id, URL [] urls, ClassLoader parent) { 83 this(id, urls, new ClassLoader []{parent}); 84 } 85 86 public MultiParentClassLoader(Artifact id, URL [] urls, ClassLoader parent, boolean inverseClassLoading, String [] hiddenClasses, String [] nonOverridableClasses) { 87 this(id, urls, new ClassLoader []{parent}, inverseClassLoading, hiddenClasses, nonOverridableClasses); 88 } 89 90 99 public MultiParentClassLoader(Artifact id, URL [] urls, ClassLoader parent, URLStreamHandlerFactory factory) { 100 this(id, urls, new ClassLoader []{parent}, factory); 101 } 102 103 110 public MultiParentClassLoader(Artifact id, URL [] urls, ClassLoader [] parents) { 111 super(urls); 112 this.id = id; 113 this.parents = copyParents(parents); 114 inverseClassLoading = false; 115 hiddenClasses = new String [0]; 116 nonOverridableClasses = new String [0]; 117 hiddenResources = new String [0]; 118 nonOverridableResources = new String [0]; 119 } 120 121 public MultiParentClassLoader(Artifact id, URL [] urls, ClassLoader [] parents, boolean inverseClassLoading, Collection hiddenClasses, Collection nonOverridableClasses) { 122 this(id, urls, parents, inverseClassLoading, (String []) hiddenClasses.toArray(new String [hiddenClasses.size()]), (String []) nonOverridableClasses.toArray(new String [nonOverridableClasses.size()])); 123 } 124 125 public MultiParentClassLoader(Artifact id, URL [] urls, ClassLoader [] parents, boolean inverseClassLoading, String [] hiddenClasses, String [] nonOverridableClasses) { 126 super(urls); 127 this.id = id; 128 this.parents = copyParents(parents); 129 this.inverseClassLoading = inverseClassLoading; 130 this.hiddenClasses = hiddenClasses; 131 this.nonOverridableClasses = nonOverridableClasses; 132 hiddenResources = toResources(hiddenClasses); 133 nonOverridableResources = toResources(nonOverridableClasses); 134 } 135 136 public MultiParentClassLoader(MultiParentClassLoader source) { 137 this(source.id, source.getURLs(), deepCopyParents(source.parents), source.inverseClassLoading, source.hiddenClasses, source.nonOverridableClasses); 138 } 139 140 static ClassLoader copy(ClassLoader source) { 141 if (source instanceof MultiParentClassLoader) { 142 return new MultiParentClassLoader((MultiParentClassLoader) source); 143 } else if (source instanceof URLClassLoader ) { 144 return new URLClassLoader (((URLClassLoader )source).getURLs(), source.getParent()); 145 } else { 146 return new URLClassLoader (new URL [0], source); 147 } 148 } 149 150 ClassLoader copy() { 151 return MultiParentClassLoader.copy(this); 152 } 153 154 private String [] toResources(String [] classes) { 155 String [] resources = new String [classes.length]; 156 for (int i = 0; i < classes.length; i++) { 157 String className = classes[i]; 158 resources[i] = className.replace('.', '/'); 159 } 160 return resources; 161 } 162 163 172 public MultiParentClassLoader(Artifact id, URL [] urls, ClassLoader [] parents, URLStreamHandlerFactory factory) { 173 super(urls, null, factory); 174 this.id = id; 175 this.parents = copyParents(parents); 176 inverseClassLoading = false; 177 hiddenClasses = new String [0]; 178 nonOverridableClasses = new String [0]; 179 hiddenResources = new String [0]; 180 nonOverridableResources = new String [0]; 181 } 182 183 private static ClassLoader [] copyParents(ClassLoader [] parents) { 184 ClassLoader [] newParentsArray = new ClassLoader [parents.length]; 185 for (int i = 0; i < parents.length; i++) { 186 ClassLoader parent = parents[i]; 187 if (parent == null) { 188 throw new NullPointerException ("parent[" + i + "] is null"); 189 } 190 newParentsArray[i] = parent; 191 } 192 return newParentsArray; 193 } 194 195 private static ClassLoader [] deepCopyParents(ClassLoader [] parents) { 196 ClassLoader [] newParentsArray = new ClassLoader [parents.length]; 197 for (int i = 0; i < parents.length; i++) { 198 ClassLoader parent = parents[i]; 199 if (parent == null) { 200 throw new NullPointerException ("parent[" + i + "] is null"); 201 } 202 if (parent instanceof MultiParentClassLoader) { 203 parent = ((MultiParentClassLoader)parent).copy(); 204 } 205 newParentsArray[i] = parent; 206 } 207 return newParentsArray; 208 } 209 210 215 public Artifact getId() { 216 return id; 217 } 218 219 224 public ClassLoader [] getParents() { 225 return parents; 226 } 227 228 public void addURL(URL url) { 229 super.addURL(url); 231 } 232 233 protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { 234 Class cachedClass = findLoadedClass(name); 238 if (cachedClass != null) { 239 return resolveClass(cachedClass, resolve); 240 } 241 242 249 if ( name.startsWith("java.") || 250 name.equals("boolean") || 251 name.equals("int") || 252 name.equals("double") || 253 name.equals("long")) { 254 Class clazz = ClassLoader.getSystemClassLoader().loadClass(name); 255 return resolveClass(clazz, resolve); 256 } 257 258 if (inverseClassLoading && !isDestroyed() && !isNonOverridableClass(name)) { 262 try { 263 Class clazz = findClass(name); 264 return resolveClass(clazz, resolve); 265 } catch (ClassNotFoundException ignored) { 266 } 267 } 268 269 if (!isHiddenClass(name)) { 273 for (int i = 0; i < parents.length; i++) { 274 ClassLoader parent = parents[i]; 275 try { 276 Class clazz = parent.loadClass(name); 277 return resolveClass(clazz, resolve); 278 } catch (ClassNotFoundException ignored) { 279 } 281 } 282 } 283 284 if (!isDestroyed()) { 291 try { 292 Class clazz = findClass(name); 293 return resolveClass(clazz, resolve); 294 } catch (ClassNotFoundException ignored) { 295 } 296 } 297 298 throw new ClassNotFoundException (name + " in classloader " + id); 299 } 300 301 private boolean isNonOverridableClass(String name) { 302 for (int i = 0; i < nonOverridableClasses.length; i++) { 303 if (name.startsWith(nonOverridableClasses[i])) { 304 return true; 305 } 306 } 307 return false; 308 } 309 310 private boolean isHiddenClass(String name) { 311 for (int i = 0; i < hiddenClasses.length; i++) { 312 if (name.startsWith(hiddenClasses[i])) { 313 return true; 314 } 315 } 316 return false; 317 } 318 319 private Class resolveClass(Class clazz, boolean resolve) { 320 if (resolve) { 321 resolveClass(clazz); 322 } 323 return clazz; 324 } 325 326 public URL getResource(String name) { 327 if (isDestroyed()) { 328 return null; 329 } 330 331 if (inverseClassLoading && !isDestroyed() && !isNonOverridableResource(name)) { 335 URL url = findResource(name); 336 if (url != null) { 337 return url; 338 } 339 } 340 341 if (!isHiddenResource(name)) { 345 for (int i = 0; i < parents.length; i++) { 346 ClassLoader parent = parents[i]; 347 URL url = parent.getResource(name); 348 if (url != null) { 349 return url; 350 } 351 } 352 } 353 354 if (!isDestroyed()) { 361 return findResource(name); 363 } 364 365 return null; 366 } 367 368 public Enumeration findResources(String name) throws IOException { 369 if (isDestroyed()) { 370 return Collections.enumeration(Collections.EMPTY_SET); 371 } 372 373 List resources = new ArrayList (); 374 375 if (inverseClassLoading && !isDestroyed()) { 379 List myResources = Collections.list(super.findResources(name)); 380 resources.addAll(myResources); 381 } 382 383 for (int i = 0; i < parents.length; i++) { 387 ClassLoader parent = parents[i]; 388 List parentResources = Collections.list(parent.getResources(name)); 389 resources.addAll(parentResources); 390 } 391 392 if (!inverseClassLoading && !isDestroyed()) { 396 List myResources = Collections.list(super.findResources(name)); 397 resources.addAll(myResources); 398 } 399 400 return Collections.enumeration(resources); 401 } 402 403 private boolean isNonOverridableResource(String name) { 404 for (int i = 0; i < nonOverridableResources.length; i++) { 405 if (name.startsWith(nonOverridableResources[i])) { 406 return true; 407 } 408 } 409 return false; 410 } 411 412 private boolean isHiddenResource(String name) { 413 for (int i = 0; i < hiddenResources.length; i++) { 414 if (name.startsWith(hiddenResources[i])) { 415 return true; 416 } 417 } 418 return false; 419 } 420 421 public String toString() { 422 return "[" + getClass().getName() + " id=" + id + "]"; 423 } 424 425 public synchronized boolean isDestroyed() { 426 return destroyed; 427 } 428 429 public void destroy() { 430 synchronized(this) { 431 if (destroyed) return; 432 destroyed = true; 433 } 434 435 LogFactory.release(this); 436 clearSoftCache(ObjectInputStream .class, "subclassAudits"); 437 clearSoftCache(ObjectOutputStream .class, "subclassAudits"); 438 clearSoftCache(ObjectStreamClass .class, "localDescs"); 439 clearSoftCache(ObjectStreamClass .class, "reflectors"); 440 441 Introspector.flushCaches(); 445 } 446 447 private static final Object lock = new Object (); 448 private static boolean clearSoftCacheFailed = false; 449 450 private static void clearSoftCache(Class clazz, String fieldName) { 451 Map cache = null; 452 try { 453 Field f = clazz.getDeclaredField(fieldName); 454 f.setAccessible(true); 455 cache = (Map ) f.get(null); 456 } catch (Throwable e) { 457 synchronized (lock) { 458 if (!clearSoftCacheFailed) { 459 clearSoftCacheFailed = true; 460 LogFactory.getLog(MultiParentClassLoader.class).debug("Unable to clear SoftCache field " + fieldName + " in class " + clazz); 461 } 462 } 463 } 464 465 if (cache != null) { 466 synchronized (cache) { 467 cache.clear(); 468 } 469 } 470 } 471 472 } 473 | Popular Tags |