You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ScopedClassPool.java 9.0KB

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