001package io.ebean.enhance.entity;
002
003import io.ebean.enhance.asm.ClassVisitor;
004import io.ebean.enhance.asm.Label;
005import io.ebean.enhance.asm.MethodVisitor;
006import io.ebean.enhance.asm.Opcodes;
007import io.ebean.enhance.common.ClassMeta;
008import io.ebean.enhance.common.EnhanceConstants;
009
010import java.util.List;
011
012/**
013 * Used to detect if a class has been enhanced.
014 * <p>
015 * Moved to use this over just relying on the existence of the EntityBean interface
016 * to make the enhancement more robust.
017 * </p>
018 */
019public class MethodIsEmbeddedNewOrDirty implements Opcodes, EnhanceConstants {
020
021        /**
022         * Generate the _ebean_isEmbeddedNewOrDirty() method.
023         * 
024         * <pre>
025         * public boolean _ebean_isEmbeddedNewOrDirty() {
026         *  // for each embedded bean field...
027         *      if (entityBeanIntercept.isEmbeddedNewOrDirty(embeddedBeanField)) return true;
028         *  ...
029         *  return false;
030         * }
031         * </pre>
032         */
033        public static void addMethod(ClassVisitor cv, ClassMeta classMeta) {
034                
035                String className = classMeta.getClassName();
036                
037                MethodVisitor mv;
038
039                mv = cv.visitMethod(ACC_PUBLIC, "_ebean_isEmbeddedNewOrDirty", "()Z", null, null);
040                mv.visitCode();
041                
042                Label labelBegin = null;
043                
044                Label labelNext = null;
045                
046                List<FieldMeta> allFields = classMeta.getAllFields();
047                for (int i = 0; i < allFields.size(); i++) {
048                        FieldMeta fieldMeta = allFields.get(i);
049                        if (fieldMeta.isEmbedded()){
050                                
051                                Label l0 = labelNext;
052                                if (l0 == null) {
053                                        l0 = new Label();
054                                }
055                                if (labelBegin == null){
056                                        labelBegin = l0;
057                                }
058                                
059                                mv.visitLabel(l0);
060                                mv.visitLineNumber(0, l0);
061                                if (i > 0) {
062                                        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
063                                }
064                                mv.visitVarInsn(ALOAD, 0);
065                                mv.visitFieldInsn(GETFIELD, className, INTERCEPT_FIELD, L_INTERCEPT);
066                                mv.visitVarInsn(ALOAD, 0);
067                                fieldMeta.appendSwitchGet(mv, classMeta, false);
068                                mv.visitMethodInsn(INVOKEVIRTUAL, C_INTERCEPT, "isEmbeddedNewOrDirty", "(Ljava/lang/Object;)Z", false);
069
070                                labelNext = new Label();
071                                mv.visitJumpInsn(IFEQ, labelNext);
072                                mv.visitInsn(ICONST_1);
073                                mv.visitInsn(IRETURN);
074                                
075                        }
076                }
077                
078                if (labelNext == null){
079                        labelNext = new Label();
080                }
081                if (labelBegin == null){
082                        labelBegin = labelNext;
083                }       
084                mv.visitLabel(labelNext);
085                mv.visitLineNumber(1, labelNext);
086                mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
087                mv.visitInsn(ICONST_0);
088                mv.visitInsn(IRETURN);
089                
090                Label l3 = new Label();
091                mv.visitLabel(l3);
092                mv.visitLocalVariable("this", "L"+className+";", null, labelBegin, l3, 0);
093                mv.visitMaxs(2, 1);
094                mv.visitEnd();
095
096        }
097}