KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > cglib > core > AbstractClassGenerator


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 org.logicalcobwebs.cglib.core;
55
56 import java.io.*;
57 import java.lang.reflect.*;
58 import java.util.*;
59 import org.logicalcobwebs.asm.ClassReader;
60 import org.logicalcobwebs.asm.ClassVisitor;
61 import org.logicalcobwebs.asm.ClassWriter;
62 import org.logicalcobwebs.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 JavaDoc NAME_KEY = new Object JavaDoc();
74
75     private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE;
76     private NamingPolicy namingPolicy;
77     private Source source;
78     private ClassLoader JavaDoc classLoader;
79     private String JavaDoc namePrefix;
80     private Object JavaDoc key;
81     private boolean useCache = true;
82
83     protected static class Source {
84         String JavaDoc name;
85         Map cache = new WeakHashMap();
86         public Source(String JavaDoc name) {
87             this.name = name;
88         }
89     }
90
91     protected AbstractClassGenerator(Source source) {
92         this.source = source;
93     }
94
95     protected void setNamePrefix(String JavaDoc namePrefix) {
96         this.namePrefix = namePrefix;
97     }
98
99     final protected String JavaDoc getClassName() {
100         return getClassName(getClassLoader());
101     }
102
103     private String JavaDoc getClassName(ClassLoader JavaDoc 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 JavaDoc arg) {
108                 return nameCache.contains(arg);
109             }
110         });
111     }
112
113     private Set getClassNameCache(ClassLoader JavaDoc 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 JavaDoc 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 JavaDoc getClassLoader() {
157         ClassLoader JavaDoc 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 JavaDoc("Cannot determine classloader");
166         }
167         return t;
168     }
169
170     abstract protected ClassLoader JavaDoc getDefaultClassLoader();
171
172     protected Object JavaDoc create(Object JavaDoc key) {
173         try {
174             Object JavaDoc instance = null;
175             synchronized (source) {
176                 ClassLoader JavaDoc 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 JavaDoc 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 JavaDoc e) {
202             throw e;
203         } catch (Error JavaDoc e) {
204             throw e;
205         } catch (Exception JavaDoc e) {
206             throw new CodeGenerationException(e);
207         }
208     }
209
210     abstract protected Object JavaDoc firstInstance(Class JavaDoc type) throws Exception JavaDoc;
211     abstract protected Object JavaDoc nextInstance(Object JavaDoc instance) throws Exception JavaDoc;
212 }
213
Popular Tags