package com.avaje.ebean.enhance.agent; import com.avaje.ebean.enhance.asm.ClassVisitor; import com.avaje.ebean.enhance.asm.Label; import com.avaje.ebean.enhance.asm.MethodVisitor; import com.avaje.ebean.enhance.asm.Opcodes; /** * Used to detect if a class has been enhanced. * <p> * Moved to use this over just relying on the existence of the EntityBean interface * to make the enhancement more robust. * </p> */ public class MethodPropertyChangeListener implements Opcodes, EnhanceConstants { /** * Add the addPropertyChangeListener and removePropertyChangeListener methods. */ public static void addMethod(ClassVisitor cv, ClassMeta classMeta) { addAddListenerMethod(cv, classMeta); addAddPropertyListenerMethod(cv, classMeta); addRemoveListenerMethod(cv, classMeta); addRemovePropertyListenerMethod(cv, classMeta); } private static boolean alreadyExisting(ClassMeta classMeta, String method, String desc) { if (classMeta.isExistingMethod(method, desc)){ if (classMeta.isLog(1)){ classMeta.log("Existing method... "+method+desc+" - not adding Ebean's implementation"); } return true; } return false; } /** * Generate the addPropertyChangeListener method. * * <pre> * public void addPropertyChangeListener(PropertyChangeListener listener) { * _ebean_intercept.addPropertyChangeListener(listener); * } * </pre> */ private static void addAddListenerMethod(ClassVisitor cv, ClassMeta classMeta) { String desc = "(Ljava/beans/PropertyChangeListener;)V"; if (alreadyExisting(classMeta, "addPropertyChangeListener", desc)){ return; } String className = classMeta.getClassName(); MethodVisitor mv; mv = cv.visitMethod(ACC_PUBLIC, "addPropertyChangeListener", desc, null, null); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitLineNumber(1, l0); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, className, INTERCEPT_FIELD, L_INTERCEPT); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, C_INTERCEPT, "addPropertyChangeListener", "(Ljava/beans/PropertyChangeListener;)V"); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLineNumber(2, l1); mv.visitInsn(RETURN); Label l2 = new Label(); mv.visitLabel(l2); mv.visitLocalVariable("this", "L"+className+";", null, l0, l2, 0); mv.visitLocalVariable("listener", "Ljava/beans/PropertyChangeListener;", null, l0, l2, 1); mv.visitMaxs(2, 2); mv.visitEnd(); } private static void addAddPropertyListenerMethod(ClassVisitor cv, ClassMeta classMeta) { String desc = "(Ljava/lang/String;Ljava/beans/PropertyChangeListener;)V"; if (alreadyExisting(classMeta, "addPropertyChangeListener", desc)){ return; } String className = classMeta.getClassName(); MethodVisitor mv; mv = cv.visitMethod(ACC_PUBLIC, "addPropertyChangeListener", desc, null, null); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitLineNumber(1, l0); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, className, INTERCEPT_FIELD, L_INTERCEPT); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, C_INTERCEPT, "addPropertyChangeListener", "(Ljava/lang/String;Ljava/beans/PropertyChangeListener;)V"); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLineNumber(2, l1); mv.visitInsn(RETURN); Label l2 = new Label(); mv.visitLabel(l2); mv.visitLocalVariable("this", "L"+className+";", null, l0, l2, 0); mv.visitLocalVariable("name", "Ljava/lang/String;", null, l0, l2, 1); mv.visitLocalVariable("listener", "Ljava/beans/PropertyChangeListener;", null, l0, l2, 2); mv.visitMaxs(3, 3); mv.visitEnd(); } /** * Add the removePropertyChangeListener method. * * <pre> * public void removePropertyChangeListener(PropertyChangeListener listener) { * _ebean_intercept.removePropertyChangeListener(listener); * } * </pre> */ private static void addRemoveListenerMethod(ClassVisitor cv, ClassMeta classMeta) { String desc = "(Ljava/beans/PropertyChangeListener;)V"; if (alreadyExisting(classMeta, "removePropertyChangeListener", desc)){ return; } String className = classMeta.getClassName(); MethodVisitor mv; mv = cv.visitMethod(ACC_PUBLIC, "removePropertyChangeListener", desc, null, null); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitLineNumber(1, l0); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, className, INTERCEPT_FIELD, L_INTERCEPT); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, C_INTERCEPT, "removePropertyChangeListener", "(Ljava/beans/PropertyChangeListener;)V"); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLineNumber(2, l1); mv.visitInsn(RETURN); Label l2 = new Label(); mv.visitLabel(l2); mv.visitLocalVariable("this", "L"+className+";", null, l0, l2, 0); mv.visitLocalVariable("listener", "Ljava/beans/PropertyChangeListener;", null, l0, l2, 1); mv.visitMaxs(2, 2); mv.visitEnd(); } private static void addRemovePropertyListenerMethod(ClassVisitor cv, ClassMeta classMeta) { String desc = "(Ljava/lang/String;Ljava/beans/PropertyChangeListener;)V"; if (alreadyExisting(classMeta, "removePropertyChangeListener", desc)){ return; } String className = classMeta.getClassName(); MethodVisitor mv; mv = cv.visitMethod(ACC_PUBLIC, "removePropertyChangeListener", desc, null, null); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitLineNumber(1, l0); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, className, INTERCEPT_FIELD, L_INTERCEPT); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, C_INTERCEPT, "removePropertyChangeListener", "(Ljava/lang/String;Ljava/beans/PropertyChangeListener;)V"); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLineNumber(2, l1); mv.visitInsn(RETURN); Label l2 = new Label(); mv.visitLabel(l2); mv.visitLocalVariable("this", "L"+className+";", null, l0, l2, 0); mv.visitLocalVariable("name", "Ljava/lang/String;", null, l0, l2, 1); mv.visitLocalVariable("listener", "Ljava/beans/PropertyChangeListener;", null, l0, l2, 2); mv.visitMaxs(3, 3); mv.visitEnd(); } }