1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later. 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 */ 15 16 package javassist.scopedpool; 17 18 import java.lang.ref.WeakReference; 19 import java.security.ProtectionDomain; 20 import java.util.Iterator; 21 import java.util.Map; 22 import javassist.CannotCompileException; 23 import javassist.ClassPool; 24 import javassist.CtClass; 25 import javassist.LoaderClassPath; 26 import javassist.NotFoundException; 27 28 /** 29 * A scoped class pool. 30 * 31 * @author <a href="mailto:bill@jboss.org">Bill Burke</a> 32 * @author <a href="adrian@jboss.com">Adrian Brock</a> 33 * @author <a href="kabir.khan@jboss.com">Kabir Khan</a> 34 * @version $Revision: 1.8 $ 35 */ 36 public class ScopedClassPool extends ClassPool { 37 protected ScopedClassPoolRepository repository; 38 39 protected WeakReference classLoader; 40 41 protected LoaderClassPath classPath; 42 43 protected SoftValueHashMap softcache = new SoftValueHashMap(); 44 45 boolean isBootstrapCl = true; 46 47 static { 48 ClassPool.doPruning = false; 49 ClassPool.releaseUnmodifiedClassFile = false; 50 } 51 52 /** 53 * Create a new ScopedClassPool. 54 * 55 * @param cl 56 * the classloader 57 * @param src 58 * the original class pool 59 * @param repository 60 * the repository 61 *@deprecated 62 */ ScopedClassPool(ClassLoader cl, ClassPool src, ScopedClassPoolRepository repository)63 protected ScopedClassPool(ClassLoader cl, ClassPool src, 64 ScopedClassPoolRepository repository) { 65 this(cl, src, repository, false); 66 } 67 68 /** 69 * Create a new ScopedClassPool. 70 * 71 * @param cl 72 * the classloader 73 * @param src 74 * the original class pool 75 * @param repository 76 * the repository 77 * @param isTemp 78 * Whether this is a temporary pool used to resolve references 79 */ ScopedClassPool(ClassLoader cl, ClassPool src, ScopedClassPoolRepository repository, boolean isTemp)80 protected ScopedClassPool(ClassLoader cl, ClassPool src, ScopedClassPoolRepository repository, boolean isTemp) 81 { 82 super(src); 83 this.repository = repository; 84 this.classLoader = new WeakReference(cl); 85 if (cl != null) { 86 classPath = new LoaderClassPath(cl); 87 this.insertClassPath(classPath); 88 } 89 childFirstLookup = true; 90 if (!isTemp && cl == null) 91 { 92 isBootstrapCl = true; 93 } 94 } 95 96 /** 97 * Get the class loader 98 * 99 * @return the class loader 100 */ getClassLoader()101 public ClassLoader getClassLoader() { 102 ClassLoader cl = getClassLoader0(); 103 if (cl == null && !isBootstrapCl) 104 { 105 throw new IllegalStateException( 106 "ClassLoader has been garbage collected"); 107 } 108 return cl; 109 } 110 getClassLoader0()111 protected ClassLoader getClassLoader0() { 112 return (ClassLoader)classLoader.get(); 113 } 114 115 /** 116 * Close the class pool 117 */ close()118 public void close() { 119 this.removeClassPath(classPath); 120 classPath.close(); 121 classes.clear(); 122 softcache.clear(); 123 } 124 125 /** 126 * Flush a class 127 * 128 * @param classname 129 * the class to flush 130 */ flushClass(String classname)131 public synchronized void flushClass(String classname) { 132 classes.remove(classname); 133 softcache.remove(classname); 134 } 135 136 /** 137 * Soften a class 138 * 139 * @param clazz 140 * the class 141 */ soften(CtClass clazz)142 public synchronized void soften(CtClass clazz) { 143 if (repository.isPrune()) 144 clazz.prune(); 145 classes.remove(clazz.getName()); 146 softcache.put(clazz.getName(), clazz); 147 } 148 149 /** 150 * Whether the classloader is loader 151 * 152 * @return false always 153 */ isUnloadedClassLoader()154 public boolean isUnloadedClassLoader() { 155 return false; 156 } 157 158 /** 159 * Get the cached class 160 * 161 * @param classname 162 * the class name 163 * @return the class 164 */ getCached(String classname)165 protected CtClass getCached(String classname) { 166 CtClass clazz = getCachedLocally(classname); 167 if (clazz == null) { 168 boolean isLocal = false; 169 170 ClassLoader dcl = getClassLoader0(); 171 if (dcl != null) { 172 final int lastIndex = classname.lastIndexOf('$'); 173 String classResourceName = null; 174 if (lastIndex < 0) { 175 classResourceName = classname.replaceAll("[\\.]", "/") 176 + ".class"; 177 } 178 else { 179 classResourceName = classname.substring(0, lastIndex) 180 .replaceAll("[\\.]", "/") 181 + classname.substring(lastIndex) + ".class"; 182 } 183 184 isLocal = dcl.getResource(classResourceName) != null; 185 } 186 187 if (!isLocal) { 188 Map registeredCLs = repository.getRegisteredCLs(); 189 synchronized (registeredCLs) { 190 Iterator it = registeredCLs.values().iterator(); 191 while (it.hasNext()) { 192 ScopedClassPool pool = (ScopedClassPool)it.next(); 193 if (pool.isUnloadedClassLoader()) { 194 repository.unregisterClassLoader(pool 195 .getClassLoader()); 196 continue; 197 } 198 199 clazz = pool.getCachedLocally(classname); 200 if (clazz != null) { 201 return clazz; 202 } 203 } 204 } 205 } 206 } 207 // *NOTE* NEED TO TEST WHEN SUPERCLASS IS IN ANOTHER UCL!!!!!! 208 return clazz; 209 } 210 211 /** 212 * Cache a class 213 * 214 * @param classname 215 * the class name 216 * @param c 217 * the ctClass 218 * @param dynamic 219 * whether the class is dynamically generated 220 */ cacheCtClass(String classname, CtClass c, boolean dynamic)221 protected void cacheCtClass(String classname, CtClass c, boolean dynamic) { 222 if (dynamic) { 223 super.cacheCtClass(classname, c, dynamic); 224 } 225 else { 226 if (repository.isPrune()) 227 c.prune(); 228 softcache.put(classname, c); 229 } 230 } 231 232 /** 233 * Lock a class into the cache 234 * 235 * @param c 236 * the class 237 */ lockInCache(CtClass c)238 public void lockInCache(CtClass c) { 239 super.cacheCtClass(c.getName(), c, false); 240 } 241 242 /** 243 * Whether the class is cached in this pooled 244 * 245 * @param classname 246 * the class name 247 * @return the cached class 248 */ getCachedLocally(String classname)249 protected CtClass getCachedLocally(String classname) { 250 CtClass cached = (CtClass)classes.get(classname); 251 if (cached != null) 252 return cached; 253 synchronized (softcache) { 254 return (CtClass)softcache.get(classname); 255 } 256 } 257 258 /** 259 * Get any local copy of the class 260 * 261 * @param classname 262 * the class name 263 * @return the class 264 * @throws NotFoundException 265 * when the class is not found 266 */ getLocally(String classname)267 public synchronized CtClass getLocally(String classname) 268 throws NotFoundException { 269 softcache.remove(classname); 270 CtClass clazz = (CtClass)classes.get(classname); 271 if (clazz == null) { 272 clazz = createCtClass(classname, true); 273 if (clazz == null) 274 throw new NotFoundException(classname); 275 super.cacheCtClass(classname, clazz, false); 276 } 277 278 return clazz; 279 } 280 281 /** 282 * Convert a javassist class to a java class 283 * 284 * @param ct 285 * the javassist class 286 * @param loader 287 * the loader 288 * @throws CannotCompileException 289 * for any error 290 */ toClass(CtClass ct, ClassLoader loader, ProtectionDomain domain)291 public Class toClass(CtClass ct, ClassLoader loader, ProtectionDomain domain) 292 throws CannotCompileException { 293 // We need to pass up the classloader stored in this pool, as the 294 // default implementation uses the Thread context cl. 295 // In the case of JSP's in Tomcat, 296 // org.apache.jasper.servlet.JasperLoader will be stored here, while 297 // it's parent 298 // org.jboss.web.tomcat.tc5.WebCtxLoader$ENCLoader is used as the Thread 299 // context cl. The invocation class needs to 300 // be generated in the JasperLoader classloader since in the case of 301 // method invocations, the package name will be 302 // the same as for the class generated from the jsp, i.e. 303 // org.apache.jsp. For classes belonging to org.apache.jsp, 304 // JasperLoader does NOT delegate to its parent if it cannot find them. 305 lockInCache(ct); 306 return super.toClass(ct, getClassLoader0(), domain); 307 } 308 } 309