Save This Page
Home » cglib-src-2.2 » net.sf.cglib.core » [javadoc | source]
    1   /*
    2    * Copyright 2003,2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    *  Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   package net.sf.cglib.core;
   17   
   18   import java.io;
   19   import java.util;
   20   import java.lang.ref;
   21   import org.objectweb.asm.ClassReader;
   22   import org.objectweb.asm.ClassVisitor;
   23   import org.objectweb.asm.ClassWriter;
   24   import org.objectweb.asm.Type;
   25   
   26   /**
   27    * Abstract class for all code-generating CGLIB utilities.
   28    * In addition to caching generated classes for performance, it provides hooks for
   29    * customizing the <code>ClassLoader</code>, name of the generated class, and transformations
   30    * applied before generation.
   31    */
   32   abstract public class AbstractClassGenerator
   33   implements ClassGenerator
   34   {
   35       private static final Object NAME_KEY = new Object();
   36       private static final ThreadLocal CURRENT = new ThreadLocal();
   37   
   38       private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE;
   39       private NamingPolicy namingPolicy = DefaultNamingPolicy.INSTANCE;
   40       private Source source;
   41       private ClassLoader classLoader;
   42       private String namePrefix;
   43       private Object key;
   44       private boolean useCache = true;
   45       private String className;
   46       private boolean attemptLoad;
   47   
   48       protected static class Source {
   49           String name;
   50           Map cache = new WeakHashMap();
   51           public Source(String name) {
   52               this.name = name;
   53           }
   54       }
   55   
   56       protected AbstractClassGenerator(Source source) {
   57           this.source = source;
   58       }
   59   
   60       protected void setNamePrefix(String namePrefix) {
   61           this.namePrefix = namePrefix;
   62       }
   63   
   64       final protected String getClassName() {
   65           if (className == null)
   66               className = getClassName(getClassLoader());
   67           return className;
   68       }
   69   
   70       private String getClassName(final ClassLoader loader) {
   71           final Set nameCache = getClassNameCache(loader);
   72           return namingPolicy.getClassName(namePrefix, source.name, key, new Predicate() {
   73               public boolean evaluate(Object arg) {
   74                   return nameCache.contains(arg);
   75               }
   76           });
   77       }
   78   
   79       private Set getClassNameCache(ClassLoader loader) {
   80           return (Set)((Map)source.cache.get(loader)).get(NAME_KEY);
   81       }
   82   
   83       /**
   84        * Set the <code>ClassLoader</code> in which the class will be generated.
   85        * Concrete subclasses of <code>AbstractClassGenerator</code> (such as <code>Enhancer</code>)
   86        * will try to choose an appropriate default if this is unset.
   87        * <p>
   88        * Classes are cached per-<code>ClassLoader</code> using a <code>WeakHashMap</code>, to allow
   89        * the generated classes to be removed when the associated loader is garbage collected.
   90        * @param classLoader the loader to generate the new class with, or null to use the default
   91        */
   92       public void setClassLoader(ClassLoader classLoader) {
   93           this.classLoader = classLoader;
   94       }
   95   
   96       /**
   97        * Override the default naming policy.
   98        * @see DefaultNamingPolicy
   99        * @param namingPolicy the custom policy, or null to use the default
  100        */
  101       public void setNamingPolicy(NamingPolicy namingPolicy) {
  102           if (namingPolicy == null)
  103               namingPolicy = DefaultNamingPolicy.INSTANCE;
  104           this.namingPolicy = namingPolicy;
  105       }
  106   
  107       /**
  108        * @see #setNamingPolicy
  109        */
  110       public NamingPolicy getNamingPolicy() {
  111           return namingPolicy;
  112       }
  113   
  114       /**
  115        * Whether use and update the static cache of generated classes
  116        * for a class with the same properties. Default is <code>true</code>.
  117        */
  118       public void setUseCache(boolean useCache) {
  119           this.useCache = useCache;
  120       }
  121   
  122       /**
  123        * @see #setUseCache
  124        */
  125       public boolean getUseCache() {
  126           return useCache;
  127       }
  128   
  129       /**
  130        * If set, CGLIB will attempt to load classes from the specified
  131        * <code>ClassLoader</code> before generating them. Because generated
  132        * class names are not guaranteed to be unique, the default is <code>false</code>.
  133        */
  134       public void setAttemptLoad(boolean attemptLoad) {
  135           this.attemptLoad = attemptLoad;
  136       }
  137   
  138       public boolean getAttemptLoad() {
  139           return attemptLoad;
  140       }
  141       
  142       /**
  143        * Set the strategy to use to create the bytecode from this generator.
  144        * By default an instance of {@see DefaultGeneratorStrategy} is used.
  145        */
  146       public void setStrategy(GeneratorStrategy strategy) {
  147           if (strategy == null)
  148               strategy = DefaultGeneratorStrategy.INSTANCE;
  149           this.strategy = strategy;
  150       }
  151   
  152       /**
  153        * @see #setStrategy
  154        */
  155       public GeneratorStrategy getStrategy() {
  156           return strategy;
  157       }
  158   
  159       /**
  160        * Used internally by CGLIB. Returns the <code>AbstractClassGenerator</code>
  161        * that is being used to generate a class in the current thread.
  162        */
  163       public static AbstractClassGenerator getCurrent() {
  164           return (AbstractClassGenerator)CURRENT.get();
  165       }
  166   
  167       public ClassLoader getClassLoader() {
  168           ClassLoader t = classLoader;
  169           if (t == null) {
  170               t = getDefaultClassLoader();
  171           }
  172           if (t == null) {
  173               t = getClass().getClassLoader();
  174           }
  175           if (t == null) {
  176               t = Thread.currentThread().getContextClassLoader();
  177           }
  178           if (t == null) {
  179               throw new IllegalStateException("Cannot determine classloader");
  180           }
  181           return t;
  182       }
  183   
  184       abstract protected ClassLoader getDefaultClassLoader();
  185   
  186       protected Object create(Object key) {
  187           try {
  188           	Class gen = null;
  189           	
  190               synchronized (source) {
  191                   ClassLoader loader = getClassLoader();
  192                   Map cache2 = null;
  193                   cache2 = (Map)source.cache.get(loader);
  194                   if (cache2 == null) {
  195                       cache2 = new HashMap();
  196                       cache2.put(NAME_KEY, new HashSet());
  197                       source.cache.put(loader, cache2);
  198                   } else if (useCache) {
  199                       Reference ref = (Reference)cache2.get(key);
  200                       gen = (Class) (( ref == null ) ? null : ref.get()); 
  201                   }
  202                   if (gen == null) {
  203                       Object save = CURRENT.get();
  204                       CURRENT.set(this);
  205                       try {
  206                           this.key = key;
  207                           
  208                           if (attemptLoad) {
  209                               try {
  210                                   gen = loader.loadClass(getClassName());
  211                               } catch (ClassNotFoundException e) {
  212                                   // ignore
  213                               }
  214                           }
  215                           if (gen == null) {
  216                               byte[] b = strategy.generate(this);
  217                               String className = ClassNameReader.getClassName(new ClassReader(b));
  218                               getClassNameCache(loader).add(className);
  219                               gen = ReflectUtils.defineClass(className, b, loader);
  220                           }
  221                          
  222                           if (useCache) {
  223                               cache2.put(key, new WeakReference(gen));
  224                           }
  225                           return firstInstance(gen);
  226                       } finally {
  227                           CURRENT.set(save);
  228                       }
  229                   }
  230               }
  231               return firstInstance(gen);
  232           } catch (RuntimeException e) {
  233               throw e;
  234           } catch (Error e) {
  235               throw e;
  236           } catch (Exception e) {
  237               throw new CodeGenerationException(e);
  238           }
  239       }
  240   
  241       abstract protected Object firstInstance(Class type) throws Exception;
  242       abstract protected Object nextInstance(Object instance) throws Exception;
  243   }

Save This Page
Home » cglib-src-2.2 » net.sf.cglib.core » [javadoc | source]