Source Code Cross Referenced for InterceptorClassAdapter.java in  » J2EE » ow2-easybeans » org » ow2 » easybeans » enhancer » interceptors » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » ow2 easybeans » org.ow2.easybeans.enhancer.interceptors 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /**
002:         * EasyBeans
003:         * Copyright (C) 2006-2007 Bull S.A.S.
004:         * Contact: easybeans@ow2.org
005:         *
006:         * This library is free software; you can redistribute it and/or
007:         * modify it under the terms of the GNU Lesser General Public
008:         * License as published by the Free Software Foundation; either
009:         * version 2.1 of the License, or any later version.
010:         *
011:         * This library is distributed in the hope that it will be useful,
012:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014:         * Lesser General Public License for more details.
015:         *
016:         * You should have received a copy of the GNU Lesser General Public
017:         * License along with this library; if not, write to the Free Software
018:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
019:         * USA
020:         *
021:         * --------------------------------------------------------------------------
022:         * $Id: InterceptorClassAdapter.java 2057 2007-11-21 15:35:32Z benoitf $
023:         * --------------------------------------------------------------------------
024:         */package org.ow2.easybeans.enhancer.interceptors;
025:
026:        import static org.ow2.easybeans.deployment.annotations.InterceptorType.AROUND_INVOKE;
027:        import static org.ow2.easybeans.deployment.annotations.InterceptorType.DEP_INJECT;
028:        import static org.ow2.easybeans.deployment.annotations.InterceptorType.POST_ACTIVATE;
029:        import static org.ow2.easybeans.deployment.annotations.InterceptorType.POST_CONSTRUCT;
030:        import static org.ow2.easybeans.deployment.annotations.InterceptorType.PRE_DESTROY;
031:        import static org.ow2.easybeans.deployment.annotations.InterceptorType.PRE_PASSIVATE;
032:        import static org.ow2.easybeans.deployment.annotations.InterceptorType.TIMED_OBJECT;
033:
034:        import java.util.ArrayList;
035:        import java.util.Arrays;
036:        import java.util.List;
037:
038:        import org.ow2.easybeans.asm.ClassAdapter;
039:        import org.ow2.easybeans.asm.ClassVisitor;
040:        import org.ow2.easybeans.asm.Label;
041:        import org.ow2.easybeans.asm.MethodAdapter;
042:        import org.ow2.easybeans.asm.MethodVisitor;
043:        import org.ow2.easybeans.asm.Opcodes;
044:        import org.ow2.easybeans.asm.Type;
045:        import org.ow2.easybeans.api.bean.lifecycle.EasyBeansMDBLifeCycle;
046:        import org.ow2.easybeans.api.bean.lifecycle.EasyBeansSFSBLifeCycle;
047:        import org.ow2.easybeans.api.bean.lifecycle.EasyBeansSLSBLifeCycle;
048:        import org.ow2.easybeans.deployment.annotations.InterceptorType;
049:        import org.ow2.easybeans.deployment.annotations.JClassInterceptor;
050:        import org.ow2.easybeans.deployment.annotations.JMethod;
051:        import org.ow2.easybeans.deployment.annotations.metadata.ClassAnnotationMetadata;
052:        import org.ow2.easybeans.deployment.annotations.metadata.MethodAnnotationMetadata;
053:        import org.ow2.easybeans.enhancer.CommonClassGenerator;
054:        import org.ow2.easybeans.enhancer.DefinedClass;
055:        import org.ow2.easybeans.enhancer.bean.BeanClassAdapter;
056:        import org.ow2.easybeans.enhancer.injection.InjectionClassAdapter;
057:        import org.ow2.easybeans.enhancer.lib.MethodRenamer;
058:
059:        /**
060:         * This class delegates the creation of an implementation of a
061:         * EasyBeansInvocationContext interface and intercepts all business methods() of a
062:         * Bean.
063:         * @author Florent Benoit
064:         */
065:        public class InterceptorClassAdapter extends ClassAdapter implements 
066:                Opcodes {
067:
068:            /**
069:             * Metadata available by this adapter for a class.
070:             */
071:            private ClassAnnotationMetadata classAnnotationMetadata;
072:
073:            /**
074:             * List of methods which have been renamed.
075:             */
076:            private List<JMethod> renamedMethods = null;
077:
078:            /**
079:             * Mappping between className and the bytecode.
080:             */
081:            private List<DefinedClass> definedClasses = null;
082:
083:            /**
084:             * List of generated classes for each interceptor type.
085:             */
086:            private List<InterceptorType> generatedTypes = null;
087:
088:            /**
089:             * List of interceptors classes used by the bean.
090:             */
091:            private List<String> beanInterceptors = null;
092:
093:            /**
094:             * If it is true, interfaces of interceptor lifecycle will be added.
095:             */
096:            private boolean addInterface = true;
097:
098:            /**
099:             * Constructor.
100:             * @param classAnnotationMetadata object containing all attributes of the
101:             *        class
102:             * @param cv the class visitor to which this adapter must delegate calls.
103:             */
104:            public InterceptorClassAdapter(
105:                    final ClassAnnotationMetadata classAnnotationMetadata,
106:                    final ClassVisitor cv) {
107:                this (classAnnotationMetadata, cv, false);
108:                this .beanInterceptors = new ArrayList<String>();
109:            }
110:
111:            /**
112:             * Constructor.
113:             * @param classAnnotationMetadata object containing all attributes of the
114:             *        class
115:             * @param cv the class visitor to which this adapter must delegate calls.
116:             * @param addInterface adds lifecycle interface for a given bean.
117:             */
118:            public InterceptorClassAdapter(
119:                    final ClassAnnotationMetadata classAnnotationMetadata,
120:                    final ClassVisitor cv, final boolean addInterface) {
121:                super (cv);
122:                this .classAnnotationMetadata = classAnnotationMetadata;
123:                this .renamedMethods = new ArrayList<JMethod>();
124:                this .definedClasses = new ArrayList<DefinedClass>();
125:                this .addInterface = addInterface;
126:                this .generatedTypes = new ArrayList<InterceptorType>();
127:            }
128:
129:            /**
130:             * Visits the header of the class.
131:             * @param version the class version.
132:             * @param access the class's access flags (see
133:             *        {@link org.ow2.easybeans.asm.Opcodes}). This parameter also indicates
134:             *        if the class is deprecated.
135:             * @param name the internal name of the class (see
136:             *        {@link org.ow2.easybeans.asm.Type#getInternalName() getInternalName}).
137:             * @param signature the signature of this class. May be <tt>null</tt> if
138:             *        the class is not a generic one, and does not extend or implement
139:             *        generic classes or interfaces.
140:             * @param superName the internal of name of the super class (see
141:             *        {@link org.ow2.easybeans.asm.Type#getInternalName() getInternalName}).
142:             *        For interfaces, the super class is {@link Object}. May be
143:             *        <tt>null</tt>, but only for the {@link Object} class.
144:             * @param interfaces the internal names of the class's interfaces (see
145:             *        {@link org.ow2.easybeans.asm.Type#getInternalName() getInternalName}).
146:             *        May be <tt>null</tt>.
147:             */
148:            @Override
149:            public void visit(final int version, final int access,
150:                    final String name, final String signature,
151:                    final String super Name, final String[] interfaces) {
152:
153:                String[] newInterfaces = null;
154:
155:                // Add new interface for lifecycle (if asked)
156:                if (classAnnotationMetadata.isBean() && addInterface) {
157:                    // copy old interfaces in the new array
158:                    newInterfaces = new String[interfaces.length + 1];
159:                    System.arraycopy(interfaces, 0, newInterfaces, 0,
160:                            interfaces.length);
161:
162:                    int indexElement = newInterfaces.length - 1;
163:
164:                    // Add the right interface (SLSB, SFSB, MDB)
165:                    if (classAnnotationMetadata.isStateless()) {
166:                        newInterfaces[indexElement] = Type
167:                                .getInternalName(EasyBeansSLSBLifeCycle.class);
168:                    } else if (classAnnotationMetadata.isStateful()) {
169:                        newInterfaces[indexElement] = Type
170:                                .getInternalName(EasyBeansSFSBLifeCycle.class);
171:                    } else if (classAnnotationMetadata.isMdb()) {
172:                        newInterfaces[indexElement] = Type
173:                                .getInternalName(EasyBeansMDBLifeCycle.class);
174:                    } else {
175:                        throw new IllegalStateException("Bean '"
176:                                + classAnnotationMetadata.getClassName()
177:                                + "' not SLSB, SFSB or MDB");
178:                    }
179:                } else {
180:                    newInterfaces = interfaces;
181:                }
182:
183:                super .visit(version, access, name, signature, super Name,
184:                        newInterfaces);
185:
186:            }
187:
188:            /**
189:             * Visits information about an inner class. This inner class is not
190:             * necessarily a member of the class being visited.
191:             * @param name the internal name of an inner class (see
192:             *        {@link org.ow2.easybeans.asm.Type#getInternalName() getInternalName}).
193:             * @param outerName the internal name of the class to which the inner class
194:             *        belongs (see
195:             *        {@link org.ow2.easybeans.asm.Type#getInternalName() getInternalName}).
196:             *        May be <tt>null</tt>.
197:             * @param innerName the (simple) name of the inner class inside its
198:             *        enclosing class. May be <tt>null</tt> for anonymous inner
199:             *        classes.
200:             * @param access the access flags of the inner class as originally declared
201:             *        in the enclosing class.
202:             */
203:            @Override
204:            public void visitInnerClass(final String name,
205:                    final String outerName, final String innerName,
206:                    final int access) {
207:                super .visitInnerClass(name, outerName, innerName, access);
208:            }
209:
210:            /**
211:             * Visits a method of the class. T
212:             * @param access the method's access flags (see {@link Opcodes}). This
213:             *        parameter also indicates if the method is synthetic and/or
214:             *        deprecated.
215:             * @param name the method's name.
216:             * @param desc the method's descriptor (see {@link org.ow2.easybeans.asm.Type}).
217:             * @param signature the method's signature. May be <tt>null</tt> if the
218:             *        method parameters, return type and exceptions do not use generic
219:             *        types.
220:             * @param exceptions the internal names of the method's exception classes
221:             *        (see
222:             *        {@link org.ow2.easybeans.asm.Type#getInternalName() getInternalName}).
223:             *        May be <tt>null</tt>.
224:             * @return an object to visit the byte code of the method, or <tt>null</tt>
225:             *         if this class visitor is not interested in visiting the code of
226:             *         this method.
227:             */
228:            @Override
229:            public MethodVisitor visitMethod(final int access,
230:                    final String name, final String desc,
231:                    final String signature, final String[] exceptions) {
232:                JMethod jMethod = new JMethod(access, name, desc, signature,
233:                        exceptions);
234:                String newName = name;
235:                int newAccess = access;
236:
237:                // Intercepted method : need to change the method name
238:                if (isInterceptedMethod(jMethod)) {
239:                    // Add the method as renamed
240:                    renamedMethods.add(jMethod);
241:
242:                    // Rename the method name
243:                    newName = MethodRenamer.encode(name);
244:                }
245:
246:                // Interceptor method : need to change access to public.
247:                if (!isDependencyInjectionMethod(jMethod)
248:                        && !isInjectedMethod(jMethod)
249:                        && isInterceptorMethod(jMethod)) {
250:                    // Change modifier to public
251:                    newAccess = Opcodes.ACC_PUBLIC;
252:                }
253:                return new MethodAdapter(super .visitMethod(newAccess, newName,
254:                        desc, signature, exceptions));
255:            }
256:
257:            /**
258:             * Visits the end of the class. This method, which is the last one to be
259:             * called, is used to inform the visitor that all the fields and methods of
260:             * the class have been visited.
261:             */
262:            @Override
263:            public void visitEnd() {
264:                super .visitEnd();
265:
266:                // For Bean only
267:                if (classAnnotationMetadata.isBean()) {
268:                    // Add default lifecycle methods. These methods will call defined
269:                    // lifecycle callback method and super methods or will do nothing.
270:                    MethodAnnotationMetadata posConsMetaData = generateBeanLifeCycleMethod(
271:                            classAnnotationMetadata, POST_CONSTRUCT);
272:                    MethodAnnotationMetadata preDesMetaData = generateBeanLifeCycleMethod(
273:                            classAnnotationMetadata, PRE_DESTROY);
274:                    MethodAnnotationMetadata postActMetaData = generateBeanLifeCycleMethod(
275:                            classAnnotationMetadata, POST_ACTIVATE);
276:                    MethodAnnotationMetadata prePassMetaData = generateBeanLifeCycleMethod(
277:                            classAnnotationMetadata, PRE_PASSIVATE);
278:
279:                    // Generate class for dependency injection
280:                    generateClass(new MethodAnnotationMetadata(
281:                            InjectionClassAdapter.INJECTED_JMETHOD,
282:                            classAnnotationMetadata), DEP_INJECT);
283:
284:                    // Generate class for timer
285:                    // Create the method by cloning the existing timer method
286:                    MethodAnnotationMetadata timerMethodAnnotationMetadata = null;
287:                    for (MethodAnnotationMetadata m : classAnnotationMetadata
288:                            .getMethodAnnotationMetadataCollection()) {
289:                        // Found the timer method ?
290:                        if (m.isTimeout()) {
291:                            // clone this method (to get the correct interceptors, etc)
292:                            timerMethodAnnotationMetadata = (MethodAnnotationMetadata) m
293:                                    .clone();
294:                            // Change the method name to the generated method
295:                            timerMethodAnnotationMetadata
296:                                    .setJMethod(BeanClassAdapter.TIMER_JMETHOD);
297:
298:                            // set the class
299:                            timerMethodAnnotationMetadata
300:                                    .setClassAnnotationMetadata(classAnnotationMetadata);
301:                            // It is not inherited as it's build on this class level
302:                            timerMethodAnnotationMetadata.setInherited(false,
303:                                    null);
304:                            break;
305:                        }
306:
307:                    }
308:                    // build an empty one if not built just before
309:                    if (timerMethodAnnotationMetadata == null) {
310:                        timerMethodAnnotationMetadata = new MethodAnnotationMetadata(
311:                                BeanClassAdapter.TIMER_JMETHOD,
312:                                classAnnotationMetadata);
313:                    }
314:                    // Generate the class
315:                    generateClass(timerMethodAnnotationMetadata, TIMED_OBJECT);
316:
317:                    // Need to generate the implementation of EasyBeansInvocationContext Impl on intercepted methods
318:                    for (MethodAnnotationMetadata method : classAnnotationMetadata
319:                            .getMethodAnnotationMetadataCollection()) {
320:
321:                        // No else if, need to generate an invocationcontext for each case
322:                        if (method.isBusinessMethod()) {
323:                            generateClass(method, AROUND_INVOKE);
324:
325:                            // method was not renamed (it is inherited), need to generate a method calling super method().
326:                            if (!renamedMethods.contains(method.getJMethod())) {
327:                                generateCallSuperEncodedMethod(method);
328:                            }
329:                        }
330:                    }
331:
332:                    // First method is the method that has been generated by the call to generateBeanLifeCycleMethod
333:                    // This is method which needs to be intercepted. (there is always
334:                    // one method as we added default method, so no need to check
335:                    // null list)
336:                    generateClass(posConsMetaData, POST_CONSTRUCT);
337:                    generateClass(preDesMetaData, PRE_DESTROY);
338:                    generateClass(prePassMetaData, PRE_PASSIVATE);
339:                    generateClass(postActMetaData, POST_ACTIVATE);
340:
341:                    // Then generate the interceptorManager
342:                    String generatedClName = classAnnotationMetadata
343:                            .getClassName()
344:                            + EasyBeansInvocationContextGenerator.SUFFIX_INTERCEPTOR_MANAGER;
345:                    InterceptorManagerGenerator interceptorManagerGenerator = new InterceptorManagerGenerator(
346:                            classAnnotationMetadata
347:                                    .getEjbJarAnnotationMetadata(),
348:                            generatedClName, beanInterceptors);
349:                    interceptorManagerGenerator.generate();
350:                    DefinedClass dc = new DefinedClass(generatedClName.replace(
351:                            "/", "."), interceptorManagerGenerator.getBytes());
352:                    // this class will be defined later on the classloader
353:                    definedClasses.add(dc);
354:
355:                }
356:            }
357:
358:            /**
359:             * Generates the call to InvocationContext impl proceed method after
360:             * building a new object. ie :
361:             *
362:             * <pre>
363:             * public int generatedMethodName(int a, int b) throws MyException {
364:             *     try {
365:             *         return ((Integer) new MethodAddInvocationContextImpl(this, a, b).proceed()).intValue();
366:             *     } catch (MyException e) {
367:             *         throw e;
368:             *     } catch (Exception e) {
369:             *         if (e instanceof RuntimeException) {
370:             *             throw (RuntimeException) e;
371:             *         } else {
372:             *             throw new RuntimeException(e);
373:             *         }
374:             *     }
375:             * }
376:             * </pre>
377:             *
378:             * @param method the annotation metadata of the method
379:             * @param genInvCtx the generator of the EasyBeansInvocationContext impl class.
380:             * @param interceptorType the type of method which is intercepted
381:             */
382:            private void generateCallToInvocationContext(
383:                    final MethodAnnotationMetadata method,
384:                    final EasyBeansInvocationContextGenerator genInvCtx,
385:                    final InterceptorType interceptorType) {
386:
387:                /**
388:                 * Method name, two cases :
389:                 *      - AroundInvoke : method = original name
390:                 *      - LifeCycle    : method = postConstructEasyBeansLifeCycle, preDestroyEasyBeansLifeCycle
391:                 */
392:                String generatedMethodName = null;
393:                switch (interceptorType) {
394:                case AROUND_INVOKE:
395:                    generatedMethodName = method.getMethodName();
396:                    break;
397:                case DEP_INJECT:
398:                case TIMED_OBJECT:
399:                    generatedMethodName = MethodRenamer.decode(method
400:                            .getMethodName());
401:                    break;
402:                case POST_CONSTRUCT:
403:                    generatedMethodName = "postConstructEasyBeansLifeCycle";
404:                    break;
405:                case PRE_DESTROY:
406:                    generatedMethodName = "preDestroyEasyBeansLifeCycle";
407:                    break;
408:                case PRE_PASSIVATE:
409:                    generatedMethodName = "prePassivateEasyBeansLifeCycle";
410:                    break;
411:                case POST_ACTIVATE:
412:                    generatedMethodName = "postActivateEasyBeansLifeCycle";
413:                    break;
414:                default:
415:                    throw new RuntimeException(
416:                            "No generated method name found for method '"
417:                                    + method.getMethodName() + "'");
418:                }
419:
420:                if (generatedMethodName == null) {
421:                    throw new RuntimeException(
422:                            "No generated method name found for method '"
423:                                    + method.getMethodName() + "'");
424:                }
425:
426:                // Adds a method which will call the invocationcontext impl
427:                MethodVisitor mv = cv.visitMethod(ACC_PUBLIC,
428:                        generatedMethodName, method.getJMethod()
429:                                .getDescriptor(), null, method.getJMethod()
430:                                .getExceptions());
431:                mv.visitCode();
432:
433:                // Start of the Try label of Try/Catch
434:                Label tryLabel = new Label();
435:                mv.visitLabel(tryLabel);
436:
437:                // build new object by calling the constructor
438:                mv.visitTypeInsn(NEW, genInvCtx.getGeneratedClassName());
439:                mv.visitInsn(DUP);
440:
441:                // Add bean (as first argument)
442:                mv.visitVarInsn(ALOAD, 0);
443:
444:                // for each argument
445:                Type[] args = Type.getArgumentTypes(method.getJMethod()
446:                        .getDescriptor());
447:                int methodArg = 1;
448:                for (Type type : args) {
449:                    int opCode = CommonClassGenerator.putFieldLoadOpCode(type
450:                            .getSort());
451:                    mv.visitVarInsn(opCode, methodArg);
452:                    // Double and Long are special parameters
453:                    if (opCode == LLOAD || opCode == DLOAD) {
454:                        methodArg++;
455:                    }
456:                    methodArg++;
457:                }
458:                Type returnType = Type.getReturnType(method.getJMethod()
459:                        .getDescriptor());
460:
461:                String constructorDesc = genInvCtx.getConstructorDesc();
462:                mv.visitMethodInsn(INVOKESPECIAL, genInvCtx
463:                        .getGeneratedClassName(), "<init>", constructorDesc);
464:                mv.visitMethodInsn(INVOKEVIRTUAL, genInvCtx
465:                        .getGeneratedClassName(), "proceed",
466:                        "()Ljava/lang/Object;");
467:
468:                CommonClassGenerator.transformObjectIntoPrimitive(returnType,
469:                        mv);
470:                CommonClassGenerator.addReturnType(returnType, mv);
471:
472:                boolean methodAlreadyThrowJavaLangException = false;
473:
474:                // Catch blocks
475:                String[] methodExceptions = method.getJMethod().getExceptions();
476:                // catch label = exceptions thrown by method + 1
477:                Label[] catchsLabel = null;
478:                if (methodExceptions != null) {
479:                    // if the java.lang.Exception is present, don't need two catchs
480:                    // blocks
481:                    // for java/lang/Exception
482:                    if (Arrays.asList(methodExceptions).contains(
483:                            "java/lang/Exception")) {
484:                        methodAlreadyThrowJavaLangException = true;
485:                        catchsLabel = new Label[methodExceptions.length];
486:                    } else {
487:                        // else, add a catch for java.lang.Exception
488:                        catchsLabel = new Label[methodExceptions.length + 1];
489:                    }
490:                } else {
491:                    catchsLabel = new Label[1];
492:                }
493:
494:                // init labels
495:                for (int i = 0; i < catchsLabel.length; i++) {
496:                    catchsLabel[i] = new Label();
497:                }
498:
499:                // First, do method exceptions (just rethrow the given exception)
500:                int lastCatchBlockLabel = 0;
501:                if (methodAlreadyThrowJavaLangException) {
502:                    lastCatchBlockLabel = catchsLabel.length;
503:                } else {
504:                    lastCatchBlockLabel = catchsLabel.length - 1;
505:                }
506:
507:                for (int block = 0; block < lastCatchBlockLabel; block++) {
508:                    mv.visitLabel(catchsLabel[block]);
509:                    mv.visitVarInsn(ASTORE, methodArg);
510:                    mv.visitVarInsn(ALOAD, methodArg);
511:                    mv.visitInsn(ATHROW);
512:                }
513:                // Now, do the wrapped of Exception into a RuntimeException
514:                if (!methodAlreadyThrowJavaLangException) {
515:                    // start label
516:                    mv.visitLabel(catchsLabel[lastCatchBlockLabel]);
517:                    mv.visitVarInsn(ASTORE, methodArg);
518:
519:                    // instanceof RuntimeException
520:                    mv.visitVarInsn(ALOAD, methodArg);
521:                    mv.visitTypeInsn(INSTANCEOF, "java/lang/RuntimeException");
522:                    Label notInstanceOfRuntimeExceptionLabel = new Label();
523:                    mv.visitJumpInsn(IFEQ, notInstanceOfRuntimeExceptionLabel);
524:
525:                    // throw existing runtime exception (by casting it)
526:                    mv.visitVarInsn(ALOAD, methodArg);
527:                    mv.visitTypeInsn(CHECKCAST, "java/lang/RuntimeException");
528:                    mv.visitInsn(ATHROW);
529:
530:                    // build Runtime exception with given exception
531:                    mv.visitLabel(notInstanceOfRuntimeExceptionLabel);
532:                    mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
533:                    mv.visitInsn(DUP);
534:                    mv.visitVarInsn(ALOAD, methodArg);
535:                    mv.visitMethodInsn(INVOKESPECIAL,
536:                            "java/lang/RuntimeException", "<init>",
537:                            "(Ljava/lang/Throwable;)V");
538:                    mv.visitInsn(ATHROW);
539:
540:                }
541:
542:                // Perform try/catch blocks with ASM
543:                int block = 0;
544:                // method exception
545:                if (methodExceptions != null) {
546:                    for (String exception : methodExceptions) {
547:                        mv.visitTryCatchBlock(tryLabel, catchsLabel[0],
548:                                catchsLabel[block], exception);
549:                        block++;
550:                    }
551:                }
552:                // Exception thrown by proceed() call
553:                if (!methodAlreadyThrowJavaLangException) {
554:                    mv.visitTryCatchBlock(tryLabel, catchsLabel[0],
555:                            catchsLabel[lastCatchBlockLabel],
556:                            "java/lang/Exception");
557:                }
558:
559:                mv.visitMaxs(0, 0);
560:                mv.visitEnd();
561:
562:            }
563:
564:            /**
565:             * Generate an invocation context object.
566:             * @param method intercepted method
567:             * @param interceptorType the type of method which is intercepted
568:             */
569:            private void generateClass(final MethodAnnotationMetadata method,
570:                    final InterceptorType interceptorType) {
571:                EasyBeansInvocationContextGenerator genInvCtx = new EasyBeansInvocationContextGenerator(
572:                        method, interceptorType);
573:                genInvCtx.generate();
574:
575:                // Get all interceptors used and that are not defined in the bean
576:                for (JClassInterceptor interceptor : genInvCtx
577:                        .getAllInterceptors()) {
578:                    String interceptorClassName = interceptor.getClassName();
579:                    if (!interceptorClassName.equals(classAnnotationMetadata
580:                            .getClassName())) {
581:                        if (!beanInterceptors.contains(interceptorClassName)) {
582:                            beanInterceptors.add(interceptorClassName);
583:                        }
584:                    }
585:                }
586:                DefinedClass dc = new DefinedClass(genInvCtx
587:                        .getGeneratedClassName().replace("/", "."), genInvCtx
588:                        .getBytes());
589:                // this class will be defined later on the classloader
590:                definedClasses.add(dc);
591:                generatedTypes.add(interceptorType);
592:                // generate method calling generated EasyBeansInvocationContext impl
593:                generateCallToInvocationContext(method, genInvCtx,
594:                        interceptorType);
595:
596:            }
597:
598:            /**
599:             * Generates a call to the method defined in the super class.
600:             * public int original$add(int i, int j) {
601:             *     return super.add(i, j);
602:             * }
603:             * @param method the annotation metadata of the method
604:             */
605:            private void generateCallSuperEncodedMethod(
606:                    final MethodAnnotationMetadata method) {
607:
608:                String generatedMethodName = MethodRenamer.encode(method
609:                        .getMethodName());
610:                JMethod jMethod = method.getJMethod();
611:                MethodVisitor mv = cv.visitMethod(jMethod.getAccess(),
612:                        generatedMethodName, jMethod.getDescriptor(), jMethod
613:                                .getSignature(), jMethod.getExceptions());
614:                mv.visitCode();
615:
616:                // Add bean (as first argument)
617:                mv.visitVarInsn(ALOAD, 0);
618:
619:                // for each argument
620:                Type[] args = Type.getArgumentTypes(jMethod.getDescriptor());
621:                int methodArg = 1;
622:                for (Type type : args) {
623:                    int opCode = CommonClassGenerator.putFieldLoadOpCode(type
624:                            .getSort());
625:                    mv.visitVarInsn(opCode, methodArg);
626:                    // Double and Long are special parameters
627:                    if (opCode == LLOAD || opCode == DLOAD) {
628:                        methodArg++;
629:                    }
630:                    methodArg++;
631:                }
632:
633:                // call super class method()
634:                mv.visitMethodInsn(INVOKESPECIAL, method
635:                        .getClassAnnotationMetadata().getSuperName(), jMethod
636:                        .getName(), jMethod.getDescriptor());
637:
638:                Type returnType = Type.getReturnType(jMethod.getDescriptor());
639:                CommonClassGenerator.addReturnType(returnType, mv);
640:
641:                mv.visitMaxs(0, 0);
642:                mv.visitEnd();
643:            }
644:
645:            /**
646:             * Generates a default method for lifecycle method events.
647:             * It will call the methods in the super classes of the defined method.
648:             * @param classMetaData the metadata used to generate method metadata
649:             * @param interceptorType the type of intercepted method
650:             * @return the generated method metadata
651:             */
652:            private MethodAnnotationMetadata generateBeanLifeCycleMethod(
653:                    final ClassAnnotationMetadata classMetaData,
654:                    final InterceptorType interceptorType) {
655:                String generatedMethodName = null;
656:                List<MethodAnnotationMetadata> existingLifecycleMethods = null;
657:                switch (interceptorType) {
658:                case AROUND_INVOKE:
659:                case DEP_INJECT:
660:                case TIMED_OBJECT:
661:                    //Nothing to generate
662:                    return null;
663:                case POST_CONSTRUCT:
664:                    generatedMethodName = "beanPostConstruct$generated";
665:                    existingLifecycleMethods = classMetaData
666:                            .getPostConstructMethodsMetadata();
667:                    break;
668:                case PRE_DESTROY:
669:                    generatedMethodName = "beanPreDestroy$generated";
670:                    existingLifecycleMethods = classMetaData
671:                            .getPreDestroyMethodsMetadata();
672:                    break;
673:                case PRE_PASSIVATE:
674:                    generatedMethodName = "beanPrePassivate$generated";
675:                    existingLifecycleMethods = classMetaData
676:                            .getPrePassivateMethodsMetadata();
677:                    break;
678:                case POST_ACTIVATE:
679:                    generatedMethodName = "beanPostActivate$generated";
680:                    existingLifecycleMethods = classMetaData
681:                            .getPostActivateMethodsMetadata();
682:                    break;
683:                default:
684:                    throw new RuntimeException(
685:                            "No generated method name found for interceptorType '"
686:                                    + interceptorType + "'");
687:                }
688:
689:                // Generates the body of this method.
690:                MethodVisitor mv = cv.visitMethod(ACC_PUBLIC,
691:                        generatedMethodName, "()V", null, null);
692:                mv.visitCode();
693:                // Call methods in their order (if any)
694:                if (existingLifecycleMethods != null) {
695:                    for (MethodAnnotationMetadata method : existingLifecycleMethods) {
696:                        // Inherited or not ?
697:                        String clName = method.getClassAnnotationMetadata()
698:                                .getClassName();
699:                        mv.visitVarInsn(ALOAD, 0);
700:                        int opcode = INVOKEVIRTUAL;
701:                        if (method.isInherited()) {
702:                            clName = method
703:                                    .getOriginalClassAnnotationMetadata()
704:                                    .getClassName();
705:                            opcode = INVOKESPECIAL;
706:                        }
707:                        mv.visitMethodInsn(opcode, clName, method
708:                                .getMethodName(), method.getJMethod()
709:                                .getDescriptor());
710:                    }
711:                }
712:
713:                mv.visitInsn(RETURN);
714:                mv.visitMaxs(0, 0);
715:                mv.visitEnd();
716:
717:                // add method in the class metadata
718:                JMethod method = new JMethod(ACC_PUBLIC, generatedMethodName,
719:                        "()V", null, null);
720:                MethodAnnotationMetadata generatedMetadata = new MethodAnnotationMetadata(
721:                        method, classMetaData);
722:
723:                // Set value
724:                switch (interceptorType) {
725:                case POST_CONSTRUCT:
726:                    generatedMetadata.setPostConstruct(true);
727:                    break;
728:                case PRE_DESTROY:
729:                    generatedMetadata.setPreDestroy(true);
730:                    break;
731:                case PRE_PASSIVATE:
732:                    generatedMetadata.setPrePassivate(true);
733:                    break;
734:                case POST_ACTIVATE:
735:                    generatedMetadata.setPostActivate(true);
736:                    break;
737:                default:
738:                    throw new RuntimeException(
739:                            "No generated method name found for interceptorType '"
740:                                    + interceptorType + "'");
741:                }
742:
743:                classMetaData.addMethodAnnotationMetadata(generatedMetadata);
744:                return generatedMetadata;
745:            }
746:
747:            /**
748:             * Check if this method is the injected method used for dependency injection.
749:             * @param jMethod object to check
750:             * @return true if the given method is the injected method used for dependency
751:             *         injection
752:             */
753:            private boolean isDependencyInjectionMethod(final JMethod jMethod) {
754:                return InjectionClassAdapter.INJECTED_METHOD.equals(jMethod
755:                        .getName());
756:            }
757:
758:            /**
759:             * Check if this method is injected or not by injection class adapter : No need to add interceptors on these methods.
760:             * @param jMethod object to check
761:             * @return true if the given method is injected by injection class adapter.
762:             */
763:            private boolean isInjectedMethod(final JMethod jMethod) {
764:                for (String method : InjectionClassAdapter.INJECTED_METHODS) {
765:                    if (method.equals(jMethod.getName())) {
766:                        return true;
767:                    }
768:                }
769:                return false;
770:            }
771:
772:            /**
773:             * @param jMethod object to check
774:             * @return true if the given method is an intercepted method
775:             * (and business method) because lifecycle methods are not renamed
776:             */
777:            private boolean isInterceptedMethod(final JMethod jMethod) {
778:                // needs to be intercepted
779:                if (isDependencyInjectionMethod(jMethod)) {
780:                    return classAnnotationMetadata.isBean();
781:                }
782:
783:                // other injected methods are helper methods (and not business --> no need to intercept them)
784:                if (isInjectedMethod(jMethod)) {
785:                    return false;
786:                }
787:
788:                // get method metadata
789:                MethodAnnotationMetadata method = classAnnotationMetadata
790:                        .getMethodAnnotationMetadata(jMethod);
791:                if (method == null) {
792:                    throw new IllegalStateException("Cannot find a method "
793:                            + jMethod + " in class "
794:                            + classAnnotationMetadata.getClassName());
795:                }
796:                return method.isBusinessMethod();
797:            }
798:
799:            /**
800:             * @param jMethod object to check
801:             * @return true if the given method is an interceptor method (ie AroundInvoke, PostConstruct, etc).
802:             */
803:            private boolean isInterceptorMethod(final JMethod jMethod) {
804:                // get method metadata
805:                MethodAnnotationMetadata method = classAnnotationMetadata
806:                        .getMethodAnnotationMetadata(jMethod);
807:                if (method == null) {
808:                    throw new IllegalStateException("Cannot find a method "
809:                            + jMethod + " in class "
810:                            + classAnnotationMetadata.getClassName());
811:                }
812:                return (method.isAroundInvoke() || method.isLifeCycleMethod());
813:            }
814:
815:            /**
816:             * @return list of classes generated and that need to be defined in a
817:             *         classloader
818:             */
819:            public List<DefinedClass> getDefinedClasses() {
820:                return definedClasses;
821:            }
822:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.