1 25 26 package org.objectweb.easybeans.enhancer.interceptors; 27 28 import static org.objectweb.easybeans.deployment.annotations.InterceptorType.AROUND_INVOKE; 29 import static org.objectweb.easybeans.deployment.annotations.InterceptorType.DEP_INJECT; 30 import static org.objectweb.easybeans.deployment.annotations.InterceptorType.POST_ACTIVATE; 31 import static org.objectweb.easybeans.deployment.annotations.InterceptorType.POST_CONSTRUCT; 32 import static org.objectweb.easybeans.deployment.annotations.InterceptorType.PRE_DESTROY; 33 import static org.objectweb.easybeans.deployment.annotations.InterceptorType.PRE_PASSIVATE; 34 35 import java.util.ArrayList ; 36 import java.util.Arrays ; 37 import java.util.List ; 38 39 import org.objectweb.asm.ClassAdapter; 40 import org.objectweb.asm.ClassVisitor; 41 import org.objectweb.asm.Label; 42 import org.objectweb.asm.MethodAdapter; 43 import org.objectweb.asm.MethodVisitor; 44 import org.objectweb.asm.Opcodes; 45 import org.objectweb.asm.Type; 46 import org.objectweb.easybeans.api.bean.lifecycle.EasyBeansMDBLifeCycle; 47 import org.objectweb.easybeans.api.bean.lifecycle.EasyBeansSFSBLifeCycle; 48 import org.objectweb.easybeans.api.bean.lifecycle.EasyBeansSLSBLifeCycle; 49 import org.objectweb.easybeans.deployment.annotations.InterceptorType; 50 import org.objectweb.easybeans.deployment.annotations.JClassInterceptor; 51 import org.objectweb.easybeans.deployment.annotations.JMethod; 52 import org.objectweb.easybeans.deployment.annotations.metadata.ClassAnnotationMetadata; 53 import org.objectweb.easybeans.deployment.annotations.metadata.MethodAnnotationMetadata; 54 import org.objectweb.easybeans.enhancer.CommonClassGenerator; 55 import org.objectweb.easybeans.enhancer.DefinedClass; 56 import org.objectweb.easybeans.enhancer.injection.InjectionClassAdapter; 57 import org.objectweb.easybeans.enhancer.lib.MethodRenamer; 58 59 65 public class InterceptorClassAdapter extends ClassAdapter implements Opcodes { 66 67 70 private ClassAnnotationMetadata classAnnotationMetadata; 71 72 75 private List <JMethod> renamedMethods = null; 76 77 80 private List <DefinedClass> definedClasses = null; 81 82 85 private List <InterceptorType> generatedTypes = null; 86 87 90 private List <String > beanInterceptors = null; 91 92 95 private boolean addInterface = true; 96 97 103 public InterceptorClassAdapter(final ClassAnnotationMetadata classAnnotationMetadata, final ClassVisitor cv) { 104 this(classAnnotationMetadata, cv, false); 105 this.beanInterceptors = new ArrayList <String >(); 106 } 107 108 115 public InterceptorClassAdapter(final ClassAnnotationMetadata classAnnotationMetadata, 116 final ClassVisitor cv, final boolean addInterface) { 117 super(cv); 118 this.classAnnotationMetadata = classAnnotationMetadata; 119 this.renamedMethods = new ArrayList <JMethod>(); 120 this.definedClasses = new ArrayList <DefinedClass>(); 121 this.addInterface = addInterface; 122 this.generatedTypes = new ArrayList <InterceptorType>(); 123 } 124 125 126 145 @Override 146 public void visit(final int version, final int access, final String name, final String signature, final String superName, 147 final String [] interfaces) { 148 149 String [] newInterfaces = null; 150 151 if (classAnnotationMetadata.isBean() && addInterface) { 153 newInterfaces = new String [interfaces.length + 1]; 155 System.arraycopy(interfaces, 0, newInterfaces, 0, interfaces.length); 156 157 int indexElement = newInterfaces.length - 1; 158 159 if (classAnnotationMetadata.isStateless()) { 161 newInterfaces[indexElement] = Type.getInternalName(EasyBeansSLSBLifeCycle.class); 162 } else if (classAnnotationMetadata.isStateful()) { 163 newInterfaces[indexElement] = Type.getInternalName(EasyBeansSFSBLifeCycle.class); 164 } else if (classAnnotationMetadata.isMdb()) { 165 newInterfaces[indexElement] = Type.getInternalName(EasyBeansMDBLifeCycle.class); 166 } else { 167 throw new IllegalStateException ("Bean '" + classAnnotationMetadata.getClassName() + "' not SLSB, SFSB or MDB"); 168 } 169 } else { 170 newInterfaces = interfaces; 171 } 172 173 super.visit(version, access, name, signature, superName, newInterfaces); 174 175 } 176 177 192 @Override 193 public void visitInnerClass(final String name, final String outerName, final String innerName, final int access) { 194 super.visitInnerClass(name, outerName, innerName, access); 195 } 196 197 215 @Override 216 public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, 217 final String [] exceptions) { 218 JMethod jMethod = new JMethod(access, name, desc, signature, exceptions); 219 String newName = name; 220 int newAccess = access; 221 222 if (isInterceptedMethod(jMethod)) { 224 renamedMethods.add(jMethod); 226 227 newName = MethodRenamer.encode(name); 229 } 230 231 if (!isDependencyInjectionMethod(jMethod) && !isInjectedMethod(jMethod)&& isInterceptorMethod(jMethod)) { 233 newAccess = Opcodes.ACC_PUBLIC; 235 } 236 return new MethodAdapter(super.visitMethod(newAccess, newName, desc, signature, exceptions)); 237 } 238 239 244 @Override 245 public void visitEnd() { 246 super.visitEnd(); 247 248 if (classAnnotationMetadata.isBean()) { 250 MethodAnnotationMetadata posConsMetaData = generateBeanLifeCycleMethod(classAnnotationMetadata, POST_CONSTRUCT); 253 MethodAnnotationMetadata preDesMetaData = generateBeanLifeCycleMethod(classAnnotationMetadata, PRE_DESTROY); 254 MethodAnnotationMetadata postActMetaData = generateBeanLifeCycleMethod(classAnnotationMetadata, POST_ACTIVATE); 255 MethodAnnotationMetadata prePassMetaData = generateBeanLifeCycleMethod(classAnnotationMetadata, PRE_PASSIVATE); 256 257 generateClass( 259 new MethodAnnotationMetadata(InjectionClassAdapter.INJECTED_JMETHOD, classAnnotationMetadata), 260 DEP_INJECT); 261 262 263 264 for (MethodAnnotationMetadata method : classAnnotationMetadata.getMethodAnnotationMetadataCollection()) { 266 267 if (method.isBusinessMethod()) { 269 generateClass(method, AROUND_INVOKE); 270 271 if (!renamedMethods.contains(method.getJMethod())) { 273 generateCallSuperEncodedMethod(method); 274 } 275 } 276 } 277 278 279 generateClass(posConsMetaData, POST_CONSTRUCT); 284 generateClass(preDesMetaData, PRE_DESTROY); 285 generateClass(prePassMetaData, PRE_PASSIVATE); 286 generateClass(postActMetaData, POST_ACTIVATE); 287 288 String generatedClName = classAnnotationMetadata.getClassName() 290 + EasyBeansInvocationContextGenerator.SUFFIX_INTERCEPTOR_MANAGER; 291 InterceptorManagerGenerator interceptorManagerGenerator = new InterceptorManagerGenerator( 292 classAnnotationMetadata.getEjbJarAnnotationMetadata(), generatedClName, beanInterceptors); 293 interceptorManagerGenerator.generate(); 294 DefinedClass dc = new DefinedClass(generatedClName.replace("/", "."), interceptorManagerGenerator.getBytes()); 295 definedClasses.add(dc); 297 298 } 299 } 300 301 325 private void generateCallToInvocationContext(final MethodAnnotationMetadata method, 326 final EasyBeansInvocationContextGenerator genInvCtx, final InterceptorType interceptorType) { 327 328 333 String generatedMethodName = null; 334 switch (interceptorType) { 335 case AROUND_INVOKE: 336 generatedMethodName = method.getMethodName(); 337 break; 338 case DEP_INJECT: 339 generatedMethodName = MethodRenamer.decode(method.getMethodName()); 340 break; 341 case POST_CONSTRUCT: 342 generatedMethodName = "postConstructEasyBeansLifeCycle"; 343 break; 344 case PRE_DESTROY: 345 generatedMethodName = "preDestroyEasyBeansLifeCycle"; 346 break; 347 case PRE_PASSIVATE: 348 generatedMethodName = "prePassivateEasyBeansLifeCycle"; 349 break; 350 case POST_ACTIVATE: 351 generatedMethodName = "postActivateEasyBeansLifeCycle"; 352 break; 353 default: 354 throw new RuntimeException ("No generated method name found for method '" + method.getMethodName() + "'"); 355 } 356 357 if (generatedMethodName == null) { 358 throw new RuntimeException ("No generated method name found for method '" + method.getMethodName() + "'"); 359 } 360 361 MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, generatedMethodName, method.getJMethod().getDescriptor(), 363 null, method.getJMethod().getExceptions()); 364 mv.visitCode(); 365 366 Label tryLabel = new Label(); 368 mv.visitLabel(tryLabel); 369 370 mv.visitTypeInsn(NEW, genInvCtx.getGeneratedClassName()); 372 mv.visitInsn(DUP); 373 374 mv.visitVarInsn(ALOAD, 0); 376 377 Type[] args = Type.getArgumentTypes(method.getJMethod().getDescriptor()); 379 int methodArg = 1; 380 for (Type type : args) { 381 int opCode = CommonClassGenerator.putFieldLoadOpCode(type.getSort()); 382 mv.visitVarInsn(opCode, methodArg); 383 if (opCode == LLOAD || opCode == DLOAD) { 385 methodArg++; 386 } 387 methodArg++; 388 } 389 Type returnType = Type.getReturnType(method.getJMethod().getDescriptor()); 390 391 String constructorDesc = genInvCtx.getConstructorDesc(); 392 mv.visitMethodInsn(INVOKESPECIAL, genInvCtx.getGeneratedClassName(), "<init>", constructorDesc); 393 mv.visitMethodInsn(INVOKEVIRTUAL, genInvCtx.getGeneratedClassName(), "proceed", "()Ljava/lang/Object;"); 394 395 CommonClassGenerator.transformObjectIntoPrimitive(returnType, mv); 396 CommonClassGenerator.addReturnType(returnType, mv); 397 398 boolean methodAlreadyThrowJavaLangException = false; 399 400 String [] methodExceptions = method.getJMethod().getExceptions(); 402 Label[] catchsLabel = null; 404 if (methodExceptions != null) { 405 if (Arrays.asList(methodExceptions).contains("java/lang/Exception")) { 409 methodAlreadyThrowJavaLangException = true; 410 catchsLabel = new Label[methodExceptions.length]; 411 } else { 412 catchsLabel = new Label[methodExceptions.length + 1]; 414 } 415 } else { 416 catchsLabel = new Label[1]; 417 } 418 419 for (int i = 0; i < catchsLabel.length; i++) { 421 catchsLabel[i] = new Label(); 422 } 423 424 int lastCatchBlockLabel = 0; 426 if (methodAlreadyThrowJavaLangException) { 427 lastCatchBlockLabel = catchsLabel.length; 428 } else { 429 lastCatchBlockLabel = catchsLabel.length - 1; 430 } 431 432 for (int block = 0; block < lastCatchBlockLabel; block++) { 433 mv.visitLabel(catchsLabel[block]); 434 mv.visitVarInsn(ASTORE, methodArg); 435 mv.visitVarInsn(ALOAD, methodArg); 436 mv.visitInsn(ATHROW); 437 } 438 if (!methodAlreadyThrowJavaLangException) { 440 mv.visitLabel(catchsLabel[lastCatchBlockLabel]); 442 mv.visitVarInsn(ASTORE, methodArg); 443 444 mv.visitVarInsn(ALOAD, methodArg); 446 mv.visitTypeInsn(INSTANCEOF, "java/lang/RuntimeException"); 447 Label notInstanceOfRuntimeExceptionLabel = new Label(); 448 mv.visitJumpInsn(IFEQ, notInstanceOfRuntimeExceptionLabel); 449 450 mv.visitVarInsn(ALOAD, methodArg); 452 mv.visitTypeInsn(CHECKCAST, "java/lang/RuntimeException"); 453 mv.visitInsn(ATHROW); 454 455 mv.visitLabel(notInstanceOfRuntimeExceptionLabel); 457 mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); 458 mv.visitInsn(DUP); 459 mv.visitVarInsn(ALOAD, methodArg); 460 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/Throwable;)V"); 461 mv.visitInsn(ATHROW); 462 463 } 464 465 int block = 0; 467 if (methodExceptions != null) { 469 for (String exception : methodExceptions) { 470 mv.visitTryCatchBlock(tryLabel, catchsLabel[0], catchsLabel[block], exception); 471 block++; 472 } 473 } 474 if (!methodAlreadyThrowJavaLangException) { 476 mv.visitTryCatchBlock(tryLabel, catchsLabel[0], catchsLabel[lastCatchBlockLabel], "java/lang/Exception"); 477 } 478 479 mv.visitMaxs(0, 0); 480 mv.visitEnd(); 481 482 } 483 484 489 private void generateClass(final MethodAnnotationMetadata method, final InterceptorType interceptorType) { 490 EasyBeansInvocationContextGenerator genInvCtx = new EasyBeansInvocationContextGenerator(method, interceptorType); 491 genInvCtx.generate(); 492 493 for (JClassInterceptor interceptor : genInvCtx.getAllInterceptors()) { 495 String interceptorClassName = interceptor.getClassName(); 496 if (!interceptorClassName.equals(classAnnotationMetadata.getClassName())) { 497 if (!beanInterceptors.contains(interceptorClassName)) { 498 beanInterceptors.add(interceptorClassName); 499 } 500 } 501 } 502 DefinedClass dc = new DefinedClass(genInvCtx.getGeneratedClassName().replace("/", "."), genInvCtx.getBytes()); 503 definedClasses.add(dc); 505 generatedTypes.add(interceptorType); 506 generateCallToInvocationContext(method, genInvCtx, interceptorType); 508 509 } 510 511 518 private void generateCallSuperEncodedMethod(final MethodAnnotationMetadata method) { 519 520 String generatedMethodName = MethodRenamer.encode(method.getMethodName()); 521 JMethod jMethod = method.getJMethod(); 522 MethodVisitor mv = cv.visitMethod(jMethod.getAccess(), generatedMethodName, 523 jMethod.getDescriptor(), jMethod.getSignature(), jMethod.getExceptions()); 524 mv.visitCode(); 525 526 mv.visitVarInsn(ALOAD, 0); 528 529 Type[] args = Type.getArgumentTypes(jMethod.getDescriptor()); 531 int methodArg = 1; 532 for (Type type : args) { 533 int opCode = CommonClassGenerator.putFieldLoadOpCode(type.getSort()); 534 mv.visitVarInsn(opCode, methodArg); 535 if (opCode == LLOAD || opCode == DLOAD) { 537 methodArg++; 538 } 539 methodArg++; 540 } 541 542 mv.visitMethodInsn(INVOKESPECIAL, method.getClassAnnotationMetadata().getSuperName(), 544 jMethod.getName(), jMethod.getDescriptor()); 545 546 Type returnType = Type.getReturnType(jMethod.getDescriptor()); 547 CommonClassGenerator.addReturnType(returnType, mv); 548 549 550 mv.visitMaxs(0, 0); 551 mv.visitEnd(); 552 } 553 554 555 556 557 558 565 private MethodAnnotationMetadata generateBeanLifeCycleMethod(final ClassAnnotationMetadata classMetaData, 566 final InterceptorType interceptorType) { 567 String generatedMethodName = null; 568 List <MethodAnnotationMetadata> existingLifecycleMethods = null; 569 switch (interceptorType) { 570 case AROUND_INVOKE: 571 case DEP_INJECT: 572 return null; 574 case POST_CONSTRUCT: 575 generatedMethodName = "beanPostConstruct$generated"; 576 existingLifecycleMethods = classMetaData.getPostConstructMethodsMetadata(); 577 break; 578 case PRE_DESTROY: 579 generatedMethodName = "beanPreDestroy$generated"; 580 existingLifecycleMethods = classMetaData.getPreDestroyMethodsMetadata(); 581 break; 582 case PRE_PASSIVATE: 583 generatedMethodName = "beanPrePassivate$generated"; 584 existingLifecycleMethods = classMetaData.getPrePassivateMethodsMetadata(); 585 break; 586 case POST_ACTIVATE: 587 generatedMethodName = "beanPostActivate$generated"; 588 existingLifecycleMethods = classMetaData.getPostActivateMethodsMetadata(); 589 break; 590 default: 591 throw new RuntimeException ("No generated method name found for interceptorType '" + interceptorType + "'"); 592 } 593 594 595 MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, generatedMethodName, "()V", null, null); 597 mv.visitCode(); 598 if (existingLifecycleMethods != null) { 600 for (MethodAnnotationMetadata method : existingLifecycleMethods) { 601 String clName = method.getClassAnnotationMetadata().getClassName(); 603 mv.visitVarInsn(ALOAD, 0); 604 int opcode = INVOKEVIRTUAL; 605 if (method.isInherited()) { 606 clName = method.getOriginalClassAnnotationMetadata().getClassName(); 607 opcode = INVOKESPECIAL; 608 } 609 mv.visitMethodInsn(opcode, clName, method.getMethodName(), method.getJMethod().getDescriptor()); 610 } 611 } 612 613 614 mv.visitInsn(RETURN); 615 mv.visitMaxs(0, 0); 616 mv.visitEnd(); 617 618 JMethod method = new JMethod(ACC_PUBLIC, generatedMethodName, "()V", null, null); 620 MethodAnnotationMetadata generatedMetadata = new MethodAnnotationMetadata(method, classMetaData); 621 622 switch (interceptorType) { 624 case POST_CONSTRUCT: 625 generatedMetadata.setPostConstruct(true); 626 break; 627 case PRE_DESTROY: 628 generatedMetadata.setPreDestroy(true); 629 break; 630 case PRE_PASSIVATE: 631 generatedMetadata.setPrePassivate(true); 632 break; 633 case POST_ACTIVATE: 634 generatedMetadata.setPostActivate(true); 635 break; 636 default: 637 throw new RuntimeException ("No generated method name found for interceptorType '" + interceptorType + "'"); 638 } 639 640 classMetaData.addMethodAnnotationMetadata(generatedMetadata); 641 return generatedMetadata; 642 } 643 644 650 private boolean isDependencyInjectionMethod(final JMethod jMethod) { 651 return InjectionClassAdapter.INJECTED_METHOD.equals(jMethod.getName()); 652 } 653 654 659 private boolean isInjectedMethod(final JMethod jMethod) { 660 for (String method : InjectionClassAdapter.INJECTED_METHODS) { 661 if (method.equals(jMethod.getName())) { 662 return true; 663 } 664 } 665 return false; 666 } 667 668 673 private boolean isInterceptedMethod(final JMethod jMethod) { 674 if (isDependencyInjectionMethod(jMethod)) { 676 return classAnnotationMetadata.isBean(); 677 } 678 679 if (isInjectedMethod(jMethod)) { 681 return false; 682 } 683 684 MethodAnnotationMetadata method = classAnnotationMetadata.getMethodAnnotationMetadata(jMethod); 686 if (method == null) { 687 throw new IllegalStateException ("Cannot find a method " + jMethod + " in class " 688 + classAnnotationMetadata.getClassName()); 689 } 690 return method.isBusinessMethod(); 691 } 692 693 697 private boolean isInterceptorMethod(final JMethod jMethod) { 698 MethodAnnotationMetadata method = classAnnotationMetadata.getMethodAnnotationMetadata(jMethod); 700 if (method == null) { 701 throw new IllegalStateException ("Cannot find a method " + jMethod + " in class " 702 + classAnnotationMetadata.getClassName()); 703 } 704 return (method.isAroundInvoke() || method.isLifeCycleMethod()); 705 } 706 707 708 712 public List <DefinedClass> getDefinedClasses() { 713 return definedClasses; 714 } 715 } 716 | Popular Tags |