KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > easybeans > enhancer > Enhancer


1 /**
2  * EasyBeans
3  * Copyright (C) 2006 Bull S.A.S.
4  * Contact: easybeans@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  *
21  * --------------------------------------------------------------------------
22  * $Id: Enhancer.java 406 2006-04-24 16:43:08Z benoitf $
23  * --------------------------------------------------------------------------
24  */

25
26 package org.objectweb.easybeans.enhancer;
27
28 import static org.objectweb.easybeans.enhancer.injection.InjectionClassAdapter.JAVA_LANG_OBJECT;
29
30 import java.io.IOException JavaDoc;
31 import java.io.InputStream JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Map JavaDoc;
34
35 import org.objectweb.asm.ClassReader;
36 import org.objectweb.asm.ClassWriter;
37 import org.objectweb.easybeans.deployment.annotations.metadata.ClassAnnotationMetadata;
38 import org.objectweb.easybeans.deployment.annotations.metadata.EjbJarAnnotationMetadata;
39 import org.objectweb.easybeans.enhancer.bean.BeanClassAdapter;
40 import org.objectweb.easybeans.enhancer.injection.InjectionClassAdapter;
41 import org.objectweb.easybeans.enhancer.interceptors.InterceptorClassAdapter;
42 import org.objectweb.easybeans.loader.EasyBeansClassLoader;
43 import org.objectweb.easybeans.log.JLog;
44 import org.objectweb.easybeans.log.JLogFactory;
45
46 /**
47  * This class is used for enhancing a set of classes (Beans like Stateless,
48  * Stateful, MDB, etc).
49  * @author Florent Benoit
50  */

51 public class Enhancer {
52
53     /**
54      * Logger.
55      */

56     private static JLog logger = JLogFactory.getLog(Enhancer.class);
57
58     /**
59      * Metadata of the classes of a given jar file.
60      */

61     private EjbJarAnnotationMetadata ejbJarAnnotationMetadata = null;
62
63     /**
64      * Classloader used to load/define classes.
65      */

66     private ClassLoader JavaDoc loader = null;
67
68     /**
69      * Map containing informations for enhancers.
70      */

71     private Map JavaDoc<String JavaDoc, Object JavaDoc> map = null;
72
73     /**
74      * Creates an new enhancer.
75      * @param loader classloader where to define enhanced classes.
76      * @param ejbJarAnnotationMetadata object with references to the metadata.
77      * @param map a map allowing to give some objects to the enhancer.
78      */

79     public Enhancer(final ClassLoader JavaDoc loader, final EjbJarAnnotationMetadata ejbJarAnnotationMetadata,
80             final Map JavaDoc<String JavaDoc, Object JavaDoc> map) {
81         this.loader = loader;
82         this.ejbJarAnnotationMetadata = ejbJarAnnotationMetadata;
83         this.map = map;
84     }
85
86     /**
87      * Enhance all classes which match beans, etc.
88      * @throws EnhancerException if enhancing fails
89      */

90     public void enhance() throws EnhancerException {
91
92         // Define all interceptors first.
93
for (ClassAnnotationMetadata classAnnotationMetadata : ejbJarAnnotationMetadata
94                 .getClassAnnotationMetadataCollection()) {
95             if (classAnnotationMetadata.isInterceptor() && !classAnnotationMetadata.isBean()
96                     && !classAnnotationMetadata.wasModified()) {
97                 logger.debug("ClassAdapter on interceptor : {0}", classAnnotationMetadata.getClassName());
98
99                 // enhance all super classes of the interceptor. (if any)
100
// And do this only one time.
101
enhanceSuperClass(classAnnotationMetadata);
102
103                 // Create ClassReader/Writer
104
ClassReader cr = getClassReader(classAnnotationMetadata);
105                 ClassWriter cw = new ClassWriter(true);
106                 InterceptorClassAdapter cv = new InterceptorClassAdapter(classAnnotationMetadata, cw);
107                 InjectionClassAdapter cv2 = new InjectionClassAdapter(classAnnotationMetadata, cv, map, false);
108                 cr.accept(cv2, false);
109                 classAnnotationMetadata.setModified();
110                 defineClass(loader, classAnnotationMetadata.getClassName().replace("/", "."), cw.toByteArray());
111             }
112         }
113         // search all beans
114
for (ClassAnnotationMetadata classAnnotationMetadata : ejbJarAnnotationMetadata
115                 .getClassAnnotationMetadataCollection()) {
116             if (classAnnotationMetadata.isBean()) {
117
118                 // First, enhance all super classes of the bean. (if any)
119
// And do this only one time.
120
enhanceSuperClass(classAnnotationMetadata);
121
122
123                 // Create ClassReader/Writer
124
ClassReader cr = getClassReader(classAnnotationMetadata);
125                 ClassWriter cw = new ClassWriter(true);
126                 BeanClassAdapter cv = new BeanClassAdapter(classAnnotationMetadata, cw);
127                 InterceptorClassAdapter itcpClassAdapter = new InterceptorClassAdapter(classAnnotationMetadata, cv);
128                 InjectionClassAdapter cv2 = new InjectionClassAdapter(classAnnotationMetadata, itcpClassAdapter, map, false);
129                 cr.accept(cv2, false);
130
131                 // define subclasses if interceptor enabled
132
loadDefinedClasses(loader, itcpClassAdapter.getDefinedClasses());
133
134                 defineClass(loader, classAnnotationMetadata.getClassName().replace("/", "."), cw.toByteArray());
135
136             }
137
138         }
139     }
140
141
142     /**
143      * Enhance all super classes that are available.
144      * @param classAnnotationMetadata the class where to lookup super classes.
145      * @throws EnhancerException if class can't be analyzed.
146      */

147     protected void enhanceSuperClass(final ClassAnnotationMetadata classAnnotationMetadata) throws EnhancerException {
148         // First, enhance all super classes of the bean. (if any)
149
// And do this only one time.
150
String JavaDoc superClass = classAnnotationMetadata.getSuperName();
151         if (!superClass.equals(JAVA_LANG_OBJECT)) {
152             ClassAnnotationMetadata superMetaData = ejbJarAnnotationMetadata.getClassAnnotationMetadata(superClass);
153             if (superMetaData != null && !superMetaData.wasModified()) {
154                 ClassReader cr = getClassReader(superMetaData);
155                 ClassWriter cw = new ClassWriter(true);
156                 InjectionClassAdapter cv = new InjectionClassAdapter(superMetaData, cw, map, false);
157                 cr.accept(cv, false);
158                 superMetaData.setModified();
159                 defineClass(loader, superMetaData.getClassName().replace("/", "."), cw.toByteArray());
160                 enhanceSuperClass(superMetaData);
161             }
162         }
163
164     }
165
166     /**
167      * Load defined classes in the list.
168      * @param loader classloader to use.
169      * @param lst a list of new generated classes.
170      */

171     private static void loadDefinedClasses(final ClassLoader JavaDoc loader, final List JavaDoc<DefinedClass> lst) {
172         if (lst != null) {
173             for (DefinedClass definedClass : lst) {
174                 defineClass(loader, definedClass.getClassName(), definedClass.getBytes());
175             }
176         }
177     }
178
179
180     /**
181      * Gets a class reader for a given metadata.
182      * @param classAnnotationMetadata given metadata
183      * @return classreader associated to the given metadata
184      * @throws EnhancerException if no classWriter can be returned
185      */

186     protected ClassReader getClassReader(final ClassAnnotationMetadata classAnnotationMetadata)
187             throws EnhancerException {
188         String JavaDoc className = classAnnotationMetadata.getClassName() + ".class";
189         InputStream JavaDoc is = loader.getResourceAsStream(className);
190         if (is == null) {
191             throw new EnhancerException("Cannot find input stream in classloader " + loader + " for class " + className);
192         }
193         ClassReader cr = null;
194         try {
195             cr = new ClassReader(is);
196         } catch (IOException JavaDoc e) {
197             throw new EnhancerException("Cannot load input stream for class '" + className + "' in classloader '"
198                     + loader);
199         }
200         return cr;
201     }
202
203     /**
204      * Loads/defines a class in the current class loader.
205      * @param loader classloader to use.
206      * @param className the name of the class
207      * @param b the bytecode of the class to define
208      */

209     public static void defineClass(final ClassLoader JavaDoc loader, final String JavaDoc className, final byte[] b) {
210         if (loader instanceof EasyBeansClassLoader) {
211             ((EasyBeansClassLoader) loader).addClassDefinition(className, b);
212         } else {
213             // use other way of loading class.
214
// override classDefine (as it is protected) and define the class.
215
try {
216                 ///ClassLoader loader = Thread.currentThread().getContextClassLoader();
217
Class JavaDoc cls = Class.forName("java.lang.ClassLoader");
218                 java.lang.reflect.Method JavaDoc method = cls.getDeclaredMethod("defineClass", new Class JavaDoc[] {String JavaDoc.class,
219                         byte[].class, int.class, int.class});
220
221                 // protected method invocaton
222
method.setAccessible(true);
223                 try {
224                     Object JavaDoc[] args = new Object JavaDoc[] {className, b, new Integer JavaDoc(0), new Integer JavaDoc(b.length)};
225                     method.invoke(loader, args);
226                 } finally {
227                     method.setAccessible(false);
228                 }
229             } catch (Exception JavaDoc e) {
230                 throw new RuntimeException JavaDoc(e);
231             }
232         }
233
234
235     }
236
237     /**
238      * @return the ejbjar annotation metadata
239      */

240     protected EjbJarAnnotationMetadata getEjbJarAnnotationMetadata() {
241         return ejbJarAnnotationMetadata;
242     }
243
244     /**
245      * @return map containing informations for enhancers.
246      */

247     protected Map JavaDoc<String JavaDoc, Object JavaDoc> getMap() {
248         return map;
249     }
250
251     /**
252      * @return the classloader used by this enhancer.
253      */

254     protected ClassLoader JavaDoc getClassLoader() {
255         return loader;
256     }
257
258 }
259
Popular Tags