Home | History | Annotate | Download | only in scopedpool
      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 (at) jboss.org">Bill Burke</a>
     32  * @author <a href="adrian (at) jboss.com">Adrian Brock</a>
     33  * @author <a href="kabir.khan (at) 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      */
     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      */
     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      */
    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 
    111     protected ClassLoader getClassLoader0() {
    112        return (ClassLoader)classLoader.get();
    113     }
    114 
    115     /**
    116      * Close the class pool
    117      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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