View Javadoc
1 /* 2 * The Apache Software License, Version 1.1 3 * 4 * Copyright (c) 2002 The Apache Software Foundation. All rights 5 * reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * 3. The end-user documentation included with the redistribution, 20 * if any, must include the following acknowledgment: 21 * "This product includes software developed by the 22 * Apache Software Foundation (http://www.apache.org/)." 23 * Alternately, this acknowledgment may appear in the software itself, 24 * if and wherever such third-party acknowledgments normally appear. 25 * 26 * 4. The names "Apache" and "Apache Software Foundation" must 27 * not be used to endorse or promote products derived from this 28 * software without prior written permission. For written 29 * permission, please contact apache@apache.org. 30 * 31 * 5. Products derived from this software may not be called "Apache", 32 * nor may "Apache" appear in their name, without prior written 33 * permission of the Apache Software Foundation. 34 * 35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46 * SUCH DAMAGE. 47 * ==================================================================== 48 * 49 * This software consists of voluntary contributions made by many 50 * individuals on behalf of the Apache Software Foundation. For more 51 * information on the Apache Software Foundation, please see 52 * <http://www.apache.org/>;. 53 */ 54 package net.sf.cglib.core; 55 56 import java.io.*; 57 import java.lang.reflect.*; 58 import java.util.*; 59 import org.objectweb.asm.ClassReader; 60 import org.objectweb.asm.ClassVisitor; 61 import org.objectweb.asm.ClassWriter; 62 import org.objectweb.asm.Type; 63 64 /*** 65 * Abstract class for all code-generating CGLIB utilities. 66 * In addition to caching generated classes for performance, it provides hooks for 67 * customizing the <code>ClassLoader</code>, name of the generated class, and transformations 68 * applied before generation. 69 */ 70 abstract public class AbstractClassGenerator 71 implements ClassGenerator 72 { 73 private static final Object NAME_KEY = new Object(); 74 75 private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE; 76 private NamingPolicy namingPolicy; 77 private Source source; 78 private ClassLoader classLoader; 79 private String namePrefix; 80 private Object key; 81 private boolean useCache = true; 82 83 protected static class Source { 84 String name; 85 Map cache = new WeakHashMap(); 86 public Source(String name) { 87 this.name = name; 88 } 89 } 90 91 protected AbstractClassGenerator(Source source) { 92 this.source = source; 93 } 94 95 protected void setNamePrefix(String namePrefix) { 96 this.namePrefix = namePrefix; 97 } 98 99 final protected String getClassName() { 100 return getClassName(getClassLoader()); 101 } 102 103 private String getClassName(ClassLoader loader) { 104 NamingPolicy np = (namingPolicy != null) ? namingPolicy : DefaultNamingPolicy.INSTANCE; 105 final Set nameCache = getClassNameCache(loader); 106 return np.getClassName(namePrefix, source.name, key, new Predicate() { 107 public boolean evaluate(Object arg) { 108 return nameCache.contains(arg); 109 } 110 }); 111 } 112 113 private Set getClassNameCache(ClassLoader loader) { 114 return (Set)((Map)source.cache.get(loader)).get(NAME_KEY); 115 } 116 117 /*** 118 * Set the <code>ClassLoader</code> in which the class will be generated. 119 * Concrete subclasses of <code>AbstractClassGenerator</code> (such as <code>Enhancer</code>) 120 * will try to choose an appropriate default if this is unset. 121 * <p> 122 * Classes are cached per-<code>ClassLoader</code> using a <code>WeakHashMap</code>, to allow 123 * the generated classes to be removed when the associated loader is garbage collected. 124 * @param classLoader the loader to generate the new class with, or null to use the default 125 */ 126 public void setClassLoader(ClassLoader classLoader) { 127 this.classLoader = classLoader; 128 } 129 130 /*** 131 * Override the default naming policy. 132 * @see DefaultNamingPolicy 133 * @param namingPolicy the custom policy, or null to use the default 134 */ 135 public void setNamingPolicy(NamingPolicy namingPolicy) { 136 this.namingPolicy = namingPolicy; 137 } 138 139 /*** 140 * Whether use and update the static cache of generated classes 141 * for a class with the same properties. Default is <code>true</code>. 142 */ 143 public void setUseCache(boolean useCache) { 144 this.useCache = useCache; 145 } 146 147 /*** 148 * Set the strategy to use to create the bytecode from this generator. 149 * By default an instance of {@see DefaultGeneratorStrategy} is used. 150 */ 151 public void setStrategy(GeneratorStrategy strategy) { 152 this.strategy = strategy; 153 } 154 155 // TODO: pluggable policy? 156 protected ClassLoader getClassLoader() { 157 ClassLoader t = classLoader; 158 if (t == null) { 159 t = getDefaultClassLoader(); 160 } 161 if (t == null) { 162 t = getClass().getClassLoader(); 163 } 164 if (t == null) { 165 throw new IllegalStateException("Cannot determine classloader"); 166 } 167 return t; 168 } 169 170 abstract protected ClassLoader getDefaultClassLoader(); 171 172 protected Object create(Object key) { 173 try { 174 Object instance = null; 175 synchronized (source) { 176 ClassLoader loader = getClassLoader(); 177 Map cache2 = null; 178 if (useCache) { 179 cache2 = (Map)source.cache.get(loader); 180 if (cache2 != null) { 181 instance = cache2.get(key); 182 } else { 183 cache2 = new HashMap(); 184 cache2.put(NAME_KEY, new HashSet()); 185 source.cache.put(loader, cache2); 186 } 187 } 188 if (instance == null) { 189 this.key = key; 190 byte[] b = strategy.generate(this); 191 String className = ClassNameReader.getClassName(new ClassReader(b)); 192 getClassNameCache(loader).add(className); 193 instance = firstInstance(ReflectUtils.defineClass(className, b, loader)); 194 if (useCache) { 195 cache2.put(key, instance); 196 } 197 return instance; 198 } 199 } 200 return nextInstance(instance); 201 } catch (RuntimeException e) { 202 throw e; 203 } catch (Error e) { 204 throw e; 205 } catch (Exception e) { 206 throw new CodeGenerationException(e); 207 } 208 } 209 210 abstract protected Object firstInstance(Class type) throws Exception; 211 abstract protected Object nextInstance(Object instance) throws Exception; 212 }

This page was automatically generated by Maven