• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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