001package io.ebean.enhance.common; 002 003import io.ebean.enhance.asm.AnnotationVisitor; 004import io.ebean.enhance.asm.ClassVisitor; 005import io.ebean.enhance.asm.MethodVisitor; 006import io.ebean.enhance.asm.Opcodes; 007 008import static io.ebean.enhance.Transformer.EBEAN_ASM_VERSION; 009import static io.ebean.enhance.common.EnhanceConstants.TRANSACTIONAL_ANNOTATION; 010 011/** 012 * ClassAdapter used to detect if this class needs enhancement for entity or 013 * transactional support. 014 */ 015public class DetectEnhancement extends ClassVisitor { 016 017 private final ClassLoader classLoader; 018 private final EnhanceContext enhanceContext; 019 private final DetectTransactionalMethod detectTransactionalMethod = new DetectTransactionalMethod(); 020 private String className; 021 private boolean entity; 022 private boolean enhancedEntity; 023 private boolean transactional; 024 private boolean enhancedTransactional; 025 026 public DetectEnhancement(ClassLoader classLoader, EnhanceContext context) { 027 super(EBEAN_ASM_VERSION); 028 this.classLoader = classLoader; 029 this.enhanceContext = context; 030 } 031 032 private boolean isLog(int level) { 033 return enhanceContext.isLog(level); 034 } 035 036 private void log(String msg) { 037 enhanceContext.log(className, msg); 038 } 039 040 public void log(int level, String msg) { 041 if (isLog(level)) { 042 log(msg); 043 } 044 } 045 046 public boolean isEnhancedEntity() { 047 return enhancedEntity; 048 } 049 050 public boolean isEnhancedTransactional() { 051 return enhancedTransactional; 052 } 053 054 /** 055 * Return true if this is an entity bean or embeddable bean. 056 */ 057 public boolean isEntity() { 058 return entity; 059 } 060 061 /** 062 * Return true if ANY method has the transactional annotation. 063 */ 064 public boolean isTransactional() { 065 return transactional; 066 } 067 068 /** 069 * Visit the class with interfaces. 070 */ 071 @Override 072 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 073 if ((access & Opcodes.ACC_INTERFACE) != 0) { 074 throw new NoEnhancementRequiredException("Interface type"); 075 } 076 if ((access & Opcodes.ACC_SYNTHETIC) != 0) { 077 throw new NoEnhancementRequiredException("Synthetic type"); 078 } 079 this.className = name; 080 for (String anInterface : interfaces) { 081 if (anInterface.equals(EnhanceConstants.C_ENTITYBEAN)) { 082 enhancedEntity = true; 083 entity = true; 084 } else if (anInterface.equals(EnhanceConstants.C_ENHANCEDTRANSACTIONAL)) { 085 enhancedTransactional = true; 086 } else { 087 ClassMeta interfaceMeta = enhanceContext.interfaceMeta(anInterface, classLoader); 088 if (interfaceMeta != null && interfaceMeta.isTransactional()) { 089 transactional = true; 090 if (isLog(9)) { 091 log("detected implements transactional interface " + interfaceMeta); 092 } 093 } 094 } 095 } 096 097 if (isLog(4)) { 098 log("interfaces: enhancedEntity[" + enhancedEntity + "] transactional[" + enhancedTransactional + "]"); 099 } 100 } 101 102 /** 103 * Visit class level annotations. 104 */ 105 @Override 106 public AnnotationVisitor visitAnnotation(String desc, boolean visible) { 107 if (isEntityAnnotation(desc)) { 108 if (isLog(5)) { 109 log("found entity annotation " + desc); 110 } 111 entity = true; 112 113 } else if (desc.equals(TRANSACTIONAL_ANNOTATION)) { 114 if (isLog(5)) { 115 log("found transactional annotation " + desc); 116 } 117 transactional = true; 118 } 119 return null; 120 } 121 122 /** 123 * Return true if the annotation is for an Entity, Embeddable or MappedSuperclass. 124 */ 125 private boolean isEntityAnnotation(String desc) { 126 return EntityCheck.isEntityAnnotation(desc); 127 } 128 129 /** 130 * Visit the methods specifically looking for method level transactional 131 * annotations. 132 */ 133 @Override 134 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { 135 return detectTransactionalMethod; 136 } 137 138 /** 139 * Check methods for Transactional annotation. 140 */ 141 private class DetectTransactionalMethod extends MethodVisitor { 142 143 DetectTransactionalMethod() { 144 super(EBEAN_ASM_VERSION); 145 } 146 147 @Override 148 public AnnotationVisitor visitAnnotation(String desc, boolean visible) { 149 if (desc.equals(TRANSACTIONAL_ANNOTATION)) { 150 transactional = true; 151 } 152 return null; 153 } 154 155 } 156}