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