1 /* 2 * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 /* 26 * Licensed Materials - Property of IBM 27 * RMI-IIOP v1.0 28 * Copyright IBM Corp. 1998 1999 All Rights Reserved 29 * 30 */ 31 32 package com.sun.corba.se.impl.util; 33 34 import sun.corba.Bridge ; 35 36 import java.util.Map ; 37 import java.util.WeakHashMap ; 38 import java.util.Collections ; 39 40 import java.security.AccessController ; 41 import java.security.PrivilegedAction ; 42 43 /** 44 * Utility method for crawling call stack to load class 45 */ 46 class JDKClassLoader { 47 48 private static final JDKClassLoaderCache classCache 49 = new JDKClassLoaderCache(); 50 51 private static final Bridge bridge = 52 (Bridge)AccessController.doPrivileged( 53 new PrivilegedAction() { 54 public Object run() { 55 return Bridge.get() ; 56 } 57 } 58 ) ; 59 60 static Class loadClass(Class aClass, String className) 61 throws ClassNotFoundException { 62 63 // Maintain the same error semantics as Class.forName() 64 if (className == null) { 65 throw new NullPointerException(); 66 } 67 if (className.length() == 0) { 68 throw new ClassNotFoundException(); 69 } 70 71 // It would be nice to bypass JDKClassLoader's attempts completely 72 // if it's known that the latest user defined ClassLoader will 73 // fail. 74 // 75 // Otherwise, we end up calling Class.forName here as well as in 76 // the next step in JDKBridge. That can take a long time depending 77 // on the length of the classpath. 78 79 // Note: Looking at the only place in JDKBridge where this code 80 // is invoked, it is clear that aClass will always be null. 81 ClassLoader loader; 82 if (aClass != null) { 83 loader = aClass.getClassLoader(); 84 } else { 85 loader = bridge.getLatestUserDefinedLoader(); 86 } 87 // See createKey for a description of what's involved 88 Object key = classCache.createKey(className, loader); 89 90 if (classCache.knownToFail(key)) { 91 throw new ClassNotFoundException(className); 92 } else { 93 try { 94 // Loading this class with the call stack 95 // loader isn't known to fail, so try 96 // to load it. 97 return Class.forName(className, false, loader); 98 } catch(ClassNotFoundException cnfe) { 99 // Record that we failed to find the class 100 // with this particular loader. This way, we won't 101 // waste time looking with this loader, again. 102 classCache.recordFailure(key); 103 throw cnfe; 104 } 105 } 106 } 107 108 /** 109 * Private cache implementation specific to JDKClassLoader. 110 */ 111 private static class JDKClassLoaderCache 112 { 113 // JDKClassLoader couldn't find the class with the located 114 // ClassLoader. Note this in our cache so JDKClassLoader 115 // can abort early next time. 116 public final void recordFailure(Object key) { 117 cache.put(key, JDKClassLoaderCache.KNOWN_TO_FAIL); 118 } 119 120 // Factory for a key (CacheKey is an implementation detail 121 // of JDKClassLoaderCache). 122 // 123 // A key currently consists of the class name as well as 124 // the latest user defined class loader, so it's fairly 125 // expensive to create. 126 public final Object createKey(String className, ClassLoader latestLoader) { 127 return new CacheKey(className, latestLoader); 128 } 129 130 // Determine whether or not this combination of class name 131 // and ClassLoader is known to fail. 132 public final boolean knownToFail(Object key) { 133 return cache.get(key) == JDKClassLoaderCache.KNOWN_TO_FAIL; 134 } 135 136 // Synchronized WeakHashMap 137 private final Map cache 138 = Collections.synchronizedMap(new WeakHashMap()); 139 140 // Cache result used to mark the caches when there is 141 // no way JDKClassLoader could succeed with the given 142 // key 143 private static final Object KNOWN_TO_FAIL = new Object(); 144 145 // Key consisting of the class name and the latest 146 // user defined class loader 147 private static class CacheKey 148 { 149 String className; 150 ClassLoader loader; 151 152 public CacheKey(String className, ClassLoader loader) { 153 this.className = className; 154 this.loader = loader; 155 } 156 157 // Try to incorporate both class name and loader 158 // into the hashcode 159 public int hashCode() { 160 if (loader == null) 161 return className.hashCode(); 162 else 163 return className.hashCode() ^ loader.hashCode(); 164 } 165 166 public boolean equals(Object obj) { 167 try { 168 169 // WeakHashMap may compare null keys 170 if (obj == null) 171 return false; 172 173 CacheKey other = (CacheKey)obj; 174 175 // I've made a decision to actually compare the 176 // loader references. I don't want a case when 177 // two loader instances override their equals 178 // methods and only compare code base. 179 // 180 // This way, at worst, our performance will 181 // be slower, but we know we'll do the correct 182 // loading. 183 return (className.equals(other.className) && 184 loader == other.loader); 185 186 } catch (ClassCastException cce) { 187 return false; 188 } 189 } 190 } 191 } 192 }