Package org.jpox.enhancer.asm

Source Code of org.jpox.enhancer.asm.JdoPropertyGetterAdapter

/**********************************************************************
Copyright (c) 2007 Andy Jefferson and others. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Contributors:
    ...
**********************************************************************/
package org.jpox.enhancer.asm;

import javax.jdo.spi.PersistenceCapable;

import org.jpox.enhancer.ClassEnhancer;
import org.jpox.enhancer.ClassMethod;
import org.jpox.metadata.AbstractClassMetaData;
import org.jpox.metadata.AbstractMemberMetaData;
import org.jpox.util.JPOXLogger;
import org.jpox.util.Localiser;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

/**
* Adapter for property getter methods in JDO-enabled classes.
* This adapter processes the getXXX method and
* <ul>
* <li>Creates jdoGetXXX with the same code as was present in getXXX</li>
* <li>Changes getXXX to have the code below</li>
* </ul>
* When detachable this will be (CHECK_READ variant)
* <pre>
* YYY getZZZ()
* {
*     if (jdoFlags > 0 && jdoStateManager != null && !jdoStateManager.isLoaded(this, 0))
*         return (Integer) jdoStateManager.getObjectField(this, 0, jdoGetXXX());
*     if (jdoIsDetached() && !((BitSet) jdoDetachedState[2]).get(0))
*         throw new JDODetachedFieldAccessException
*             ("You have just attempted to access property \"id\" yet this field was not detached ...");
*     return jdoGetXXX();
* }
* </pre>
* and when not detachable
* <pre>
* YYY getZZZ()
* {
*     if (jdoFlags > 0 && jdoStateManager != null && !jdoStateManager.isLoaded(this, 0))
*         return (Integer) jdoStateManager.getObjectField(this, 0, jdoGetXXX());
*     return jdoGetXXX();
* }
* </pre>
* There are other variants for MEDIATE_READ and NORMAL_READ
*
* @version $Revision: 1.9 $
*/
public class JdoPropertyGetterAdapter extends MethodAdapter
{
    /** Localisation of messages. */
    protected static Localiser LOCALISER = Localiser.getInstance("org.jpox.enhancer.Localisation", ClassEnhancer.class.getClassLoader());

    /** The enhancer for this class. */
    protected ASMClassEnhancer enhancer;

    /** Name for the method being adapted. */
    protected String methodName;

    /** Descriptor for the method being adapted. */
    protected String methodDescriptor;

    /** MetaData for the property. */
    protected AbstractMemberMetaData mmd;

    /** Visitor for the jdoGetXXX method. */
    protected MethodVisitor jdoVisitor = null;

    /**
     * Constructor for the method adapter.
     * @param mv MethodVisitor
     * @param enhancer ClassEnhancer for the class with the method
     * @param methodName Name of the method
     * @param methodDesc Method descriptor
     * @param mmd MetaData for the property
     * @param cv ClassVisitor
     */
    public JdoPropertyGetterAdapter(MethodVisitor mv, ASMClassEnhancer enhancer, String methodName, String methodDesc,
            AbstractMemberMetaData mmd, ClassVisitor cv)
    {
        super(mv);
        this.enhancer = enhancer;
        this.methodName = methodName;
        this.methodDescriptor = methodDesc;
        this.mmd = mmd;

        // Generate jdoGetXXX method to include code that this getXXX currently has
        int access = (mmd.isPublic() ? Opcodes.ACC_PUBLIC : 0) |
            (mmd.isProtected() ? Opcodes.ACC_PROTECTED : 0) |
            (mmd.isPrivate() ? Opcodes.ACC_PRIVATE : 0) |
            (mmd.isAbstract() ? Opcodes.ACC_ABSTRACT : 0);
        this.jdoVisitor = cv.visitMethod(access, "jdoGet" + mmd.getName(), methodDesc, null, null);
    }

    /**
     * Method called at the end of visiting the getXXX method.
     * This is used to add the jdoGetXXX method with the same code as is present originally in the getXXX method.
     */
    public void visitEnd()
    {
        jdoVisitor.visitEnd();
        if (JPOXLogger.ENHANCER.isDebugEnabled())
        {
            String msg = ClassMethod.getMethodAdditionMessage("jdoGet" + mmd.getName(), mmd.getType(), null, null);
            JPOXLogger.ENHANCER.debug(LOCALISER.msg("Enhancer.AddMethod", msg));
        }

        if (!mmd.isAbstract())
        {
            // Property is not abstract so generate the getXXX method to use the jdoGetXXX we just added
            generateGetXXXMethod(mv, mmd, enhancer.getASMClassName(), enhancer.getClassDescriptor());
        }
    }

    /**
     * Convenience method to use the MethodVisitor to generate the code for the method getXXX() for the
     * property with the specified MetaData.
     * @param mv MethodVisitor
     * @param mmd MetaData for the property
     * @param asmClassName ASM class name for the owning class
     * @param asmClassDesc ASM descriptor for the owning class
     */
    public static void generateGetXXXMethod(MethodVisitor mv, AbstractMemberMetaData mmd,
            String asmClassName, String asmClassDesc)
    {
        String[] argNames = new String[] {"objPC"};
        String fieldTypeDesc = Type.getDescriptor(mmd.getType());

        mv.visitCode();

        AbstractClassMetaData cmd = mmd.getAbstractClassMetaData();
        if ((mmd.getJdoFieldFlag() & PersistenceCapable.MEDIATE_READ) == PersistenceCapable.MEDIATE_READ)
        {
            // MEDIATE_READ
            Label startLabel = new Label();
            mv.visitLabel(startLabel);

            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, asmClassName,
                ClassEnhancer.FN_StateManager, "Ljavax/jdo/spi/StateManager;");
            Label l1 = new Label();
            mv.visitJumpInsn(Opcodes.IFNULL, l1);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, asmClassName,
                ClassEnhancer.FN_StateManager, "Ljavax/jdo/spi/StateManager;");
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            ASMUtils.addBIPUSHToMethod(mv, mmd.getFieldId());
            if (cmd.getPersistenceCapableSuperclass() != null)
            {
                mv.visitFieldInsn(Opcodes.GETSTATIC, asmClassName, "jdoInheritedFieldCount", "I");
                mv.visitInsn(Opcodes.IADD);
            }
            mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "javax/jdo/spi/StateManager",
                "isLoaded", "(Ljavax/jdo/spi/PersistenceCapable;I)Z");
            mv.visitJumpInsn(Opcodes.IFNE, l1);

            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, asmClassName,
                ClassEnhancer.FN_StateManager, "Ljavax/jdo/spi/StateManager;");
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            ASMUtils.addBIPUSHToMethod(mv, mmd.getFieldId());
            if (cmd.getPersistenceCapableSuperclass() != null)
            {
                mv.visitFieldInsn(Opcodes.GETSTATIC, asmClassName, "jdoInheritedFieldCount", "I");
                mv.visitInsn(Opcodes.IADD);
            }

            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, asmClassName,
                "jdoGet" + mmd.getName(), "()" + fieldTypeDesc);
            String jdoMethodName = "get" + ASMUtils.getTypeNameForJDOMethod(mmd.getType()) + "Field";
            String argTypeDesc = fieldTypeDesc;
            if (jdoMethodName.equals("getObjectField"))
            {
                argTypeDesc = ASMUtils.CD_Object;
            }
            mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "javax/jdo/spi/StateManager",
                jdoMethodName, "(Ljavax/jdo/spi/PersistenceCapable;I" + argTypeDesc + ")" + argTypeDesc);
            if (jdoMethodName.equals("getObjectField"))
            {
                // Cast any object fields to the correct type
                mv.visitTypeInsn(Opcodes.CHECKCAST, mmd.getTypeName().replace('.', '/'));
            }
            ASMUtils.addReturnForType(mv, mmd.getType());

            mv.visitLabel(l1);

            Label l4 = new Label();
            if (cmd.isDetachable())
            {
                // "if (objPC.jdoIsDetached() != false && ((BitSet) objPC.jdoDetachedState[2]).get(5) != true)"
                mv.visitVarInsn(Opcodes.ALOAD, 0);
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, asmClassName, "jdoIsDetached", "()Z");
                mv.visitJumpInsn(Opcodes.IFEQ, l4);
                mv.visitVarInsn(Opcodes.ALOAD, 0);
                mv.visitFieldInsn(Opcodes.GETFIELD, asmClassName,
                    ClassEnhancer.FN_JdoDetachedState, "[Ljava/lang/Object;");
                mv.visitInsn(Opcodes.ICONST_2);
                mv.visitInsn(Opcodes.AALOAD);
                mv.visitTypeInsn(Opcodes.CHECKCAST, "java/util/BitSet");
                ASMUtils.addBIPUSHToMethod(mv, mmd.getFieldId());
                if (cmd.getPersistenceCapableSuperclass() != null)
                {
                    mv.visitFieldInsn(Opcodes.GETSTATIC, asmClassName, "jdoInheritedFieldCount", "I");
                    mv.visitInsn(Opcodes.IADD);
                }
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/BitSet", "get", "(I)Z");
                mv.visitJumpInsn(Opcodes.IFNE, l4);
                mv.visitVarInsn(Opcodes.ALOAD, 0);
                mv.visitFieldInsn(Opcodes.GETFIELD, asmClassName,
                    ClassEnhancer.FN_JdoDetachedState, "[Ljava/lang/Object;");
                mv.visitInsn(Opcodes.ICONST_3);
                mv.visitInsn(Opcodes.AALOAD);
                mv.visitTypeInsn(Opcodes.CHECKCAST, "java/util/BitSet");
                ASMUtils.addBIPUSHToMethod(mv, mmd.getFieldId());
                if (cmd.getPersistenceCapableSuperclass() != null)
                {
                    mv.visitFieldInsn(Opcodes.GETSTATIC, asmClassName, "jdoInheritedFieldCount", "I");
                    mv.visitInsn(Opcodes.IADD);
                }
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/BitSet", "get", "(I)Z");
                mv.visitJumpInsn(Opcodes.IFNE, l4);

                // "throw new JDODetachedFieldAccessException(...)"
                mv.visitTypeInsn(Opcodes.NEW, "javax/jdo/JDODetachedFieldAccessException");
                mv.visitInsn(Opcodes.DUP);
                mv.visitLdcInsn(LOCALISER.msg("Enhancer.DetachedPropertyAccess", mmd.getName()));
                mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "javax/jdo/JDODetachedFieldAccessException",
                    "<init>", "(Ljava/lang/String;)V");
                mv.visitInsn(Opcodes.ATHROW);
            }

            mv.visitLabel(l4);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, asmClassName,
                "jdoGet" + mmd.getName(), "()" + fieldTypeDesc);
            ASMUtils.addReturnForType(mv, mmd.getType());

            Label endLabel = new Label();
            mv.visitLabel(endLabel);
            mv.visitLocalVariable(argNames[0], asmClassDesc, null, startLabel, endLabel, 0);
            mv.visitMaxs(4, 1);
        }
        else if ((mmd.getJdoFieldFlag() & PersistenceCapable.CHECK_READ) == PersistenceCapable.CHECK_READ)
        {
            // CHECK_READ
            Label startLabel = new Label();
            mv.visitLabel(startLabel);

            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, asmClassName, ClassEnhancer.FN_Flag, "B");
            Label l1 = new Label();
            mv.visitJumpInsn(Opcodes.IFLE, l1);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, asmClassName,
                ClassEnhancer.FN_StateManager, "Ljavax/jdo/spi/StateManager;");
            mv.visitJumpInsn(Opcodes.IFNULL, l1);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, asmClassName,
                ClassEnhancer.FN_StateManager, "Ljavax/jdo/spi/StateManager;");
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            ASMUtils.addBIPUSHToMethod(mv, mmd.getFieldId());
            if (cmd.getPersistenceCapableSuperclass() != null)
            {
                mv.visitFieldInsn(Opcodes.GETSTATIC, asmClassName,
                    ClassEnhancer.FN_JdoInheritedFieldCount, "I");
                mv.visitInsn(Opcodes.IADD);
            }
            mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "javax/jdo/spi/StateManager",
                "isLoaded", "(Ljavax/jdo/spi/PersistenceCapable;I)Z");
            mv.visitJumpInsn(Opcodes.IFNE, l1);

            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, asmClassName,
                ClassEnhancer.FN_StateManager, "Ljavax/jdo/spi/StateManager;");
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            ASMUtils.addBIPUSHToMethod(mv, mmd.getFieldId());
            if (cmd.getPersistenceCapableSuperclass() != null)
            {
                mv.visitFieldInsn(Opcodes.GETSTATIC, asmClassName, ClassEnhancer.FN_JdoInheritedFieldCount, "I");
                mv.visitInsn(Opcodes.IADD);
            }

            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, asmClassName, "jdoGet" + mmd.getName(), "()" + fieldTypeDesc);
            String jdoMethodName = "get" + ASMUtils.getTypeNameForJDOMethod(mmd.getType()) + "Field";
            String argTypeDesc = fieldTypeDesc;
            if (jdoMethodName.equals("getObjectField"))
            {
                argTypeDesc = ASMUtils.CD_Object;
            }
            mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "javax/jdo/spi/StateManager",
                jdoMethodName, "(Ljavax/jdo/spi/PersistenceCapable;I" + argTypeDesc + ")" + argTypeDesc);
            if (jdoMethodName.equals("getObjectField"))
            {
                // Cast any object fields to the correct type
                mv.visitTypeInsn(Opcodes.CHECKCAST, mmd.getTypeName().replace('.', '/'));
            }
            ASMUtils.addReturnForType(mv, mmd.getType());

            mv.visitLabel(l1);

            Label l4 = new Label();
            if (cmd.isDetachable())
            {
                // "if (objPC.jdoIsDetached() != false && ((BitSet) objPC.jdoDetachedState[2]).get(5) != true)"
                mv.visitVarInsn(Opcodes.ALOAD, 0);
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, asmClassName, ClassEnhancer.MN_JdoIsDetached, "()Z");
                mv.visitJumpInsn(Opcodes.IFEQ, l4);
                mv.visitVarInsn(Opcodes.ALOAD, 0);
                mv.visitFieldInsn(Opcodes.GETFIELD, asmClassName,
                    ClassEnhancer.FN_JdoDetachedState, "[Ljava/lang/Object;");
                mv.visitInsn(Opcodes.ICONST_2);
                mv.visitInsn(Opcodes.AALOAD);
                mv.visitTypeInsn(Opcodes.CHECKCAST, "java/util/BitSet");
                ASMUtils.addBIPUSHToMethod(mv, mmd.getFieldId());
                if (cmd.getPersistenceCapableSuperclass() != null)
                {
                    mv.visitFieldInsn(Opcodes.GETSTATIC, asmClassName,
                        ClassEnhancer.FN_JdoInheritedFieldCount, "I");
                    mv.visitInsn(Opcodes.IADD);
                }
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/BitSet", "get", "(I)Z");
                mv.visitJumpInsn(Opcodes.IFNE, l4);

                // "throw new JDODetachedFieldAccessException(...)"
                mv.visitTypeInsn(Opcodes.NEW, "javax/jdo/JDODetachedFieldAccessException");
                mv.visitInsn(Opcodes.DUP);
                mv.visitLdcInsn(LOCALISER.msg("Enhancer.DetachedPropertyAccess", mmd.getName()));
                mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "javax/jdo/JDODetachedFieldAccessException",
                    "<init>", "(Ljava/lang/String;)V");
                mv.visitInsn(Opcodes.ATHROW);
            }

            mv.visitLabel(l4);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, asmClassName,
                "jdoGet" + mmd.getName(), "()" + fieldTypeDesc);
            ASMUtils.addReturnForType(mv, mmd.getType());

            Label endLabel = new Label();
            mv.visitLabel(endLabel);
            mv.visitLocalVariable(argNames[0], asmClassDesc, null, startLabel, endLabel, 0);
            mv.visitMaxs(4, 1);
        }
        else
        {
            // NORMAL
            Label startLabel = new Label();
            mv.visitLabel(startLabel);

            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, asmClassName,
                "jdoGet" + mmd.getName(), "()" + fieldTypeDesc);
            ASMUtils.addReturnForType(mv, mmd.getType());

            Label endLabel = new Label();
            mv.visitLabel(endLabel);
            mv.visitLocalVariable(argNames[0], asmClassDesc, null, startLabel, endLabel, 0);
            mv.visitMaxs(1, 1);
        }

        mv.visitEnd();
    }

    public AnnotationVisitor visitAnnotation(String arg0, boolean arg1)
    {
        // Keep any annotations on the getXXX method
        return mv.visitAnnotation(arg0, arg1);
    }

    public AnnotationVisitor visitAnnotationDefault()
    {
        return jdoVisitor.visitAnnotationDefault();
    }

    public void visitAttribute(Attribute arg0)
    {
        jdoVisitor.visitAttribute(arg0);
    }

    public void visitCode()
    {
        jdoVisitor.visitCode();
    }

    public void visitFieldInsn(int arg0, String arg1, String arg2, String arg3)
    {
        jdoVisitor.visitFieldInsn(arg0, arg1, arg2, arg3);
    }

    public void visitFrame(int arg0, int arg1, Object[] arg2, int arg3, Object[] arg4)
    {
        jdoVisitor.visitFrame(arg0, arg1, arg2, arg3, arg4);
    }

    public void visitIincInsn(int arg0, int arg1)
    {
        jdoVisitor.visitIincInsn(arg0, arg1);
    }

    public void visitInsn(int arg0)
    {
        jdoVisitor.visitInsn(arg0);
    }

    public void visitIntInsn(int arg0, int arg1)
    {
        jdoVisitor.visitIntInsn(arg0, arg1);
    }

    public void visitJumpInsn(int arg0, Label arg1)
    {
        jdoVisitor.visitJumpInsn(arg0, arg1);
    }

    public void visitLabel(Label arg0)
    {
        jdoVisitor.visitLabel(arg0);
    }

    public void visitLdcInsn(Object arg0)
    {
        jdoVisitor.visitLdcInsn(arg0);
    }

    public void visitLineNumber(int arg0, Label arg1)
    {
        jdoVisitor.visitLineNumber(arg0, arg1);
    }

    public void visitLocalVariable(String arg0, String arg1, String arg2, Label arg3, Label arg4, int arg5)
    {
        jdoVisitor.visitLocalVariable(arg0, arg1, arg2, arg3, arg4, arg5);
    }

    public void visitLookupSwitchInsn(Label arg0, int[] arg1, Label[] arg2)
    {
        jdoVisitor.visitLookupSwitchInsn(arg0, arg1, arg2);
    }

    public void visitMaxs(int arg0, int arg1)
    {
        jdoVisitor.visitMaxs(arg0, arg1);
    }

    public void visitMethodInsn(int arg0, String arg1, String arg2, String arg3)
    {
        jdoVisitor.visitMethodInsn(arg0, arg1, arg2, arg3);
    }

    public void visitMultiANewArrayInsn(String arg0, int arg1)
    {
        jdoVisitor.visitMultiANewArrayInsn(arg0, arg1);
    }

    public AnnotationVisitor visitParameterAnnotation(int arg0, String arg1, boolean arg2)
    {
        return jdoVisitor.visitParameterAnnotation(arg0, arg1, arg2);
    }

    public void visitTableSwitchInsn(int arg0, int arg1, Label arg2, Label[] arg3)
    {
        jdoVisitor.visitTableSwitchInsn(arg0, arg1, arg2, arg3);
    }

    public void visitTryCatchBlock(Label arg0, Label arg1, Label arg2, String arg3)
    {
        jdoVisitor.visitTryCatchBlock(arg0, arg1, arg2, arg3);
    }

    public void visitTypeInsn(int arg0, String arg1)
    {
        jdoVisitor.visitTypeInsn(arg0, arg1);
    }

    public void visitVarInsn(int arg0, int arg1)
    {
        jdoVisitor.visitVarInsn(arg0, arg1);
    }
}
TOP

Related Classes of org.jpox.enhancer.asm.JdoPropertyGetterAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.