1. /*
  2. * @(#)JDKClassLoader.java 1.23 04/04/07
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * Licensed Materials - Property of IBM
  9. * RMI-IIOP v1.0
  10. * Copyright IBM Corp. 1998 1999 All Rights Reserved
  11. *
  12. * US Government Users Restricted Rights - Use, duplication or
  13. * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  14. */
  15. package com.sun.corba.se.impl.util;
  16. import sun.corba.Bridge ;
  17. import java.util.Map ;
  18. import java.util.WeakHashMap ;
  19. import java.util.Collections ;
  20. import java.security.AccessController ;
  21. import java.security.PrivilegedAction ;
  22. /**
  23. * Utility method for crawling call stack to load class
  24. */
  25. class JDKClassLoader {
  26. private static final JDKClassLoaderCache classCache
  27. = new JDKClassLoaderCache();
  28. private static final Bridge bridge =
  29. (Bridge)AccessController.doPrivileged(
  30. new PrivilegedAction() {
  31. public Object run() {
  32. return Bridge.get() ;
  33. }
  34. }
  35. ) ;
  36. static Class loadClass(Class aClass, String className)
  37. throws ClassNotFoundException {
  38. // Maintain the same error semantics as Class.forName()
  39. if (className == null) {
  40. throw new NullPointerException();
  41. }
  42. if (className.length() == 0) {
  43. throw new ClassNotFoundException();
  44. }
  45. // It would be nice to bypass JDKClassLoader's attempts completely
  46. // if it's known that the latest user defined ClassLoader will
  47. // fail.
  48. //
  49. // Otherwise, we end up calling Class.forName here as well as in
  50. // the next step in JDKBridge. That can take a long time depending
  51. // on the length of the classpath.
  52. // Note: Looking at the only place in JDKBridge where this code
  53. // is invoked, it is clear that aClass will always be null.
  54. ClassLoader loader;
  55. if (aClass != null) {
  56. loader = aClass.getClassLoader();
  57. } else {
  58. loader = bridge.getLatestUserDefinedLoader();
  59. }
  60. // See createKey for a description of what's involved
  61. Object key = classCache.createKey(className, loader);
  62. if (classCache.knownToFail(key)) {
  63. throw new ClassNotFoundException(className);
  64. } else {
  65. try {
  66. // Loading this class with the call stack
  67. // loader isn't known to fail, so try
  68. // to load it.
  69. return Class.forName(className, false, loader);
  70. } catch(ClassNotFoundException cnfe) {
  71. // Record that we failed to find the class
  72. // with this particular loader. This way, we won't
  73. // waste time looking with this loader, again.
  74. classCache.recordFailure(key);
  75. throw cnfe;
  76. }
  77. }
  78. }
  79. /**
  80. * Private cache implementation specific to JDKClassLoader.
  81. */
  82. private static class JDKClassLoaderCache
  83. {
  84. // JDKClassLoader couldn't find the class with the located
  85. // ClassLoader. Note this in our cache so JDKClassLoader
  86. // can abort early next time.
  87. public final void recordFailure(Object key) {
  88. cache.put(key, JDKClassLoaderCache.KNOWN_TO_FAIL);
  89. }
  90. // Factory for a key (CacheKey is an implementation detail
  91. // of JDKClassLoaderCache).
  92. //
  93. // A key currently consists of the class name as well as
  94. // the latest user defined class loader, so it's fairly
  95. // expensive to create.
  96. public final Object createKey(String className, ClassLoader latestLoader) {
  97. return new CacheKey(className, latestLoader);
  98. }
  99. // Determine whether or not this combination of class name
  100. // and ClassLoader is known to fail.
  101. public final boolean knownToFail(Object key) {
  102. return cache.get(key) == JDKClassLoaderCache.KNOWN_TO_FAIL;
  103. }
  104. // Synchronized WeakHashMap
  105. private final Map cache
  106. = Collections.synchronizedMap(new WeakHashMap());
  107. // Cache result used to mark the caches when there is
  108. // no way JDKClassLoader could succeed with the given
  109. // key
  110. private static final Object KNOWN_TO_FAIL = new Object();
  111. // Key consisting of the class name and the latest
  112. // user defined class loader
  113. private static class CacheKey
  114. {
  115. String className;
  116. ClassLoader loader;
  117. public CacheKey(String className, ClassLoader loader) {
  118. this.className = className;
  119. this.loader = loader;
  120. }
  121. // Try to incorporate both class name and loader
  122. // into the hashcode
  123. public int hashCode() {
  124. if (loader == null)
  125. return className.hashCode();
  126. else
  127. return className.hashCode() ^ loader.hashCode();
  128. }
  129. public boolean equals(Object obj) {
  130. try {
  131. // WeakHashMap may compare null keys
  132. if (obj == null)
  133. return false;
  134. CacheKey other = (CacheKey)obj;
  135. // I've made a decision to actually compare the
  136. // loader references. I don't want a case when
  137. // two loader instances override their equals
  138. // methods and only compare code base.
  139. //
  140. // This way, at worst, our performance will
  141. // be slower, but we know we'll do the correct
  142. // loading.
  143. return (className.equals(other.className) &&
  144. loader == other.loader);
  145. } catch (ClassCastException cce) {
  146. return false;
  147. }
  148. }
  149. }
  150. }
  151. }