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