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