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 008/** 009 * ClassAdapter used to detect if this class needs enhancement for entity or 010 * transactional support. 011 */ 012public class DetectEnhancement extends ClassVisitor { 013 014 private final ClassLoader classLoader; 015 016 private final EnhanceContext enhanceContext; 017 018 private final DetectTransactionalMethod detectTransactionalMethod = new DetectTransactionalMethod(); 019 020 private String className; 021 022 private boolean entity; 023 024 private boolean enhancedEntity; 025 026 private boolean transactional; 027 028 private boolean enhancedTransactional; 029 030 public DetectEnhancement(ClassLoader classLoader, EnhanceContext context) { 031 super(Opcodes.ASM7); 032 this.classLoader = classLoader; 033 this.enhanceContext = context; 034 } 035 036 public boolean isLog(int level) { 037 return enhanceContext.isLog(level); 038 } 039 040 public void log(String msg) { 041 enhanceContext.log(className, msg); 042 } 043 044 public void log(int level, String msg) { 045 if (isLog(level)) { 046 log(msg); 047 } 048 } 049 050 public boolean isEnhancedEntity() { 051 return enhancedEntity; 052 } 053 054 public boolean isEnhancedTransactional() { 055 return enhancedTransactional; 056 } 057 058 /** 059 * Return true if this is an entity bean or embeddable bean. 060 */ 061 public boolean isEntity() { 062 return entity; 063 } 064 065 /** 066 * Return true if ANY method has the transactional annotation. 067 */ 068 public boolean isTransactional() { 069 return transactional; 070 } 071 072 /** 073 * Visit the class with interfaces. 074 */ 075 @Override 076 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 077 078 if ((access & Opcodes.ACC_INTERFACE) != 0) { 079 throw new NoEnhancementRequiredException("Interface type"); 080 } 081 082 this.className = name; 083 084 for (int i = 0; i < interfaces.length; i++) { 085 086 if (interfaces[i].equals(EnhanceConstants.C_ENTITYBEAN)) { 087 enhancedEntity = true; 088 entity = true; 089 090 } else if (interfaces[i].equals(EnhanceConstants.C_ENHANCEDTRANSACTIONAL)) { 091 enhancedTransactional = true; 092 093 } else { 094 ClassMeta interfaceMeta = enhanceContext.getInterfaceMeta(interfaces[i], 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(EnhanceConstants.AVAJE_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(EnhanceConstants.AVAJE_TRANSACTIONAL_ANNOTATION)) { 157 transactional = true; 158 } 159 return null; 160 } 161 162 } 163}