KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > easybeans > enhancer > interceptors > InterceptorClassAdapter


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: InterceptorClassAdapter.java 818 2006-07-04 12:07:42Z benoitf $
23  * --------------------------------------------------------------------------
24  */

25
26 package org.objectweb.easybeans.enhancer.interceptors;
27
28 import static org.objectweb.easybeans.deployment.annotations.InterceptorType.AROUND_INVOKE;
29 import static org.objectweb.easybeans.deployment.annotations.InterceptorType.DEP_INJECT;
30 import static org.objectweb.easybeans.deployment.annotations.InterceptorType.POST_ACTIVATE;
31 import static org.objectweb.easybeans.deployment.annotations.InterceptorType.POST_CONSTRUCT;
32 import static org.objectweb.easybeans.deployment.annotations.InterceptorType.PRE_DESTROY;
33 import static org.objectweb.easybeans.deployment.annotations.InterceptorType.PRE_PASSIVATE;
34
35 import java.util.ArrayList JavaDoc;
36 import java.util.Arrays JavaDoc;
37 import java.util.List JavaDoc;
38
39 import org.objectweb.asm.ClassAdapter;
40 import org.objectweb.asm.ClassVisitor;
41 import org.objectweb.asm.Label;
42 import org.objectweb.asm.MethodAdapter;
43 import org.objectweb.asm.MethodVisitor;
44 import org.objectweb.asm.Opcodes;
45 import org.objectweb.asm.Type;
46 import org.objectweb.easybeans.api.bean.lifecycle.EasyBeansMDBLifeCycle;
47 import org.objectweb.easybeans.api.bean.lifecycle.EasyBeansSFSBLifeCycle;
48 import org.objectweb.easybeans.api.bean.lifecycle.EasyBeansSLSBLifeCycle;
49 import org.objectweb.easybeans.deployment.annotations.InterceptorType;
50 import org.objectweb.easybeans.deployment.annotations.JClassInterceptor;
51 import org.objectweb.easybeans.deployment.annotations.JMethod;
52 import org.objectweb.easybeans.deployment.annotations.metadata.ClassAnnotationMetadata;
53 import org.objectweb.easybeans.deployment.annotations.metadata.MethodAnnotationMetadata;
54 import org.objectweb.easybeans.enhancer.CommonClassGenerator;
55 import org.objectweb.easybeans.enhancer.DefinedClass;
56 import org.objectweb.easybeans.enhancer.injection.InjectionClassAdapter;
57 import org.objectweb.easybeans.enhancer.lib.MethodRenamer;
58
59 /**
60  * This class delegates the creation of an implementation of a
61  * EasyBeansInvocationContext interface and intercepts all business methods() of a
62  * Bean.
63  * @author Florent Benoit
64  */

65 public class InterceptorClassAdapter extends ClassAdapter implements Opcodes {
66
67     /**
68      * Metadata available by this adapter for a class.
69      */

70     private ClassAnnotationMetadata classAnnotationMetadata;
71
72     /**
73      * List of methods which have been renamed.
74      */

75     private List JavaDoc<JMethod> renamedMethods = null;
76
77     /**
78      * Mappping between className and the bytecode.
79      */

80     private List JavaDoc<DefinedClass> definedClasses = null;
81
82     /**
83      * List of generated classes for each interceptor type.
84      */

85     private List JavaDoc<InterceptorType> generatedTypes = null;
86
87     /**
88      * List of interceptors classes used by the bean.
89      */

90     private List JavaDoc<String JavaDoc> beanInterceptors = null;
91
92     /**
93      * If it is true, interfaces of interceptor lifecycle will be added.
94      */

95     private boolean addInterface = true;
96
97     /**
98      * Constructor.
99      * @param classAnnotationMetadata object containing all attributes of the
100      * class
101      * @param cv the class visitor to which this adapter must delegate calls.
102      */

103     public InterceptorClassAdapter(final ClassAnnotationMetadata classAnnotationMetadata, final ClassVisitor cv) {
104         this(classAnnotationMetadata, cv, false);
105         this.beanInterceptors = new ArrayList JavaDoc<String JavaDoc>();
106     }
107
108     /**
109      * Constructor.
110      * @param classAnnotationMetadata object containing all attributes of the
111      * class
112      * @param cv the class visitor to which this adapter must delegate calls.
113      * @param addInterface adds lifecycle interface for a given bean.
114      */

115     public InterceptorClassAdapter(final ClassAnnotationMetadata classAnnotationMetadata,
116             final ClassVisitor cv, final boolean addInterface) {
117         super(cv);
118         this.classAnnotationMetadata = classAnnotationMetadata;
119         this.renamedMethods = new ArrayList JavaDoc<JMethod>();
120         this.definedClasses = new ArrayList JavaDoc<DefinedClass>();
121         this.addInterface = addInterface;
122         this.generatedTypes = new ArrayList JavaDoc<InterceptorType>();
123     }
124
125
126     /**
127      * Visits the header of the class.
128      * @param version the class version.
129      * @param access the class's access flags (see
130      * {@link org.objectweb.asm.Opcodes}). This parameter also indicates
131      * if the class is deprecated.
132      * @param name the internal name of the class (see
133      * {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
134      * @param signature the signature of this class. May be <tt>null</tt> if
135      * the class is not a generic one, and does not extend or implement
136      * generic classes or interfaces.
137      * @param superName the internal of name of the super class (see
138      * {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
139      * For interfaces, the super class is {@link Object}. May be
140      * <tt>null</tt>, but only for the {@link Object} class.
141      * @param interfaces the internal names of the class's interfaces (see
142      * {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
143      * May be <tt>null</tt>.
144      */

145     @Override JavaDoc
146     public void visit(final int version, final int access, final String JavaDoc name, final String JavaDoc signature, final String JavaDoc superName,
147             final String JavaDoc[] interfaces) {
148
149         String JavaDoc[] newInterfaces = null;
150
151         // Add new interface for lifecycle (if asked)
152
if (classAnnotationMetadata.isBean() && addInterface) {
153             // copy old interfaces in the new array
154
newInterfaces = new String JavaDoc[interfaces.length + 1];
155             System.arraycopy(interfaces, 0, newInterfaces, 0, interfaces.length);
156
157             int indexElement = newInterfaces.length - 1;
158
159             // Add the right interface (SLSB, SFSB, MDB)
160
if (classAnnotationMetadata.isStateless()) {
161                 newInterfaces[indexElement] = Type.getInternalName(EasyBeansSLSBLifeCycle.class);
162             } else if (classAnnotationMetadata.isStateful()) {
163                 newInterfaces[indexElement] = Type.getInternalName(EasyBeansSFSBLifeCycle.class);
164             } else if (classAnnotationMetadata.isMdb()) {
165                 newInterfaces[indexElement] = Type.getInternalName(EasyBeansMDBLifeCycle.class);
166             } else {
167                 throw new IllegalStateException JavaDoc("Bean '" + classAnnotationMetadata.getClassName() + "' not SLSB, SFSB or MDB");
168             }
169         } else {
170             newInterfaces = interfaces;
171         }
172
173         super.visit(version, access, name, signature, superName, newInterfaces);
174
175     }
176
177     /**
178      * Visits information about an inner class. This inner class is not
179      * necessarily a member of the class being visited.
180      * @param name the internal name of an inner class (see
181      * {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
182      * @param outerName the internal name of the class to which the inner class
183      * belongs (see
184      * {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
185      * May be <tt>null</tt>.
186      * @param innerName the (simple) name of the inner class inside its
187      * enclosing class. May be <tt>null</tt> for anonymous inner
188      * classes.
189      * @param access the access flags of the inner class as originally declared
190      * in the enclosing class.
191      */

192     @Override JavaDoc
193     public void visitInnerClass(final String JavaDoc name, final String JavaDoc outerName, final String JavaDoc innerName, final int access) {
194         super.visitInnerClass(name, outerName, innerName, access);
195     }
196
197     /**
198      * Visits a method of the class. T
199      * @param access the method's access flags (see {@link Opcodes}). This
200      * parameter also indicates if the method is synthetic and/or
201      * deprecated.
202      * @param name the method's name.
203      * @param desc the method's descriptor (see {@link org.objectweb.asm.Type}).
204      * @param signature the method's signature. May be <tt>null</tt> if the
205      * method parameters, return type and exceptions do not use generic
206      * types.
207      * @param exceptions the internal names of the method's exception classes
208      * (see
209      * {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
210      * May be <tt>null</tt>.
211      * @return an object to visit the byte code of the method, or <tt>null</tt>
212      * if this class visitor is not interested in visiting the code of
213      * this method.
214      */

215     @Override JavaDoc
216     public MethodVisitor visitMethod(final int access, final String JavaDoc name, final String JavaDoc desc, final String JavaDoc signature,
217             final String JavaDoc[] exceptions) {
218         JMethod jMethod = new JMethod(access, name, desc, signature, exceptions);
219         String JavaDoc newName = name;
220         int newAccess = access;
221
222         // Intercepted method : need to change the method name
223
if (isInterceptedMethod(jMethod)) {
224             // Add the method as renamed
225
renamedMethods.add(jMethod);
226
227             // Rename the method name
228
newName = MethodRenamer.encode(name);
229         }
230
231         // Interceptor method : need to change access to public.
232
if (!isDependencyInjectionMethod(jMethod) && !isInjectedMethod(jMethod)&& isInterceptorMethod(jMethod)) {
233             // Change modifier to public
234
newAccess = Opcodes.ACC_PUBLIC;
235         }
236         return new MethodAdapter(super.visitMethod(newAccess, newName, desc, signature, exceptions));
237     }
238
239     /**
240      * Visits the end of the class. This method, which is the last one to be
241      * called, is used to inform the visitor that all the fields and methods of
242      * the class have been visited.
243      */

244     @Override JavaDoc
245     public void visitEnd() {
246         super.visitEnd();
247
248         // For Bean only
249
if (classAnnotationMetadata.isBean()) {
250             // Add default lifecycle methods. These methods will call defined
251
// lifecycle callback method and super methods or will do nothing.
252
MethodAnnotationMetadata posConsMetaData = generateBeanLifeCycleMethod(classAnnotationMetadata, POST_CONSTRUCT);
253             MethodAnnotationMetadata preDesMetaData = generateBeanLifeCycleMethod(classAnnotationMetadata, PRE_DESTROY);
254             MethodAnnotationMetadata postActMetaData = generateBeanLifeCycleMethod(classAnnotationMetadata, POST_ACTIVATE);
255             MethodAnnotationMetadata prePassMetaData = generateBeanLifeCycleMethod(classAnnotationMetadata, PRE_PASSIVATE);
256
257             // Generate class for dependency injection
258
generateClass(
259                     new MethodAnnotationMetadata(InjectionClassAdapter.INJECTED_JMETHOD, classAnnotationMetadata),
260                     DEP_INJECT);
261
262
263
264             // Need to generate the implementation of EasyBeansInvocationContext Impl on intercepted methods
265
for (MethodAnnotationMetadata method : classAnnotationMetadata.getMethodAnnotationMetadataCollection()) {
266
267                 // No else if, need to generate an invocationcontext for each case
268
if (method.isBusinessMethod()) {
269                     generateClass(method, AROUND_INVOKE);
270
271                     // method was not renamed (it is inherited), need to generate a method calling super method().
272
if (!renamedMethods.contains(method.getJMethod())) {
273                         generateCallSuperEncodedMethod(method);
274                     }
275                 }
276             }
277
278
279             // First method is the method that has been generated by the call to generateBeanLifeCycleMethod
280
// This is method which needs to be intercepted. (there is always
281
// one method as we added default method, so no need to check
282
// null list)
283
generateClass(posConsMetaData, POST_CONSTRUCT);
284             generateClass(preDesMetaData, PRE_DESTROY);
285             generateClass(prePassMetaData, PRE_PASSIVATE);
286             generateClass(postActMetaData, POST_ACTIVATE);
287
288             // Then generate the interceptorManager
289
String JavaDoc generatedClName = classAnnotationMetadata.getClassName()
290                     + EasyBeansInvocationContextGenerator.SUFFIX_INTERCEPTOR_MANAGER;
291             InterceptorManagerGenerator interceptorManagerGenerator = new InterceptorManagerGenerator(
292                     classAnnotationMetadata.getEjbJarAnnotationMetadata(), generatedClName, beanInterceptors);
293             interceptorManagerGenerator.generate();
294             DefinedClass dc = new DefinedClass(generatedClName.replace("/", "."), interceptorManagerGenerator.getBytes());
295             // this class will be defined later on the classloader
296
definedClasses.add(dc);
297
298         }
299     }
300
301     /**
302      * Generates the call to InvocationContext impl proceed method after
303      * building a new object. ie :
304      *
305      * <pre>
306      * public int generatedMethodName(int a, int b) throws MyException {
307      * try {
308      * return ((Integer) new MethodAddInvocationContextImpl(this, a, b).proceed()).intValue();
309      * } catch (MyException e) {
310      * throw e;
311      * } catch (Exception e) {
312      * if (e instanceof RuntimeException) {
313      * throw (RuntimeException) e;
314      * } else {
315      * throw new RuntimeException(e);
316      * }
317      * }
318      * }
319      * </pre>
320      *
321      * @param method the annotation metadata of the method
322      * @param genInvCtx the generator of the EasyBeansInvocationContext impl class.
323      * @param interceptorType the type of method which is intercepted
324      */

325     private void generateCallToInvocationContext(final MethodAnnotationMetadata method,
326             final EasyBeansInvocationContextGenerator genInvCtx, final InterceptorType interceptorType) {
327
328         /**
329          * Method name, two cases :
330          * - AroundInvoke : method = original name
331          * - LifeCycle : method = postConstructEasyBeansLifeCycle, preDestroyEasyBeansLifeCycle
332          */

333         String JavaDoc generatedMethodName = null;
334         switch (interceptorType) {
335             case AROUND_INVOKE:
336                 generatedMethodName = method.getMethodName();
337                 break;
338             case DEP_INJECT:
339                 generatedMethodName = MethodRenamer.decode(method.getMethodName());
340                 break;
341             case POST_CONSTRUCT:
342                 generatedMethodName = "postConstructEasyBeansLifeCycle";
343                 break;
344             case PRE_DESTROY:
345                 generatedMethodName = "preDestroyEasyBeansLifeCycle";
346                 break;
347             case PRE_PASSIVATE:
348                 generatedMethodName = "prePassivateEasyBeansLifeCycle";
349                 break;
350             case POST_ACTIVATE:
351                 generatedMethodName = "postActivateEasyBeansLifeCycle";
352                 break;
353                 default:
354                     throw new RuntimeException JavaDoc("No generated method name found for method '" + method.getMethodName() + "'");
355         }
356
357         if (generatedMethodName == null) {
358             throw new RuntimeException JavaDoc("No generated method name found for method '" + method.getMethodName() + "'");
359         }
360
361         // Adds a method which will call the invocationcontext impl
362
MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, generatedMethodName, method.getJMethod().getDescriptor(),
363                 null, method.getJMethod().getExceptions());
364         mv.visitCode();
365
366         // Start of the Try label of Try/Catch
367
Label tryLabel = new Label();
368         mv.visitLabel(tryLabel);
369
370         // build new object by calling the constructor
371
mv.visitTypeInsn(NEW, genInvCtx.getGeneratedClassName());
372         mv.visitInsn(DUP);
373
374         // Add bean (as first argument)
375
mv.visitVarInsn(ALOAD, 0);
376
377         // for each argument
378
Type[] args = Type.getArgumentTypes(method.getJMethod().getDescriptor());
379         int methodArg = 1;
380         for (Type type : args) {
381             int opCode = CommonClassGenerator.putFieldLoadOpCode(type.getSort());
382             mv.visitVarInsn(opCode, methodArg);
383             // Double and Long are special parameters
384
if (opCode == LLOAD || opCode == DLOAD) {
385                 methodArg++;
386             }
387             methodArg++;
388         }
389         Type returnType = Type.getReturnType(method.getJMethod().getDescriptor());
390
391         String JavaDoc constructorDesc = genInvCtx.getConstructorDesc();
392         mv.visitMethodInsn(INVOKESPECIAL, genInvCtx.getGeneratedClassName(), "<init>", constructorDesc);
393         mv.visitMethodInsn(INVOKEVIRTUAL, genInvCtx.getGeneratedClassName(), "proceed", "()Ljava/lang/Object;");
394
395         CommonClassGenerator.transformObjectIntoPrimitive(returnType, mv);
396         CommonClassGenerator.addReturnType(returnType, mv);
397
398         boolean methodAlreadyThrowJavaLangException = false;
399
400         // Catch blocks
401
String JavaDoc[] methodExceptions = method.getJMethod().getExceptions();
402         // catch label = exceptions thrown by method + 1
403
Label[] catchsLabel = null;
404         if (methodExceptions != null) {
405             // if the java.lang.Exception is present, don't need two catchs
406
// blocks
407
// for java/lang/Exception
408
if (Arrays.asList(methodExceptions).contains("java/lang/Exception")) {
409                 methodAlreadyThrowJavaLangException = true;
410                 catchsLabel = new Label[methodExceptions.length];
411             } else {
412                 // else, add a catch for java.lang.Exception
413
catchsLabel = new Label[methodExceptions.length + 1];
414             }
415         } else {
416             catchsLabel = new Label[1];
417         }
418
419         // init labels
420
for (int i = 0; i < catchsLabel.length; i++) {
421             catchsLabel[i] = new Label();
422         }
423
424         // First, do method exceptions (just rethrow the given exception)
425
int lastCatchBlockLabel = 0;
426         if (methodAlreadyThrowJavaLangException) {
427             lastCatchBlockLabel = catchsLabel.length;
428         } else {
429             lastCatchBlockLabel = catchsLabel.length - 1;
430         }
431
432         for (int block = 0; block < lastCatchBlockLabel; block++) {
433             mv.visitLabel(catchsLabel[block]);
434             mv.visitVarInsn(ASTORE, methodArg);
435             mv.visitVarInsn(ALOAD, methodArg);
436             mv.visitInsn(ATHROW);
437         }
438         // Now, do the wrapped of Exception into a RuntimeException
439
if (!methodAlreadyThrowJavaLangException) {
440             // start label
441
mv.visitLabel(catchsLabel[lastCatchBlockLabel]);
442             mv.visitVarInsn(ASTORE, methodArg);
443
444             // instanceof RuntimeException
445
mv.visitVarInsn(ALOAD, methodArg);
446             mv.visitTypeInsn(INSTANCEOF, "java/lang/RuntimeException");
447             Label notInstanceOfRuntimeExceptionLabel = new Label();
448             mv.visitJumpInsn(IFEQ, notInstanceOfRuntimeExceptionLabel);
449
450             // throw existing runtime exception (by casting it)
451
mv.visitVarInsn(ALOAD, methodArg);
452             mv.visitTypeInsn(CHECKCAST, "java/lang/RuntimeException");
453             mv.visitInsn(ATHROW);
454
455             // build Runtime exception with given exception
456
mv.visitLabel(notInstanceOfRuntimeExceptionLabel);
457             mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
458             mv.visitInsn(DUP);
459             mv.visitVarInsn(ALOAD, methodArg);
460             mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/Throwable;)V");
461             mv.visitInsn(ATHROW);
462
463         }
464
465         // Perform try/catch blocks with ASM
466
int block = 0;
467         // method exception
468
if (methodExceptions != null) {
469             for (String JavaDoc exception : methodExceptions) {
470                 mv.visitTryCatchBlock(tryLabel, catchsLabel[0], catchsLabel[block], exception);
471                 block++;
472             }
473         }
474         // Exception thrown by proceed() call
475
if (!methodAlreadyThrowJavaLangException) {
476             mv.visitTryCatchBlock(tryLabel, catchsLabel[0], catchsLabel[lastCatchBlockLabel], "java/lang/Exception");
477         }
478
479         mv.visitMaxs(0, 0);
480         mv.visitEnd();
481
482     }
483
484     /**
485      * Generate an invocation context object.
486      * @param method intercepted method
487      * @param interceptorType the type of method which is intercepted
488      */

489     private void generateClass(final MethodAnnotationMetadata method, final InterceptorType interceptorType) {
490         EasyBeansInvocationContextGenerator genInvCtx = new EasyBeansInvocationContextGenerator(method, interceptorType);
491         genInvCtx.generate();
492
493         // Get all interceptors used and that are not defined in the bean
494
for (JClassInterceptor interceptor : genInvCtx.getAllInterceptors()) {
495             String JavaDoc interceptorClassName = interceptor.getClassName();
496             if (!interceptorClassName.equals(classAnnotationMetadata.getClassName())) {
497                 if (!beanInterceptors.contains(interceptorClassName)) {
498                     beanInterceptors.add(interceptorClassName);
499                 }
500             }
501         }
502         DefinedClass dc = new DefinedClass(genInvCtx.getGeneratedClassName().replace("/", "."), genInvCtx.getBytes());
503         // this class will be defined later on the classloader
504
definedClasses.add(dc);
505         generatedTypes.add(interceptorType);
506         // generate method calling generated EasyBeansInvocationContext impl
507
generateCallToInvocationContext(method, genInvCtx, interceptorType);
508
509     }
510
511     /**
512      * Generates a call to the method defined in the super class.
513      * public int original$add(int i, int j) {
514      * return super.add(i, j);
515      * }
516      * @param method the annotation metadata of the method
517      */

518     private void generateCallSuperEncodedMethod(final MethodAnnotationMetadata method) {
519
520         String JavaDoc generatedMethodName = MethodRenamer.encode(method.getMethodName());
521         JMethod jMethod = method.getJMethod();
522         MethodVisitor mv = cv.visitMethod(jMethod.getAccess(), generatedMethodName,
523                 jMethod.getDescriptor(), jMethod.getSignature(), jMethod.getExceptions());
524         mv.visitCode();
525
526         // Add bean (as first argument)
527
mv.visitVarInsn(ALOAD, 0);
528
529         // for each argument
530
Type[] args = Type.getArgumentTypes(jMethod.getDescriptor());
531         int methodArg = 1;
532         for (Type type : args) {
533             int opCode = CommonClassGenerator.putFieldLoadOpCode(type.getSort());
534             mv.visitVarInsn(opCode, methodArg);
535             // Double and Long are special parameters
536
if (opCode == LLOAD || opCode == DLOAD) {
537                 methodArg++;
538             }
539             methodArg++;
540         }
541
542         // call super class method()
543
mv.visitMethodInsn(INVOKESPECIAL, method.getClassAnnotationMetadata().getSuperName(),
544                 jMethod.getName(), jMethod.getDescriptor());
545
546         Type returnType = Type.getReturnType(jMethod.getDescriptor());
547         CommonClassGenerator.addReturnType(returnType, mv);
548
549
550         mv.visitMaxs(0, 0);
551         mv.visitEnd();
552     }
553
554
555
556
557
558     /**
559      * Generates a default method for lifecycle method events.
560      * It will call the methods in the super classes of the defined method.
561      * @param classMetaData the metadata used to generate method metadata
562      * @param interceptorType the type of intercepted method
563      * @return the generated method metadata
564      */

565     private MethodAnnotationMetadata generateBeanLifeCycleMethod(final ClassAnnotationMetadata classMetaData,
566             final InterceptorType interceptorType) {
567         String JavaDoc generatedMethodName = null;
568         List JavaDoc<MethodAnnotationMetadata> existingLifecycleMethods = null;
569         switch (interceptorType) {
570             case AROUND_INVOKE:
571             case DEP_INJECT:
572                 //Nothing to generate
573
return null;
574             case POST_CONSTRUCT:
575                 generatedMethodName = "beanPostConstruct$generated";
576                 existingLifecycleMethods = classMetaData.getPostConstructMethodsMetadata();
577                 break;
578             case PRE_DESTROY:
579                 generatedMethodName = "beanPreDestroy$generated";
580                 existingLifecycleMethods = classMetaData.getPreDestroyMethodsMetadata();
581                 break;
582             case PRE_PASSIVATE:
583                 generatedMethodName = "beanPrePassivate$generated";
584                 existingLifecycleMethods = classMetaData.getPrePassivateMethodsMetadata();
585                 break;
586             case POST_ACTIVATE:
587                 generatedMethodName = "beanPostActivate$generated";
588                 existingLifecycleMethods = classMetaData.getPostActivateMethodsMetadata();
589                 break;
590                 default:
591                     throw new RuntimeException JavaDoc("No generated method name found for interceptorType '" + interceptorType + "'");
592         }
593
594
595         // Generates the body of this method.
596
MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, generatedMethodName, "()V", null, null);
597         mv.visitCode();
598         // Call methods in their order (if any)
599
if (existingLifecycleMethods != null) {
600             for (MethodAnnotationMetadata method : existingLifecycleMethods) {
601                 // Inherited or not ?
602
String JavaDoc clName = method.getClassAnnotationMetadata().getClassName();
603                 mv.visitVarInsn(ALOAD, 0);
604                 int opcode = INVOKEVIRTUAL;
605                 if (method.isInherited()) {
606                     clName = method.getOriginalClassAnnotationMetadata().getClassName();
607                     opcode = INVOKESPECIAL;
608                 }
609                 mv.visitMethodInsn(opcode, clName, method.getMethodName(), method.getJMethod().getDescriptor());
610             }
611         }
612
613
614         mv.visitInsn(RETURN);
615         mv.visitMaxs(0, 0);
616         mv.visitEnd();
617
618         // add method in the class metadata
619
JMethod method = new JMethod(ACC_PUBLIC, generatedMethodName, "()V", null, null);
620         MethodAnnotationMetadata generatedMetadata = new MethodAnnotationMetadata(method, classMetaData);
621
622         // Set value
623
switch (interceptorType) {
624             case POST_CONSTRUCT:
625                 generatedMetadata.setPostConstruct(true);
626                 break;
627             case PRE_DESTROY:
628                 generatedMetadata.setPreDestroy(true);
629                 break;
630             case PRE_PASSIVATE:
631                 generatedMetadata.setPrePassivate(true);
632                 break;
633             case POST_ACTIVATE:
634                 generatedMetadata.setPostActivate(true);
635                 break;
636             default:
637                     throw new RuntimeException JavaDoc("No generated method name found for interceptorType '" + interceptorType + "'");
638         }
639
640         classMetaData.addMethodAnnotationMetadata(generatedMetadata);
641         return generatedMetadata;
642     }
643
644     /**
645      * Check if this method is the injected method used for dependency injection.
646      * @param jMethod object to check
647      * @return true if the given method is the injected method used for dependency
648      * injection
649      */

650     private boolean isDependencyInjectionMethod(final JMethod jMethod) {
651         return InjectionClassAdapter.INJECTED_METHOD.equals(jMethod.getName());
652     }
653
654     /**
655      * Check if this method is injected or not by injection class adapter : No need to add interceptors on these methods.
656      * @param jMethod object to check
657      * @return true if the given method is injected by injection class adapter.
658      */

659     private boolean isInjectedMethod(final JMethod jMethod) {
660         for (String JavaDoc method : InjectionClassAdapter.INJECTED_METHODS) {
661             if (method.equals(jMethod.getName())) {
662                 return true;
663             }
664         }
665         return false;
666     }
667
668     /**
669      * @param jMethod object to check
670      * @return true if the given method is an intercepted method
671      * (and business method) because lifecycle methods are not renamed
672      */

673     private boolean isInterceptedMethod(final JMethod jMethod) {
674         // needs to be intercepted
675
if (isDependencyInjectionMethod(jMethod)) {
676             return classAnnotationMetadata.isBean();
677         }
678
679         // other injected methods are helper methods (and not business --> no need to intercept them)
680
if (isInjectedMethod(jMethod)) {
681             return false;
682         }
683
684         // get method metadata
685
MethodAnnotationMetadata method = classAnnotationMetadata.getMethodAnnotationMetadata(jMethod);
686         if (method == null) {
687             throw new IllegalStateException JavaDoc("Cannot find a method " + jMethod + " in class "
688                     + classAnnotationMetadata.getClassName());
689         }
690         return method.isBusinessMethod();
691     }
692
693     /**
694      * @param jMethod object to check
695      * @return true if the given method is an interceptor method (ie AroundInvoke, PostConstruct, etc).
696      */

697     private boolean isInterceptorMethod(final JMethod jMethod) {
698         // get method metadata
699
MethodAnnotationMetadata method = classAnnotationMetadata.getMethodAnnotationMetadata(jMethod);
700         if (method == null) {
701             throw new IllegalStateException JavaDoc("Cannot find a method " + jMethod + " in class "
702                     + classAnnotationMetadata.getClassName());
703         }
704         return (method.isAroundInvoke() || method.isLifeCycleMethod());
705     }
706
707
708     /**
709      * @return list of classes generated and that need to be defined in a
710      * classloader
711      */

712     public List JavaDoc<DefinedClass> getDefinedClasses() {
713         return definedClasses;
714     }
715 }
716
Popular Tags