0001: /**
0002: * EasyBeans
0003: * Copyright (C) 2006 Bull S.A.S.
0004: * Contact: easybeans@ow2.org
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation; either
0009: * version 2.1 of the License, or any later version.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: *
0016: * You should have received a copy of the GNU Lesser General Public
0017: * License along with this library; if not, write to the Free Software
0018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
0019: * USA
0020: *
0021: * --------------------------------------------------------------------------
0022: * $Id: EasyBeansInvocationContextGenerator.java 2057 2007-11-21 15:35:32Z benoitf $
0023: * --------------------------------------------------------------------------
0024: */package org.ow2.easybeans.enhancer.interceptors;
0025:
0026: import static org.ow2.easybeans.deployment.annotations.InterceptorType.AROUND_INVOKE;
0027:
0028: import java.io.File;
0029: import java.io.FileOutputStream;
0030: import java.util.ArrayList;
0031: import java.util.List;
0032:
0033: import org.ow2.easybeans.asm.ClassWriter;
0034: import org.ow2.easybeans.asm.Label;
0035: import org.ow2.easybeans.asm.MethodVisitor;
0036: import org.ow2.easybeans.asm.Type;
0037: import org.ow2.easybeans.api.EasyBeansInvocationContext;
0038: import org.ow2.easybeans.deployment.annotations.InterceptorType;
0039: import org.ow2.easybeans.deployment.annotations.JClassInterceptor;
0040: import org.ow2.easybeans.deployment.annotations.JMethod;
0041: import org.ow2.easybeans.deployment.annotations.metadata.ClassAnnotationMetadata;
0042: import org.ow2.easybeans.deployment.annotations.metadata.EjbJarAnnotationMetadata;
0043: import org.ow2.easybeans.deployment.annotations.metadata.MethodAnnotationMetadata;
0044: import org.ow2.easybeans.enhancer.CommonClassGenerator;
0045: import org.ow2.easybeans.enhancer.lib.MethodRenamer;
0046: import org.ow2.util.log.Log;
0047: import org.ow2.util.log.LogFactory;
0048:
0049: /**
0050: * Generates the implementation of
0051: * {@link org.ow2.easybeans.api.EasyBeansInvocationContext} interface for a
0052: * given business method.
0053: * @author Florent Benoit
0054: */
0055: public class EasyBeansInvocationContextGenerator extends
0056: CommonClassGenerator {
0057:
0058: /**
0059: * Prefix used as package name for generated classes
0060: * (EasyBeansInvocationContext* impl).
0061: */
0062: public static final String PACKAGE_NAME_PREFIX = "org.ow2.easybeans.gen.invocationcontext.";
0063:
0064: /**
0065: * Name of the attributes will start with this name with an index as suffix,
0066: * ie : arg0, arg1, arg2,...
0067: */
0068: public static final String ARG = "arg";
0069:
0070: /**
0071: * Name of the interceptor attributes will start with this name with an index as suffix,
0072: * ie : interceptor0, interceptor1, interceptor2,...
0073: */
0074: public static final String INTERCEPTOR = "interceptor";
0075:
0076: /**
0077: * Suffix for generated classes EasyBeansInvocationContextImpl.
0078: */
0079: public static final String SUFFIX_CLASS = "EasyBeansInvocationContextImpl";
0080:
0081: /**
0082: * Interface of this invocation context.
0083: */
0084: public static final String[] INTERFACES = new String[] { "org/ow2/easybeans/api/EasyBeansInvocationContext" };
0085:
0086: /**
0087: * Exceptions of the proceed method.
0088: */
0089: public static final String[] PROCEED_EXCEPTIONS = new String[] { Type
0090: .getInternalName(Exception.class) };
0091:
0092: /**
0093: * EasyBeansInvocationContext interface.
0094: */
0095: public static final String EASYBEANS_INVOCATION_CONTEXT = Type
0096: .getDescriptor(EasyBeansInvocationContext.class);
0097:
0098: /**
0099: * Logger.
0100: */
0101: private static Log logger = LogFactory
0102: .getLog(EasyBeansInvocationContextGenerator.class);
0103:
0104: /**
0105: * Metadata available for a class (extracted from method metadat object.
0106: * (parent))
0107: */
0108: private ClassAnnotationMetadata classAnnotationMetadata = null;
0109:
0110: /**
0111: * Package name which is used for generating class.
0112: */
0113: private String packageName = null;
0114:
0115: /**
0116: * Full class name of the generated class (prefixed by packageName).
0117: */
0118: private String generatedClassName = null;
0119:
0120: /**
0121: * JMethod object which correspond to the current method metadata which is
0122: * used.
0123: */
0124: private JMethod jMethod = null;
0125:
0126: /**
0127: * Metadata available for a method (given as constructor arg).
0128: */
0129: private MethodAnnotationMetadata methodAnnotationMetadata;
0130:
0131: /**
0132: * Bean class descriptor.
0133: */
0134: private String beanClassDesc = null;
0135:
0136: /**
0137: * Bean class name.
0138: */
0139: private String beanClassName = null;
0140:
0141: /**
0142: * Bean class Type (ASM).
0143: */
0144: private Type beanClassType = null;
0145:
0146: /**
0147: * ASM descriptor of the generated constructor.
0148: */
0149: private String constructorDesc = null;
0150:
0151: /**
0152: * ASM Type arguments of the method.
0153: */
0154: private Type[] methodArgsType = null;
0155:
0156: /**
0157: * List of interceptors.
0158: */
0159: private List<JClassInterceptor> allInterceptors = null;
0160:
0161: /**
0162: * Type of the interceptor (AroundInvoke, PostConstruct, etc).
0163: */
0164: private InterceptorType interceptorType = null;
0165:
0166: /**
0167: * Name of the interceptor manager class.
0168: */
0169: private String interceptorManagerClassName = null;
0170:
0171: /**
0172: * Suffix for InterceptorManager.
0173: */
0174: public static final String SUFFIX_INTERCEPTOR_MANAGER = "InterceptorManager";
0175:
0176: /**
0177: * Constructor It will generate a class for the given method metadata.
0178: * @param methodAnnotationMetadata method meta data
0179: * @param interceptorType the type of invocationContext to generate (AroundInvoke, PostConstruct, etc)
0180: */
0181: public EasyBeansInvocationContextGenerator(
0182: final MethodAnnotationMetadata methodAnnotationMetadata,
0183: final InterceptorType interceptorType) {
0184: super (new ClassWriter(ClassWriter.COMPUTE_MAXS));
0185: this .methodAnnotationMetadata = methodAnnotationMetadata;
0186: this .classAnnotationMetadata = methodAnnotationMetadata
0187: .getClassAnnotationMetadata();
0188: this .jMethod = methodAnnotationMetadata.getJMethod();
0189:
0190: // package name is prefixed
0191: packageName = PACKAGE_NAME_PREFIX
0192: + classAnnotationMetadata.getClassName();
0193:
0194: // Type of the generated interceptor
0195: this .interceptorType = interceptorType;
0196:
0197: this .interceptorManagerClassName = classAnnotationMetadata
0198: .getClassName()
0199: + SUFFIX_INTERCEPTOR_MANAGER;
0200:
0201: // Name of the class that is generated
0202: generatedClassName = packageName.replace(".", "/") + "/"
0203: + SUFFIX_CLASS;
0204: generatedClassName += methodAnnotationMetadata.getJMethod()
0205: .getName()
0206: + interceptorType.name().replace("_", "");
0207: // Also, as two methods with the same name but different parameters will produce the same class name,
0208: // add the hashcode of the ASM descriptor.
0209: generatedClassName += methodAnnotationMetadata.getJMethod()
0210: .getDescriptor().hashCode();
0211:
0212: // useful constants
0213: beanClassDesc = encodeClassDesc(classAnnotationMetadata
0214: .getClassName());
0215: beanClassName = classAnnotationMetadata.getClassName();
0216: beanClassType = Type.getType(beanClassDesc);
0217:
0218: // type arguments of the method
0219: methodArgsType = Type.getArgumentTypes(jMethod.getDescriptor());
0220:
0221: // build a list of all interceptors (first = global then method then users)
0222: allInterceptors = new ArrayList<JClassInterceptor>();
0223: if (classAnnotationMetadata.getGlobalEasyBeansInterceptors() != null) {
0224: for (JClassInterceptor interceptor : classAnnotationMetadata
0225: .getGlobalEasyBeansInterceptors()) {
0226: allInterceptors.add(interceptor);
0227: }
0228: }
0229:
0230: // global interceptor on the method (remove annotation for example)
0231: if (methodAnnotationMetadata.getGlobalEasyBeansInterceptors() != null) {
0232: for (JClassInterceptor interceptor : methodAnnotationMetadata
0233: .getGlobalEasyBeansInterceptors()) {
0234: allInterceptors.add(interceptor);
0235: }
0236: }
0237:
0238: // Get interceptors on method metadata (tx, security, etc)
0239: if (methodAnnotationMetadata.getInterceptors() != null) {
0240: for (JClassInterceptor interceptor : methodAnnotationMetadata
0241: .getInterceptors()) {
0242: allInterceptors.add(interceptor);
0243: }
0244: }
0245:
0246: // Default interceptors (if they are not excluded) and that the interceptors haven't been ordered
0247: EjbJarAnnotationMetadata ejbJarAnnotationMetadata = classAnnotationMetadata
0248: .getEjbJarAnnotationMetadata();
0249: if (!classAnnotationMetadata.isOrderedInterceptors()
0250: && ejbJarAnnotationMetadata.getDefaultInterceptors() != null
0251: && !classAnnotationMetadata
0252: .isExcludedDefaultInterceptors()) {
0253: // Not excluded at method level too
0254: if (!methodAnnotationMetadata
0255: .isExcludedDefaultInterceptors()) {
0256: List<JClassInterceptor> defaultInterceptorslist = ejbJarAnnotationMetadata
0257: .getDefaultInterceptors().get(interceptorType);
0258: if (defaultInterceptorslist != null) {
0259: for (JClassInterceptor interceptor : defaultInterceptorslist) {
0260: allInterceptors.add(interceptor);
0261: }
0262: }
0263: }
0264: }
0265:
0266: // interceptors in the interceptor classes (user) + not excluded
0267: if (classAnnotationMetadata
0268: .getExternalUserEasyBeansInterceptors() != null
0269: && !methodAnnotationMetadata
0270: .isExcludedClassInterceptors()) {
0271: List<JClassInterceptor> userInterceptorslist = classAnnotationMetadata
0272: .getExternalUserEasyBeansInterceptors().get(
0273: interceptorType);
0274: if (userInterceptorslist != null) {
0275: for (JClassInterceptor interceptor : userInterceptorslist) {
0276: allInterceptors.add(interceptor);
0277: }
0278: }
0279: }
0280:
0281: // interceptors on the method (user)
0282: if (methodAnnotationMetadata.getUserEasyBeansInterceptors() != null) {
0283: List<JClassInterceptor> userInterceptorslist = methodAnnotationMetadata
0284: .getUserEasyBeansInterceptors()
0285: .get(interceptorType);
0286: if (userInterceptorslist != null) {
0287: for (JClassInterceptor interceptor : userInterceptorslist) {
0288: allInterceptors.add(interceptor);
0289: }
0290: }
0291: }
0292:
0293: // interceptors on the bean class (user) + not excluded and that the interceptors haven't been ordered
0294: if (!classAnnotationMetadata.isOrderedInterceptors()
0295: && classAnnotationMetadata
0296: .getInternalUserEasyBeansInterceptors() != null
0297: && !methodAnnotationMetadata
0298: .isExcludedClassInterceptors()) {
0299: List<JClassInterceptor> userInterceptorslist = classAnnotationMetadata
0300: .getInternalUserEasyBeansInterceptors().get(
0301: interceptorType);
0302: if (userInterceptorslist != null) {
0303: for (JClassInterceptor interceptor : userInterceptorslist) {
0304: allInterceptors.add(interceptor);
0305: }
0306: }
0307: }
0308: }
0309:
0310: /**
0311: * Generates the class. It call sub methods for being more clear for read
0312: * the code
0313: */
0314: public void generate() {
0315: if (logger.isDebugEnabled()) {
0316: logger.debug("Generating InvocationContext for Method "
0317: + jMethod + " of class " + beanClassName);
0318: }
0319:
0320: addClassDeclaration();
0321: addAttributes();
0322: addConstructor();
0323: addStaticClassInitialization();
0324: addMethods();
0325: endClass();
0326:
0327: if (logger.isDebugEnabled()) {
0328: String fName = System.getProperty("java.io.tmpdir")
0329: + File.separator
0330: + generatedClassName.replace("/", ".") + ".class";
0331: logger.debug("Writing Invocation context of method "
0332: + methodAnnotationMetadata.getMethodName() + " to "
0333: + fName);
0334: try {
0335: FileOutputStream fos = new FileOutputStream(fName);
0336: fos.write(getCW().toByteArray());
0337: fos.close();
0338: } catch (Exception e) {
0339: throw new RuntimeException(e);
0340: }
0341: }
0342: }
0343:
0344: /**
0345: * @return the bytecode of the generated class.
0346: */
0347: public byte[] getBytes() {
0348: return getCW().toByteArray();
0349: }
0350:
0351: /**
0352: * Creates the declaration of the class with the given interfaces.
0353: */
0354: private void addClassDeclaration() {
0355: // create class
0356: getCW().visit(GENERATED_CLASS_VERSION, ACC_PUBLIC + ACC_SUPER,
0357: generatedClassName, null, "java/lang/Object",
0358: INTERFACES);
0359: }
0360:
0361: /**
0362: * Create the constructor which should look like :
0363: * <ul>
0364: * <li> First arg = bean instance</li>
0365: * <li> Last args are arguments of the method (if any)</li>
0366: * </ul>
0367: * <br>
0368: *
0369: * <pre>
0370: * public CtxImpl(Bean bean, int i, Long k, ...) {
0371: * this.bean = bean;
0372: * this.factory = bean.getEasyBeansFactory();
0373: * this.interceptorManager = bean.getEasyBeansInterceptorManager();
0374: * this.i = i;
0375: * this.k = k;
0376: * this... = ...
0377: * this.interceptor0 = interceptorManager.getXXXInterceptor();
0378: * this.interceptor1 = interceptorManager....();
0379: * }
0380: * </pre>
0381: */
0382: private void addConstructor() {
0383:
0384: // First, get the desc of the intercepted method
0385: String argsMethodDesc = "";
0386: for (Type t : methodArgsType) {
0387: argsMethodDesc += t.getDescriptor();
0388: }
0389:
0390: // Add the bean class type before arguments
0391: // public CtxImpl(Bean bean, <args of the method>)
0392: // it is a void type for return type
0393: constructorDesc = "(" + beanClassDesc + argsMethodDesc + ")V";
0394:
0395: // Generate constructor
0396: MethodVisitor mv = getCW().visitMethod(ACC_PUBLIC, "<init>",
0397: constructorDesc, null, null);
0398: mv.visitCode();
0399:
0400: // Call super constructor
0401: int arg = 1;
0402: mv.visitVarInsn(ALOAD, 0);
0403: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>",
0404: "()V");
0405:
0406: // Now, set the attributes of the class
0407: // this.bean = bean
0408: int argBean = arg++;
0409: mv.visitVarInsn(ALOAD, 0);
0410: mv.visitVarInsn(ALOAD, argBean);
0411: mv
0412: .visitFieldInsn(PUTFIELD, generatedClassName, "bean",
0413: encodeClassDesc(classAnnotationMetadata
0414: .getClassName()));
0415:
0416: // this.factory = bean.getEasyBeansFactory();
0417: mv.visitVarInsn(ALOAD, 0);
0418: mv.visitVarInsn(ALOAD, argBean);
0419: mv.visitMethodInsn(INVOKEVIRTUAL, classAnnotationMetadata
0420: .getClassName(), "getEasyBeansFactory",
0421: "()Lorg/ow2/easybeans/api/Factory;");
0422: mv.visitFieldInsn(PUTFIELD, generatedClassName, "factory",
0423: "Lorg/ow2/easybeans/api/Factory;");
0424:
0425: // this.interceptorManager = bean.getEasyBeansInterceptorManager();
0426: mv.visitVarInsn(ALOAD, 0);
0427: mv.visitVarInsn(ALOAD, argBean);
0428: mv.visitMethodInsn(INVOKEVIRTUAL, classAnnotationMetadata
0429: .getClassName(), "getEasyBeansInterceptorManager", "()"
0430: + encodeClassDesc(interceptorManagerClassName));
0431: mv.visitFieldInsn(PUTFIELD, generatedClassName,
0432: "interceptorManager",
0433: encodeClassDesc(interceptorManagerClassName));
0434:
0435: // And now, the attributes corresponding to the arguments of the method
0436: // it will do : this.ARG0 = xxx;
0437: int methodArg = 0;
0438: for (Type type : methodArgsType) {
0439: mv.visitVarInsn(ALOAD, 0);
0440: int opCode = putFieldLoadOpCode(type.getSort());
0441: mv.visitVarInsn(opCode, arg++);
0442: mv.visitFieldInsn(PUTFIELD, generatedClassName, ARG
0443: + (methodArg++), type.getDescriptor());
0444: // Double and Long are special parameters
0445: if (opCode == LLOAD || opCode == DLOAD) {
0446: arg++;
0447: }
0448: }
0449:
0450: // this.interceptorXX = interceptorManager.getXXXInterceptor();
0451: int index = 0;
0452: for (JClassInterceptor interceptor : allInterceptors) {
0453: // Only if interceptor is not in the bean class
0454: if (!interceptor.getClassName().equals(beanClassName)) {
0455: mv.visitVarInsn(ALOAD, 0);
0456: mv.visitVarInsn(ALOAD, 0);
0457: mv.visitFieldInsn(GETFIELD, generatedClassName,
0458: "interceptorManager",
0459: encodeClassDesc(interceptorManagerClassName));
0460: String getterName = "get"
0461: + interceptor.getClassName().replace("/", "");
0462: mv.visitMethodInsn(INVOKEVIRTUAL,
0463: interceptorManagerClassName, getterName, "()"
0464: + encodeClassDesc(interceptor
0465: .getClassName()));
0466: mv.visitFieldInsn(PUTFIELD, generatedClassName,
0467: INTERCEPTOR + (index++),
0468: encodeClassDesc(interceptor.getClassName()));
0469: }
0470: }
0471:
0472: // need to add return instruction
0473: mv.visitInsn(RETURN);
0474:
0475: // visit max compute automatically
0476: mv.visitMaxs(0, 0);
0477: mv.visitEnd();
0478:
0479: }
0480:
0481: /**
0482: * Called when the generated class is done.
0483: */
0484: private void endClass() {
0485: getCW().visitEnd();
0486: }
0487:
0488: /**
0489: * Add attributes of the class in two steps.
0490: * <ul>
0491: * <li>InvocationContext interface</li>
0492: * <li>EasyBeansInvocationContext interface</li>
0493: * </ul>
0494: */
0495: private void addAttributes() {
0496: addInvocationContextAttributes();
0497: addEasyBeansInvocationContextAttributes();
0498:
0499: }
0500:
0501: /**
0502: * Add methods of the class in two steps.
0503: * <ul>
0504: * <li>InvocationContext interface</li>
0505: * <li>EasyBeansInvocationContext interface</li>
0506: * <li>toString() method</li>
0507: * </ul>
0508: */
0509: private void addMethods() {
0510: addInvocationContextMethods();
0511: addEasyBeansInvocationContextMethods();
0512: addToString();
0513:
0514: }
0515:
0516: /**
0517: * Add methods for InvocationContext interface.
0518: */
0519: private void addInvocationContextMethods() {
0520: addInvocationContextGetParameters();
0521: addInvocationContextSetParameters();
0522: addInvocationContextGetMethod();
0523: addInvocationContextGetTarget();
0524: addInvocationContextProceed();
0525: addInvocationContextGetContextData();
0526: }
0527:
0528: /**
0529: * Add methods for EasyBeansInvocationContext interface.
0530: */
0531: private void addEasyBeansInvocationContextMethods() {
0532:
0533: addEasyBeansInvocationContextGetFactory();
0534:
0535: }
0536:
0537: /**
0538: * Adds the getTarget method of InvocationContext interface.<br>
0539: * It adds :
0540: *
0541: * <pre>
0542: * public Object getTarget() {
0543: * return bean;
0544: * }
0545: * </pre>
0546: */
0547: private void addInvocationContextGetTarget() {
0548: MethodVisitor mv = getCW().visitMethod(ACC_PUBLIC, "getTarget",
0549: "()Ljava/lang/Object;", null, null);
0550: mv.visitCode();
0551: mv.visitVarInsn(ALOAD, 0);
0552: mv.visitFieldInsn(GETFIELD, generatedClassName, "bean",
0553: beanClassDesc);
0554: mv.visitInsn(ARETURN);
0555: mv.visitMaxs(0, 0);
0556: mv.visitEnd();
0557: }
0558:
0559: /**
0560: * Adds the getFactory method of EasyBeansInvocationContext interface.<br>
0561: * It adds :
0562: *
0563: * <pre>
0564: * public Factory getFactory() {
0565: * return this.factory;
0566: * }
0567: * </pre>
0568: */
0569: private void addEasyBeansInvocationContextGetFactory() {
0570: MethodVisitor mv = getCW().visitMethod(ACC_PUBLIC,
0571: "getFactory", "()" + EASYBEANS_FACTORY, null, null);
0572: mv.visitCode();
0573: mv.visitVarInsn(ALOAD, 0);
0574: mv.visitFieldInsn(GETFIELD, generatedClassName, "factory",
0575: EASYBEANS_FACTORY);
0576: mv.visitInsn(ARETURN);
0577: mv.visitMaxs(0, 0);
0578: mv.visitEnd();
0579:
0580: }
0581:
0582: /**
0583: * Adds the getMethod() method of InvocationContext interface.<br>
0584: * It adds :
0585: *
0586: * <pre>
0587: * public Method getMethod() {
0588: * if (method == null) {
0589: * try {
0590: * method = MyEjb.class.getMethod("methodName", new Class[] {xxx, yyy, ...});
0591: * } catch (SecurityException e) {
0592: * throw new RuntimeException("Cannot...", e);
0593: * } catch (NoSuchMethodException e) {
0594: * throw new RuntimeException("Cannot...", e);
0595: * }
0596: * }
0597: * return method;
0598: * }
0599: * </pre>
0600: */
0601: private void addInvocationContextGetMethod() {
0602: MethodVisitor mv = getCW().visitMethod(ACC_PUBLIC, "getMethod",
0603: "()" + JAVA_LANG_REFLECT_METHOD, null, null);
0604: mv.visitCode();
0605:
0606: // only for around invoke type, lifecycle interceptor should return null
0607: if (interceptorType == AROUND_INVOKE) {
0608:
0609: // if (method == null) {
0610: mv.visitFieldInsn(GETSTATIC, generatedClassName, "method",
0611: JAVA_LANG_REFLECT_METHOD);
0612: // go to this label if not null
0613: Label notNullParametersLabel = new Label();
0614: mv.visitJumpInsn(IFNONNULL, notNullParametersLabel);
0615:
0616: // Start of the try block
0617: Label tryLabel = new Label();
0618: mv.visitLabel(tryLabel);
0619:
0620: // call a method on the bean class
0621: mv.visitLdcInsn(beanClassType);
0622: // name of the method which is searched
0623: mv.visitLdcInsn(jMethod.getName());
0624:
0625: // build an array of java.lang.Class with the size of args of the method
0626: mv.visitIntInsn(BIPUSH, methodArgsType.length);
0627: mv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
0628: int argCount = 0;
0629: for (Type type : methodArgsType) {
0630: mv.visitInsn(DUP);
0631: mv.visitIntInsn(BIPUSH, argCount);
0632: visitClassType(type, mv);
0633: mv.visitInsn(AASTORE);
0634: argCount++;
0635: }
0636:
0637: // signature of the getMethod() method on java.lang.Class class
0638: mv
0639: .visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class",
0640: "getMethod",
0641: "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
0642:
0643: // set the result : method = ...
0644: mv.visitFieldInsn(PUTSTATIC, generatedClassName, "method",
0645: "Ljava/lang/reflect/Method;");
0646:
0647: // go to the return label
0648: mv.visitJumpInsn(GOTO, notNullParametersLabel);
0649:
0650: // start of the catch label which throw a runtime exception
0651: // } catch (SecurityException e) {
0652: // throw new RuntimeException("Cannot...", e);
0653: // }
0654: Label firstCatchLabel = new Label();
0655: mv.visitLabel(firstCatchLabel);
0656: mv.visitVarInsn(ASTORE, 1);
0657: mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
0658: mv.visitInsn(DUP);
0659: mv
0660: .visitLdcInsn("Cannot find method due to a security exception");
0661: mv.visitVarInsn(ALOAD, 1);
0662: mv.visitMethodInsn(INVOKESPECIAL,
0663: "java/lang/RuntimeException", "<init>",
0664: "(Ljava/lang/String;Ljava/lang/Throwable;)V");
0665: mv.visitInsn(ATHROW);
0666:
0667: // } catch (NoSuchMethodException e) {
0668: // throw new RuntimeException("Cannot...", e);
0669: // }
0670: Label secondCatchLabel = new Label();
0671: mv.visitLabel(secondCatchLabel);
0672: mv.visitVarInsn(ASTORE, 1);
0673: mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
0674: mv.visitInsn(DUP);
0675: mv.visitLdcInsn("Cannot find the method");
0676: mv.visitVarInsn(ALOAD, 1);
0677: mv.visitMethodInsn(INVOKESPECIAL,
0678: "java/lang/RuntimeException", "<init>",
0679: "(Ljava/lang/String;Ljava/lang/Throwable;)V");
0680: mv.visitInsn(ATHROW);
0681:
0682: // if method is not null, return it
0683: mv.visitLabel(notNullParametersLabel);
0684: mv.visitFieldInsn(GETSTATIC, generatedClassName, "method",
0685: JAVA_LANG_REFLECT_METHOD);
0686: mv.visitInsn(ARETURN);
0687:
0688: // add try/cacth
0689: mv.visitTryCatchBlock(tryLabel, firstCatchLabel,
0690: firstCatchLabel, "java/lang/SecurityException");
0691: mv
0692: .visitTryCatchBlock(tryLabel, firstCatchLabel,
0693: secondCatchLabel,
0694: "java/lang/NoSuchMethodException");
0695: } else {
0696: // for lifecycle method
0697: mv.visitInsn(ACONST_NULL);
0698: mv.visitInsn(ARETURN);
0699: }
0700:
0701: // finish
0702: mv.visitMaxs(0, 0);
0703: mv.visitEnd();
0704:
0705: }
0706:
0707: /**
0708: * Adds attributes of InvocationContext interface.
0709: *
0710: * <pre>
0711: * private StatelessBean bean;
0712: * private Object[] parameters;
0713: * private static Method method;
0714: * private int interceptor;
0715: * private Map contextData;
0716: *
0717: * // args of the method
0718: * private TYPE_ARG_METHOD arg0 = xxx;
0719: * private TYPE_ARG_METHOD arg1 = xxx;
0720: * private TYPE_ARG_METHOD arg2 = xxx;
0721: * private TYPE_ARG_METHOD.......;
0722: * </pre>
0723: */
0724: private void addInvocationContextAttributes() {
0725:
0726: // Add bean attribute
0727: // private StatelessBean bean;
0728: addAttribute(ACC_PRIVATE, "bean", beanClassDesc);
0729:
0730: // Add parameters attribute
0731: // private Object[] parameters;
0732: addAttribute(ACC_PRIVATE, "parameters", ARRAY_OBJECTS);
0733:
0734: // Add java.lang.reflect.Method attribute
0735: // private static Method method;
0736: addAttribute(ACC_PRIVATE + ACC_STATIC, "method",
0737: JAVA_LANG_REFLECT_METHOD);
0738:
0739: // Add the interceptor counter
0740: // private int interceptor;
0741: addAttribute(ACC_PRIVATE, "interceptor", "I", Integer
0742: .valueOf(0));
0743:
0744: // Now, add argument of the method as attributes
0745: int arg = 0;
0746: for (Type t : methodArgsType) {
0747: addAttribute(ACC_PRIVATE, ARG + (arg++), t.getDescriptor());
0748: }
0749:
0750: // Now, add interceptors objects
0751: int intercpt = 0;
0752: for (JClassInterceptor interceptor : allInterceptors) {
0753: // Only if interceptor is not in the bean class
0754: if (!interceptor.getClassName().equals(beanClassName)) {
0755: addAttribute(ACC_PRIVATE, INTERCEPTOR + (intercpt++),
0756: encodeClassDesc(interceptor.getClassName()));
0757: }
0758: }
0759:
0760: // ContextData
0761: addAttribute(ACC_PRIVATE, "contextData", "Ljava/util/Map;");
0762:
0763: }
0764:
0765: /**
0766: * Adds the initialization of static attributes.
0767: * ie : private static Method method = null
0768: * private static InterceptorClass interceptor0 = new MyInterceptor();
0769: * private static InterceptorClass2 interceptor1 = ....
0770: */
0771: private void addStaticClassInitialization() {
0772: MethodVisitor mv = getCW().visitMethod(ACC_STATIC, "<clinit>",
0773: "()V", null, null);
0774: mv.visitCode();
0775:
0776: // private static Method method = null
0777: mv.visitInsn(ACONST_NULL);
0778: mv.visitFieldInsn(PUTSTATIC, generatedClassName, "method",
0779: JAVA_LANG_REFLECT_METHOD);
0780:
0781: mv.visitInsn(RETURN);
0782: mv.visitMaxs(0, 0);
0783: mv.visitEnd();
0784:
0785: }
0786:
0787: /**
0788: * Adds attributes of EasyBeansInvocationContext interface.
0789: *
0790: * <pre>
0791: * private Factory factory;
0792: * </pre>
0793: */
0794: private void addEasyBeansInvocationContextAttributes() {
0795:
0796: // Add factory attribute
0797: // private Factory factory;
0798: addAttribute(ACC_PRIVATE, "factory", EASYBEANS_FACTORY);
0799:
0800: // Add interceptor manager attribute
0801: // private interceptorManagerClassName interceptorManager;
0802: addAttribute(ACC_PRIVATE, "interceptorManager",
0803: encodeClassDesc(interceptorManagerClassName));
0804:
0805: }
0806:
0807: /**
0808: * Adds the proceed method.<br>
0809: * It adds :
0810: *
0811: * <pre>
0812: * public Object proceed() throws Exception {
0813: * interceptor++;
0814: * switch (interceptor) {
0815: * case 1 :
0816: * return myInterceptor.intercept(this);
0817: * case 2 :
0818: * return otherInterceptor.intercept(this);
0819: * case 3 :
0820: * return bean.originalmethod(...);
0821: * default:
0822: * throw new IllegalStateException("Problem in interceptors");
0823: * }
0824: * }
0825: * </pre>
0826: */
0827: private void addInvocationContextProceed() {
0828: MethodVisitor mv = getCW().visitMethod(ACC_PUBLIC, "proceed",
0829: "()" + JAVA_LANG_OBJECT, null, PROCEED_EXCEPTIONS);
0830: mv.visitCode();
0831:
0832: // interceptor++ or in fact : interceptor = interceptor + 1;
0833: mv.visitVarInsn(ALOAD, 0);
0834: mv.visitInsn(DUP);
0835: mv.visitFieldInsn(GETFIELD, generatedClassName, "interceptor",
0836: "I");
0837: mv.visitInsn(ICONST_1);
0838: mv.visitInsn(IADD); // + 1
0839: mv.visitFieldInsn(PUTFIELD, generatedClassName, "interceptor",
0840: "I");
0841:
0842: // load interceptor constant to do the switch
0843: mv.visitVarInsn(ALOAD, 0);
0844: mv.visitFieldInsn(GETFIELD, generatedClassName, "interceptor",
0845: "I");
0846:
0847: // Size
0848: int sizeInterceptors = allInterceptors.size();
0849:
0850: // need to add call to the original method
0851: int switchSize = sizeInterceptors + 1;
0852:
0853: // Build array of labels corresponding to swtich entries
0854: Label[] switchLabels = new Label[switchSize];
0855: for (int s = 0; s < switchSize; s++) {
0856: switchLabels[s] = new Label();
0857: }
0858:
0859: // default label
0860: Label defaultCaseLabel = new Label();
0861:
0862: // switch
0863: mv.visitTableSwitchInsn(1, switchSize, defaultCaseLabel,
0864: switchLabels);
0865:
0866: // add each interceptor switch entry with a return block at the end
0867: // ie : case 1 :
0868: // return myInterceptor.intercept(this); // interceptor class
0869: // or case 1 :
0870: // return bean.intercept(this) // bean class
0871: int index = 0;
0872: int interceptorIndex = 0;
0873: for (JClassInterceptor interceptor : allInterceptors) {
0874: mv.visitLabel(switchLabels[index]);
0875:
0876: Type returnType = Type.getReturnType(interceptor
0877: .getJMethod().getDescriptor());
0878:
0879: // interceptor on the bean
0880: if (interceptor.getClassName().equals(beanClassName)) {
0881: mv.visitVarInsn(ALOAD, 0);
0882: mv.visitFieldInsn(GETFIELD, generatedClassName, "bean",
0883: beanClassDesc);
0884: mv.visitVarInsn(ALOAD, 0);
0885: mv.visitMethodInsn(INVOKEVIRTUAL, beanClassName,
0886: interceptor.getJMethod().getName(), interceptor
0887: .getJMethod().getDescriptor());
0888:
0889: // return object or null if the return type is void
0890: returnsObject(returnType, mv);
0891: } else { // interceptor in another class
0892: mv.visitVarInsn(ALOAD, 0);
0893: mv.visitFieldInsn(GETFIELD, generatedClassName,
0894: INTERCEPTOR + interceptorIndex,
0895: encodeClassDesc(interceptor.getClassName()));
0896: mv.visitVarInsn(ALOAD, 0);
0897: mv.visitMethodInsn(INVOKEVIRTUAL, interceptor
0898: .getClassName(), interceptor.getJMethod()
0899: .getName(), interceptor.getJMethod()
0900: .getDescriptor());
0901: // return object or null if the return type is void
0902: returnsObject(returnType, mv);
0903: interceptorIndex++;
0904: }
0905: index++;
0906: }
0907:
0908: // then, add call to original method, ie bean.businessMethod(i,j,...);
0909: mv.visitLabel(switchLabels[index++]);
0910: // get bean object
0911: mv.visitVarInsn(ALOAD, 0);
0912: mv.visitFieldInsn(GETFIELD, generatedClassName, "bean",
0913: beanClassDesc);
0914:
0915: // arguments of the method
0916: int indexArg = 0;
0917: for (Type argType : methodArgsType) {
0918: mv.visitVarInsn(ALOAD, 0);
0919: mv.visitFieldInsn(GETFIELD, generatedClassName, ARG
0920: + (indexArg++), argType.getDescriptor());
0921: }
0922:
0923: // Call to the renamed method only for AroundInvoke
0924: // LifeCycle interceptors call the original method
0925: String interceptedMethod = null;
0926: if (interceptorType.equals(AROUND_INVOKE)) {
0927: interceptedMethod = MethodRenamer.encode(jMethod.getName());
0928: } else {
0929: interceptedMethod = jMethod.getName();
0930: }
0931:
0932: mv.visitMethodInsn(INVOKEVIRTUAL, beanClassName,
0933: interceptedMethod, jMethod.getDescriptor());
0934: Type returnType = Type.getReturnType(jMethod.getDescriptor());
0935: // return object or null if the return type is void
0936: returnsObject(returnType, mv);
0937:
0938: // default case
0939: mv.visitLabel(defaultCaseLabel);
0940: mv.visitTypeInsn(NEW, "java/lang/IllegalStateException");
0941: mv.visitInsn(DUP);
0942: mv
0943: .visitLdcInsn("Problem in interceptors. Shouldn't go in the default case.");
0944: mv.visitMethodInsn(INVOKESPECIAL,
0945: "java/lang/IllegalStateException", "<init>",
0946: "(Ljava/lang/String;)V");
0947: mv.visitInsn(ATHROW);
0948:
0949: // end
0950: mv.visitMaxs(0, 0);
0951: mv.visitEnd();
0952: }
0953:
0954: /**
0955: * Adds the getContextData() method.
0956: * <pre>
0957: * public Map getContextData() {
0958: * if (contextData == null) {
0959: * contextData = new HashMap();
0960: * }
0961: * return contextData;
0962: * }
0963: * </pre>
0964: *
0965: */
0966: public void addInvocationContextGetContextData() {
0967: MethodVisitor mv = getCW().visitMethod(ACC_PUBLIC,
0968: "getContextData", "()Ljava/util/Map;", null, null);
0969: mv.visitCode();
0970: mv.visitVarInsn(ALOAD, 0);
0971: mv.visitFieldInsn(GETFIELD, generatedClassName, "contextData",
0972: "Ljava/util/Map;");
0973:
0974: Label elseLabel = new Label();
0975: mv.visitJumpInsn(IFNONNULL, elseLabel);
0976:
0977: // if
0978: mv.visitVarInsn(ALOAD, 0);
0979: mv.visitTypeInsn(NEW, "java/util/HashMap");
0980: mv.visitInsn(DUP);
0981: mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap",
0982: "<init>", "()V");
0983: mv.visitFieldInsn(PUTFIELD, generatedClassName, "contextData",
0984: "Ljava/util/Map;");
0985:
0986: // else
0987: mv.visitLabel(elseLabel);
0988: mv.visitVarInsn(ALOAD, 0);
0989: mv.visitFieldInsn(GETFIELD, generatedClassName, "contextData",
0990: "Ljava/util/Map;");
0991:
0992: // return
0993: mv.visitInsn(ARETURN);
0994:
0995: mv.visitMaxs(0, 0);
0996: mv.visitEnd();
0997:
0998: }
0999:
1000: /**
1001: * Adds the getParameters method of InvocationContext interface.<br>
1002: * It adds :
1003: *
1004: * <pre>
1005: * public Object[] getParameters() {
1006: * if (parameters == null) {
1007: * parameters = new Object[] {arg0, arg1, argxxx};
1008: * }
1009: * return parameters;
1010: * }
1011: * </pre>
1012: */
1013: private void addInvocationContextGetParameters() {
1014: MethodVisitor mv = getCW().visitMethod(ACC_PUBLIC,
1015: "getParameters", "()" + ARRAY_OBJECTS, null, null);
1016: mv.visitCode();
1017:
1018: // only for around invoke type
1019: if (interceptorType == AROUND_INVOKE) {
1020:
1021: // if (parameters == null) {
1022: mv.visitVarInsn(ALOAD, 0);
1023: mv.visitFieldInsn(GETFIELD, generatedClassName,
1024: "parameters", ARRAY_OBJECTS);
1025: // go to this label if not null
1026: Label notNullParametersLabel = new Label();
1027: mv.visitJumpInsn(IFNONNULL, notNullParametersLabel);
1028:
1029: // parameters = new Object[] {arg0, arg1, arg...};
1030: // put size of the array
1031: mv.visitVarInsn(ALOAD, 0);
1032: mv.visitIntInsn(BIPUSH, methodArgsType.length);
1033: mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
1034:
1035: // for each argument of the methods :
1036: int argCount = 0;
1037: for (Type type : methodArgsType) {
1038: mv.visitInsn(DUP);
1039: mv.visitIntInsn(BIPUSH, argCount);
1040: mv.visitVarInsn(ALOAD, 0);
1041: mv.visitFieldInsn(GETFIELD, generatedClassName, ARG
1042: + argCount, type.getDescriptor());
1043: // if type is not object type, need to convert it
1044: // for example : Integer.valueOf(i);
1045: transformPrimitiveIntoObject(type, mv);
1046: mv.visitInsn(AASTORE);
1047: argCount++;
1048: }
1049:
1050: // store field
1051: mv.visitFieldInsn(PUTFIELD, generatedClassName,
1052: "parameters", ARRAY_OBJECTS);
1053:
1054: // not null label :
1055: // return parameters;
1056: mv.visitLabel(notNullParametersLabel);
1057: mv.visitVarInsn(ALOAD, 0);
1058: mv.visitFieldInsn(GETFIELD, generatedClassName,
1059: "parameters", ARRAY_OBJECTS);
1060: } else {
1061: // throw Exception
1062: mv.visitTypeInsn(NEW, "java/lang/IllegalStateException");
1063: mv.visitInsn(DUP);
1064: mv
1065: .visitLdcInsn("Operation getParameters can only be applied on AroundInvoke interceptors");
1066: mv.visitMethodInsn(INVOKESPECIAL,
1067: "java/lang/IllegalStateException", "<init>",
1068: "(Ljava/lang/String;)V");
1069: mv.visitInsn(ATHROW);
1070: }
1071:
1072: // return
1073: mv.visitInsn(ARETURN);
1074: mv.visitMaxs(0, 0);
1075: mv.visitEnd();
1076:
1077: }
1078:
1079: /**
1080: * Adds the setParameters method of InvocationContext interface.<br>
1081: * It adds :
1082: *
1083: * <pre>
1084: * public void setParameters(Object aobj[]) {
1085: * if (aobj == null) {
1086: * throw new IllegalStateException("Cannot set a null array.");
1087: * }
1088: * if (aobj.length != ...) {
1089: * throw new IllegalStateException("Invalid size of the given array. The length should be '" + ... + "'.");
1090: * }
1091: * parameters = aobj;
1092: *
1093: * arg0 = (Integer) aobj[0];
1094: * arg1 = ((Integer) aobj[1]).intValue();
1095: * arg2 = ((Double) aobj[2]).doubleValue();
1096: * arg3 = ((Float) aobj[3]).floatValue();
1097: * arg4 = (String) aobj[4];
1098: * ...
1099: * }
1100: *
1101: * </pre>
1102: */
1103: private void addInvocationContextSetParameters() {
1104: MethodVisitor mv = getCW()
1105: .visitMethod(ACC_PUBLIC, "setParameters",
1106: "(" + ARRAY_OBJECTS + ")V", null, null);
1107: mv.visitCode();
1108:
1109: // only for aroundInvoke
1110: if (interceptorType == AROUND_INVOKE) {
1111: /**
1112: * if (aobj == null) { throw new IllegalStateException("Cannot set a
1113: * null array."); }
1114: */
1115: mv.visitVarInsn(ALOAD, 1);
1116: Label notNull = new Label();
1117: mv.visitJumpInsn(IFNONNULL, notNull);
1118: mv.visitTypeInsn(NEW, "java/lang/IllegalStateException");
1119: mv.visitInsn(DUP);
1120: mv.visitLdcInsn("Cannot set a null array.");
1121: mv.visitMethodInsn(INVOKESPECIAL,
1122: "java/lang/IllegalStateException", "<init>",
1123: "(Ljava/lang/String;)V");
1124: mv.visitInsn(ATHROW);
1125: mv.visitLabel(notNull);
1126:
1127: /**
1128: * if (aobj.length != ...) { throw new
1129: * IllegalStateException("Invalid size of the given array. The
1130: * length should be '" + ... + "'."); }
1131: */
1132: mv.visitVarInsn(ALOAD, 1);
1133: mv.visitInsn(ARRAYLENGTH);
1134: mv.visitIntInsn(BIPUSH, methodArgsType.length);
1135: Label sizeOk = new Label();
1136: mv.visitJumpInsn(IF_ICMPEQ, sizeOk);
1137: mv.visitTypeInsn(NEW, "java/lang/IllegalStateException");
1138: mv.visitInsn(DUP);
1139: mv
1140: .visitLdcInsn("Invalid size of the given array. The length should be '"
1141: + methodArgsType.length + "'.");
1142: mv.visitMethodInsn(INVOKESPECIAL,
1143: "java/lang/IllegalStateException", "<init>",
1144: "(Ljava/lang/String;)V");
1145: mv.visitInsn(ATHROW);
1146: mv.visitLabel(sizeOk);
1147:
1148: // this.parameters = parameters
1149: mv.visitVarInsn(ALOAD, 0);
1150: mv.visitVarInsn(ALOAD, 1);
1151: mv.visitFieldInsn(PUTFIELD, generatedClassName,
1152: "parameters", ARRAY_OBJECTS);
1153:
1154: /**
1155: * arg0 = (Integer) aobj[0]; arg1 = ((Integer) aobj[1]).intValue();
1156: * arg2 = ((Double) aobj[2]).doubleValue(); arg3 = ((Float)
1157: * aobj[3]).floatValue(); arg4 = (String) aobj[4]; ...
1158: */
1159: int argCount = 0;
1160: for (Type type : methodArgsType) {
1161: mv.visitVarInsn(ALOAD, 0);
1162: mv.visitVarInsn(ALOAD, 1);
1163: mv.visitIntInsn(BIPUSH, argCount);
1164: mv.visitInsn(AALOAD);
1165: // Cast object Integer.valueOf(i);
1166: transformObjectIntoPrimitive(type, mv);
1167: // write result
1168: mv.visitFieldInsn(PUTFIELD, generatedClassName, ARG
1169: + argCount, type.getDescriptor());
1170: argCount++;
1171: }
1172: } else {
1173: // throw Exception
1174: mv.visitTypeInsn(NEW, "java/lang/IllegalStateException");
1175: mv.visitInsn(DUP);
1176: mv
1177: .visitLdcInsn("Operation setParameters can only be applied on AroundInvoke interceptors");
1178: mv.visitMethodInsn(INVOKESPECIAL,
1179: "java/lang/IllegalStateException", "<init>",
1180: "(Ljava/lang/String;)V");
1181: mv.visitInsn(ATHROW);
1182: }
1183:
1184: mv.visitInsn(RETURN);
1185: mv.visitMaxs(0, 0);
1186: mv.visitEnd();
1187: }
1188:
1189: /**
1190: * Generated toString() method.
1191: * Generated code is in the comments of the method body.
1192: */
1193: private void addToString() {
1194: MethodVisitor mv = getCW().visitMethod(ACC_PUBLIC, "toString",
1195: "()Ljava/lang/String;", null, null);
1196: mv.visitCode();
1197:
1198: // local vars
1199: // 1 = sb
1200: // 2 = classNames
1201: // 3 = className
1202: // 4 = indent2
1203: // 5 = indent4
1204: // 6 = i
1205: //
1206: int localVar = 1;
1207: final int varSB = localVar++;
1208: int varCLASSNAMES = localVar++;
1209: int varCLASSNAME = localVar++;
1210: int varINDENT2 = localVar++;
1211: int varINDENT4 = localVar++;
1212: int varI = localVar++;
1213:
1214: /*
1215: * StringBuilder sb = new StringBuilder();
1216: * String[] classNames = this.getClass().getName().split("\\.");
1217: * String className = classNames[classNames.length - 1];
1218: * // classname
1219: * sb.append(className);
1220: * sb.append("[\n");
1221: * String indent2 = " ";
1222: * String indent4 = " ";
1223: * sb.append(indent2);
1224: * sb.append("List of interceptors :\n");
1225: */
1226:
1227: mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
1228: mv.visitInsn(DUP);
1229: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder",
1230: "<init>", "()V");
1231: mv.visitVarInsn(ASTORE, varSB);
1232: mv.visitVarInsn(ALOAD, 0);
1233: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object",
1234: "getClass", "()Ljava/lang/Class;");
1235: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName",
1236: "()Ljava/lang/String;");
1237: mv.visitLdcInsn("\\.");
1238: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "split",
1239: "(Ljava/lang/String;)[Ljava/lang/String;");
1240: mv.visitVarInsn(ASTORE, varCLASSNAMES);
1241: mv.visitVarInsn(ALOAD, varCLASSNAMES);
1242: mv.visitVarInsn(ALOAD, varCLASSNAMES);
1243: mv.visitInsn(ARRAYLENGTH);
1244: mv.visitInsn(ICONST_1);
1245: mv.visitInsn(ISUB);
1246: mv.visitInsn(AALOAD);
1247: mv.visitVarInsn(ASTORE, varCLASSNAME);
1248: mv.visitVarInsn(ALOAD, varSB);
1249: mv.visitVarInsn(ALOAD, varCLASSNAME);
1250: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
1251: "append",
1252: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1253: mv.visitInsn(POP);
1254: mv.visitVarInsn(ALOAD, varSB);
1255: mv.visitLdcInsn("[\n");
1256: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
1257: "append",
1258: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1259: mv.visitInsn(POP);
1260: mv.visitLdcInsn(" ");
1261: mv.visitVarInsn(ASTORE, varINDENT2);
1262: mv.visitLdcInsn(" ");
1263: mv.visitVarInsn(ASTORE, varINDENT4);
1264: mv.visitVarInsn(ALOAD, varSB);
1265: mv.visitVarInsn(ALOAD, varINDENT2);
1266: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
1267: "append",
1268: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1269: mv.visitInsn(POP);
1270: mv.visitVarInsn(ALOAD, varSB);
1271: mv.visitLdcInsn("List of interceptors :\n");
1272: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
1273: "append",
1274: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1275: mv.visitInsn(POP);
1276:
1277: /*
1278: * In the loop, print :
1279: * sb.append(indent4);
1280: * sb.append(i);
1281: * sb.append(") - ");
1282: * sb.append(interceptor.getClassName());
1283: * sb.append("[");
1284: * sb.append(interceptor.getJMethod().getName());
1285: * sb.append("]\n");
1286: */
1287: int i = 1;
1288:
1289: // int i = 1;
1290: mv.visitInsn(ICONST_1);
1291: mv.visitVarInsn(ISTORE, varI);
1292:
1293: if (allInterceptors != null) {
1294: for (JClassInterceptor interceptor : allInterceptors) {
1295: mv.visitVarInsn(ALOAD, varSB);
1296: mv.visitVarInsn(ALOAD, varINDENT4);
1297: mv
1298: .visitMethodInsn(INVOKEVIRTUAL,
1299: "java/lang/StringBuilder", "append",
1300: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1301: mv.visitInsn(POP);
1302:
1303: mv.visitVarInsn(ALOAD, varSB);
1304: mv.visitVarInsn(ILOAD, varI);
1305: mv.visitMethodInsn(INVOKEVIRTUAL,
1306: "java/lang/StringBuilder", "append",
1307: "(I)Ljava/lang/StringBuilder;");
1308: mv.visitInsn(POP);
1309:
1310: mv.visitVarInsn(ALOAD, varSB);
1311: mv.visitLdcInsn(") - ");
1312: mv
1313: .visitMethodInsn(INVOKEVIRTUAL,
1314: "java/lang/StringBuilder", "append",
1315: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1316: mv.visitInsn(POP);
1317:
1318: // sb.append(interceptor.getClassName());
1319: mv.visitVarInsn(ALOAD, varSB);
1320: mv.visitLdcInsn(interceptor.getClassName());
1321: mv
1322: .visitMethodInsn(INVOKEVIRTUAL,
1323: "java/lang/StringBuilder", "append",
1324: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1325: mv.visitInsn(POP);
1326:
1327: mv.visitVarInsn(ALOAD, varSB);
1328: mv.visitLdcInsn("[");
1329: mv
1330: .visitMethodInsn(INVOKEVIRTUAL,
1331: "java/lang/StringBuilder", "append",
1332: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1333: mv.visitInsn(POP);
1334:
1335: // sb.append(interceptor.getJMethod().getName());
1336: mv.visitVarInsn(ALOAD, varSB);
1337: mv.visitLdcInsn(interceptor.getJMethod().getName());
1338: mv
1339: .visitMethodInsn(INVOKEVIRTUAL,
1340: "java/lang/StringBuilder", "append",
1341: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1342: mv.visitInsn(POP);
1343:
1344: mv.visitVarInsn(ALOAD, varSB);
1345: mv.visitLdcInsn("]\n");
1346: mv
1347: .visitMethodInsn(INVOKEVIRTUAL,
1348: "java/lang/StringBuilder", "append",
1349: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1350: mv.visitInsn(POP);
1351:
1352: i++;
1353: // i++
1354: mv.visitIincInsn(varI, 1);
1355: }
1356: /*
1357: * sb.append(indent2);
1358: * sb.append("Current interceptor : ");
1359: * sb.append(interceptor); sb.append("/");
1360: * sb.append(allInterceptors.size());
1361: */
1362: mv.visitVarInsn(ALOAD, varSB);
1363: mv.visitVarInsn(ALOAD, varINDENT2);
1364: mv.visitMethodInsn(INVOKEVIRTUAL,
1365: "java/lang/StringBuilder", "append",
1366: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1367: mv.visitInsn(POP);
1368:
1369: mv.visitVarInsn(ALOAD, varSB);
1370: mv.visitLdcInsn("Current interceptor : ");
1371: mv.visitMethodInsn(INVOKEVIRTUAL,
1372: "java/lang/StringBuilder", "append",
1373: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1374: mv.visitInsn(POP);
1375:
1376: mv.visitVarInsn(ALOAD, varSB);
1377: mv.visitVarInsn(ALOAD, 0);
1378: mv.visitFieldInsn(GETFIELD, generatedClassName,
1379: "interceptor", "I");
1380: mv.visitMethodInsn(INVOKEVIRTUAL,
1381: "java/lang/StringBuilder", "append",
1382: "(I)Ljava/lang/StringBuilder;");
1383: mv.visitInsn(POP);
1384:
1385: mv.visitVarInsn(ALOAD, varSB);
1386: mv.visitLdcInsn("/");
1387: mv.visitMethodInsn(INVOKEVIRTUAL,
1388: "java/lang/StringBuilder", "append",
1389: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1390: mv.visitInsn(POP);
1391:
1392: mv.visitVarInsn(ALOAD, varSB);
1393: mv.visitLdcInsn(String.valueOf(allInterceptors.size()));
1394: mv.visitMethodInsn(INVOKEVIRTUAL,
1395: "java/lang/StringBuilder", "append",
1396: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1397: mv.visitInsn(POP);
1398:
1399: } else {
1400: /*
1401: * sb.append(indent2);
1402: * sb.append("No interceptors : ");
1403: */
1404: mv.visitVarInsn(ALOAD, varSB);
1405: mv.visitVarInsn(ALOAD, varINDENT2);
1406: mv.visitMethodInsn(INVOKEVIRTUAL,
1407: "java/lang/StringBuilder", "append",
1408: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1409: mv.visitInsn(POP);
1410:
1411: mv.visitVarInsn(ALOAD, varSB);
1412: mv.visitLdcInsn("No interceptors : ");
1413: mv.visitMethodInsn(INVOKEVIRTUAL,
1414: "java/lang/StringBuilder", "append",
1415: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1416: mv.visitInsn(POP);
1417: }
1418:
1419: /*
1420: * sb.append("\n");
1421: * sb.append("]");
1422: * return sb.toString();
1423: */
1424: mv.visitVarInsn(ALOAD, varSB);
1425: mv.visitLdcInsn("\n");
1426: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
1427: "append",
1428: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1429: mv.visitInsn(POP);
1430:
1431: mv.visitVarInsn(ALOAD, varSB);
1432: mv.visitLdcInsn("]");
1433: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
1434: "append",
1435: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
1436: mv.visitInsn(POP);
1437:
1438: mv.visitVarInsn(ALOAD, varSB);
1439: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
1440: "toString", "()Ljava/lang/String;");
1441: mv.visitInsn(ARETURN);
1442:
1443: mv.visitMaxs(0, 0);
1444: mv.visitEnd();
1445:
1446: }
1447:
1448: /**
1449: * @return method metadata used by this generator
1450: */
1451: public MethodAnnotationMetadata getMethodAnnotationMetadata() {
1452: return methodAnnotationMetadata;
1453: }
1454:
1455: /**
1456: * @return the name of the generated class name (with package name)
1457: */
1458: public String getGeneratedClassName() {
1459: return generatedClassName;
1460: }
1461:
1462: /**
1463: * @return the ASM descriptor of the generated constructor.
1464: */
1465: public String getConstructorDesc() {
1466: return constructorDesc;
1467: }
1468:
1469: /**
1470: * @return the interceptors used by this InvocationContext implementation object.
1471: */
1472: public List<JClassInterceptor> getAllInterceptors() {
1473: return allInterceptors;
1474: }
1475:
1476: }
|