Package org.jpox.enhancer.asm

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

/**********************************************************************
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 org.jpox.enhancer.ClassEnhancer;
import org.jpox.enhancer.asm.method.InitClass;
import org.jpox.metadata.AbstractClassMetaData;
import org.jpox.metadata.AbstractMemberMetaData;
import org.jpox.metadata.ClassPersistenceModifier;
import org.jpox.metadata.FieldPersistenceModifier;
import org.jpox.util.JPOXLogger;
import org.jpox.util.Localiser;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

/**
* Adapter for methods in JDO-enabled classes allowing enhancement of direct access to user fields.
* Currently performs the following updates
* <ul>
* <li>Any GETFIELD on a field of a PersistenceCapable class is replaced by a call to jdoGetXXX()</li>
* <li>Any PUTFIELD on a field of a PersistenceCapable class is replaced by a call to jdoSetXXX()</li>
* <li>Any clone() method that has no superclass but calls clone() is changed to call jdoSuperClone()</li>
* <li>Any static class initialisation adds on the Jdo "InitClass" instructions</li>
* </ul>
*
* @version $Revision: 1.12 $
*/
public class JdoMethodAdapter 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;

    /**
     * Constructor for the method adapter.
     * @param mv MethodVisitor
     * @param enhancer ClassEnhancer for the class with the method
     */
    public JdoMethodAdapter(MethodVisitor mv, ASMClassEnhancer enhancer, String methodName, String methodDesc)
    {
        super(mv);
        this.enhancer = enhancer;
        this.methodName = methodName;
        this.methodDescriptor = methodDesc;
    }

    /**
     * Method to intercept any calls to fields.
     * @param opcode Operation
     * @param owner Owner class
     * @param name Name of the field
     * @param desc Descriptor for the field
     */
    public void visitFieldInsn(int opcode, String owner, String name, String desc)
    {
        String ownerName = owner.replace('/', '.');
        if (enhancer.isPersistenceCapable(ownerName))
        {
            AbstractClassMetaData cmd = null;
            if (enhancer.getClassMetaData().getFullClassName().equals(ownerName))
            {
                // Same class so use the input MetaData
                cmd = enhancer.getClassMetaData();
            }
            else
            {
                cmd = enhancer.getClassMetaData().getMetaDataManager().getMetaDataForClass(
                    ownerName, enhancer.getClassLoaderResolver());
            }
            AbstractMemberMetaData fmd = cmd.getMetaDataForMember(name);
            if (fmd != null && !fmd.isStatic() && !fmd.isFinal() &&
                fmd.getPersistenceModifier() != FieldPersistenceModifier.NONE &&
                fmd.getJdoFieldFlag() != 0 && !fmd.isProperty())
            {
                // Field being accessed has its access mediated by the enhancer, so intercept it
                // Make sure we address the field being in the class it is actually in
                String fieldOwner = fmd.getClassName(true).replace('.', '/');
                if (opcode == Opcodes.GETFIELD)
                {
                    // Read of a field of a PC class, so replace with jdoGetXXX() call
                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, fieldOwner, "jdoGet" + name,
                        "(L" + fieldOwner + ";)" + desc);
                    if (JPOXLogger.ENHANCER.isDebugEnabled())
                    {
                        JPOXLogger.ENHANCER.debug(LOCALISER.msg("Enhancer.EnhanceOriginalMethodField",
                            enhancer.className + "." + methodName, name, "jdoGet" + name + "()"));
                    }
                    return;
                }
                else if (opcode == Opcodes.PUTFIELD)
                {
                    // Write of a field of a PC class, so replace with jdoSetXXX() call
                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, fieldOwner, "jdoSet" + name,
                        "(L" + fieldOwner + ";" + desc + ")V");
                    if (JPOXLogger.ENHANCER.isDebugEnabled())
                    {
                        JPOXLogger.ENHANCER.debug(LOCALISER.msg("Enhancer.EnhanceOriginalMethodField",
                            enhancer.className + "." + methodName, name, "jdoSet" + name + "()"));
                    }
                    return;
                }
            }
        }

        super.visitFieldInsn(opcode, owner, name, desc);
    }

    /**
     * Method to intercept any calls to methods.
     * @param opcode Operation
     * @param owner Owner class
     * @param name Name of the field
     * @param desc Descriptor for the field
     */
    public void visitMethodInsn(int opcode, String owner, String name, String desc)
    {
        if (methodName.equals("clone") && methodDescriptor.equals("()Ljava/lang/Object;") &&
            enhancer.getClassMetaData().getPersistenceCapableSuperclass() == null &&
            opcode == Opcodes.INVOKESPECIAL && name.equals("clone") && desc.equals("()Ljava/lang/Object;"))
        {
            // clone() method calls super.clone() so change to use JdoSuperClone()
            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, enhancer.getASMClassName(), "jdoSuperClone", "()Ljava/lang/Object;");
            return;
        }

        super.visitMethodInsn(opcode, owner, name, desc);
    }

    /**
     * Method to intercept any general instructions.
     * We use it to intercept any RETURN on a static initialisation block so we can append to it.
     * @param opcode Operation
     */
    public void visitInsn(int opcode)
    {
        if (enhancer.getClassMetaData().getPersistenceModifier() == ClassPersistenceModifier.PERSISTENCE_CAPABLE &&
            methodName.equals("<clinit>") && methodDescriptor.equals("()V") && opcode == Opcodes.RETURN)
        {
            // Add the initialise instructions to the existing block
            InitClass initMethod = InitClass.getInstance(enhancer);
            initMethod.addInitialiseInstructions(mv);

            // Add the RETURN
            mv.visitInsn(Opcodes.RETURN);
            return;
        }

        super.visitInsn(opcode);
    }
}
TOP

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

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.