Package org.apache.openejb.core.cmp.cmp2

Source Code of org.apache.openejb.core.cmp.cmp2.Cmp2Generator

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.openejb.core.cmp.cmp2;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.ejb.EntityContext;

import org.apache.openejb.OpenEJBRuntimeException;
import org.apache.xbean.asm4.ClassWriter;
import org.apache.xbean.asm4.FieldVisitor;
import org.apache.xbean.asm4.Label;
import org.apache.xbean.asm4.MethodVisitor;
import org.apache.xbean.asm4.Opcodes;
import org.apache.xbean.asm4.Type;

/**
* Code generate for CMP level 2 beans.  This will
* generate the concrete class used to instantiate
* the bean instance.
*/
public class Cmp2Generator implements Opcodes {
    private static final String UNKNOWN_PK_NAME = "OpenEJB_pk";
    private static final Type UNKNOWN_PK_TYPE = Type.getType(Long.class);

    private final String implClassName;
    private final String beanClassName;
    private final ClassWriter cw;
    private final Map<String, CmpField> cmpFields = new LinkedHashMap<String, CmpField>();
    private final Collection<CmrField> cmrFields = new ArrayList<CmrField>();
    private final CmpField pkField;
    private final Class primKeyClass;
    private final List<Method> selectMethods = new ArrayList<Method>();
    private final Class beanClass;
    private final PostCreateGenerator postCreateGenerator;
    private static final String DELETED = "openejb_deleted";

    /**
     * Constructor for a Cmp2Generator.  This validates the
     * initial EJB state information and prepares for the
     * code generation process.
     *
     * @param cmpImplClass
     *                  The name of the implementation class we're generating.
     * @param beanClass The bean implementation class that is our starting
     *                  point for code generation.
     * @param pkField   The name of the primary key field (optional if the
     *                  primary key class is given).
     * @param primKeyClass
     *                  The optional primary key class for complex primary
     *                  keys.
     * @param cmpFields The list of fields that are managed using cmp.
     */
    public Cmp2Generator(String cmpImplClass, Class beanClass, String pkField, Class<?> primKeyClass, String[] cmpFields) {

        this.beanClass = beanClass;
        beanClassName = Type.getInternalName(beanClass);
        implClassName = cmpImplClass.replace('.', '/');
       
        if (pkField == null && primKeyClass == null) {
            throw new NullPointerException("Both pkField and primKeyClass are null for bean " + beanClassName);
        }
       
        this.primKeyClass = primKeyClass;
       

        // for each of the defined cmp fields, we need to locate the getter method
        // for the name and retrieve the type.  This a) verifies that we have at least
        // a getter defined and b) that we know the field return type.  The created CmpField
        // list will feed into the generation process.
        for (String cmpFieldName : cmpFields) {
            Method getter = getterMethod(cmpFieldName);
            if (getter == null) {
                throw new IllegalArgumentException("No such property " + cmpFieldName + " defined on bean class " + beanClassName);
            }
            // if this is an abstract method, then it's one we have to generate
            if (Modifier.isAbstract(getter.getModifiers())) {

                Type type = Type.getType(getter.getReturnType());
                CmpField cmpField = new CmpField(cmpFieldName, type, getter);
                this.cmpFields.put(cmpFieldName, cmpField);
            }
            else {
                // the getter is non-abstract.  We only allow this if the class that
                // defines the getter also has a private field with a matching type. 
                try {
                    Field field = getter.getDeclaringClass().getDeclaredField(cmpFieldName);
                    // if this is a private field, then just continue.  We don't need to generate
                    // any code for this
                    if (Modifier.isPrivate(field.getModifiers())) {
                        continue;
                    }
                } catch (NoSuchFieldException e) {
                }
                throw new IllegalArgumentException("No such property " + cmpFieldName + " defined on bean class " + beanClassName);
            }
        }

        // if a pkField is defined, it MUST be a CMP field.  Make sure it really exists
        // in the list we constructed above.
        if (pkField != null) {
            this.pkField = this.cmpFields.get(pkField);
            if (this.pkField == null) {
                throw new IllegalArgumentException("No such property " + pkField + " defined on bean class " + beanClassName);
            }
        } else {
            this.pkField = null;
        }

        // build up the list of ejbSelectxxxx methods.  These will be generated automatically.
        for (Method method : beanClass.getMethods()) {
            if (Modifier.isAbstract(method.getModifiers()) && method.getName().startsWith("ejbSelect")) {
                addSelectMethod(method);
            }
        }

        // The class writer will be used for all generator activies, while the
        // postCreateGenerator will be used to add the ejbPostCreatexxxx methods as a
        // last step.
        cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        postCreateGenerator = new PostCreateGenerator(beanClass, cw);
    }

    /**
     * Add a field to the list of fields defined as CMR
     * fields.  Note that if the field is also defined
     * as a CMP field, it will be removed from the normal
     * CMP list.
     *
     * @param cmrField The new CMR field definition pulled from the
     *                 EJB metadata.
     */
    public void addCmrField(CmrField cmrField) {
        if (cmpFields.get(cmrField.getName()) != null) {
            cmpFields.remove(cmrField.getName());
        }
        cmrFields.add(cmrField);
    }

    /**
     * Add a method to the list of ejbSelect methods that
     * need to be processed.
     *
     * @param selectMethod
     *               The method that needs to be processed.
     */
    public void addSelectMethod(Method selectMethod) {
        selectMethods.add(selectMethod);
    }

    /**
     * Perform the generation step for a CMP Entity Bean. 
     * This uses the accumulated meta data and the
     * base bean class to generate a subclass with
     * the automatically generated bits of OpenEJB infrastructure
     * hooks.
     *
     * @return The class file byte array to be used for defining this
     *         class.
     */
    public byte[] generate() {
        // generate the class as super class of the base bean class.  This class will also implment
        // EntityBean and Cmp2Entity.
        cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, implClassName, null, beanClassName, new String[]{"org/apache/openejb/core/cmp/cmp2/Cmp2Entity", "javax/ejb/EntityBean"});

        // public static Object deploymentInfo;
        {
            FieldVisitor fv = cw.visitField(ACC_PUBLIC + ACC_STATIC, "deploymentInfo", "Ljava/lang/Object;", null, null);
            fv.visitEnd();
        }

        // private transient boolean deleted;
        {
            FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_TRANSIENT, DELETED, "Z", null, null);
            fv.visitEnd();
        }

        if (Object.class.equals(primKeyClass)) {
            FieldVisitor fv = cw.visitField(ACC_PRIVATE, UNKNOWN_PK_NAME, UNKNOWN_PK_TYPE.getDescriptor(), null, null);
            fv.visitEnd();
        }

        // Generate the set of cmp fields as private attributes.
        // private ${cmpField.type} ${cmpField.name};
        for (CmpField cmpField : cmpFields.values()) {
            createField(cmpField);
        }

        // and create the corresponding CMR fields as well.
        for (CmrField cmrField : cmrFields) {
            createCmrFields(cmrField);
        }

        createConstructor();

        // now for each of the CMP fields, generate the getter and setter methods
        // from the abstract methods the bean author should have provided.
        for (CmpField cmpField : cmpFields.values()) {
            // public ${cmpField.type} get${cmpField.name}() {
            //     return this.${cmpField.name};
            // }
            createGetter(cmpField);

            // public void setId(${cmpField.type} ${cmpField.name}) {
            //    this.${cmpField.name} = ${cmpField.name};
            // }
            createSetter(cmpField);
        }

        // and repeat this for the cmr fields.
        for (CmrField cmrField : cmrFields) {
            createCmrGetter(cmrField);
            createCmrSetter(cmrField);
        }

       
        createSimplePrimaryKeyGetter();

        // add the set of OpenEJB container management methods.
        createOpenEJB_isDeleted();
        createOpenEJB_deleted();
        createOpenEJB_addCmr();
        createOpenEJB_removeCmr();

        // generate the select methods
        for (Method selectMethod : selectMethods) {
            createSelectMethod(selectMethod);
        }

       
        // now automatically generate any of the ejb* methods.  According to the
        // spec, the bean author should be responsble for these, but since these
        // are frequently just nop stubs, we'll take responsibility for creating
        // empty ones in the generated superclass.
        if (!hasMethod(beanClass, "ejbActivate")) createEjbActivate();
        if (!hasMethod(beanClass, "ejbPassivate")) createEjbPassivate();
        if (!hasMethod(beanClass, "ejbLoad")) createEjbLoad();
        if (!hasMethod(beanClass, "ejbStore")) createEjbStore();
        if (!hasMethod(beanClass, "ejbRemove")) createEjbRemove();
        if (!hasMethod(beanClass, "setEntityContext", EntityContext.class)) createSetEntityContext();
        if (!hasMethod(beanClass, "unsetEntityContext")) createUnsetEntityContext();

        // add on any post-create methods that might be required.
        postCreateGenerator.generate();

        cw.visitEnd();
        // the class, in theory, is now complete.  Return in byte[] form so this can
        // be defined in the appropriate classloader instance.
        return cw.toByteArray();
    }

    private boolean hasMethod(Class beanClass, String name, Class... args) {
        try {
            Method method = beanClass.getMethod(name, args);
            return !Modifier.isAbstract(method.getModifiers());
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    private void createConstructor() {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, beanClassName, "<init>", "()V");

        for (CmrField cmrField : cmrFields) {
            initCmrFields(mv, cmrField);
        }

        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    private void createOpenEJB_isDeleted() {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "OpenEJB_isDeleted", "()Z", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, implClassName, DELETED, "Z");
        mv.visitInsn(IRETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    private void createOpenEJB_deleted() {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "OpenEJB_deleted", "()V", null, null);
        mv.visitCode();

        /* if (deleted) return; */
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, implClassName, DELETED, "Z");
        Label notDeleted = new Label();
        mv.visitJumpInsn(IFEQ, notDeleted);
        mv.visitInsn(RETURN);
        mv.visitLabel(notDeleted);

        // deleted = true;
        mv.visitVarInsn(ALOAD, 0);
        mv.visitInsn(ICONST_1);
        mv.visitFieldInsn(PUTFIELD, implClassName, DELETED, "Z");

        for (CmrField cmrField : cmrFields) {
            // ${cmrField.accessor}.delete(${cmrField.name});
            createOpenEJB_deleted(mv, cmrField);
        }

        // return;
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    private void createOpenEJB_addCmr() {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "OpenEJB_addCmr", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;", null, null);
        mv.visitCode();

        // if (deleted) return null;
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, implClassName, DELETED, "Z");
        Label notDeleted = new Label();
        mv.visitJumpInsn(IFEQ, notDeleted);
        mv.visitInsn(ACONST_NULL);
        mv.visitInsn(ARETURN);
        mv.visitLabel(notDeleted);

        for (CmrField cmrField : cmrFields) {
            // if ("${cmrField.name}".equals(name)) {
            //     ${cmrField.name}.add((${cmrField.type})value);
            //     return null;
            // }
            //
            // OR
            //
            // if ("${cmrField.name}".equals(name)) {
            //     Object oldValue = ${cmrField.name};
            //     ${cmrField.name} = (${cmrField.type}) bean;
            //     return oldValue;
            // }
            createOpenEJB_addCmr(mv, cmrField);
        }

        // throw new IllegalArgumentException("Unknown cmr field " + name + " on entity bean of type " + getClass().getName());
        mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
        mv.visitInsn(DUP);
        mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V");
        mv.visitLdcInsn("Unknown cmr field ");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
        mv.visitLdcInsn(" on entity bean of type ");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V");
        mv.visitInsn(ATHROW);

        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    private void createOpenEJB_removeCmr() {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "OpenEJB_removeCmr", "(Ljava/lang/String;Ljava/lang/Object;)V", null, null);
        mv.visitCode();

        // if (deleted) return;
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, implClassName, DELETED, "Z");
        Label notDeleted = new Label();
        mv.visitJumpInsn(IFEQ, notDeleted);
        mv.visitInsn(RETURN);
        mv.visitLabel(notDeleted);

        for (CmrField cmrField : cmrFields) {
            // if ("${cmrField.name}".equals(name)) {
            //     ${cmrField.name}.remove(value);
            //     return;
            // }
            //
            // OR
            //
            // if ("${cmrField.name}".equals(name)) {
            //     ${cmrField.name} = null;
            //     return;
            // }
            createOpenEJB_removeCmr(mv, cmrField);
        }

        // throw new IllegalArgumentException("Unknown cmr field " + name + " on entity bean of type " + getClass().getName());
        mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
        mv.visitInsn(DUP);
        mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V");
        mv.visitLdcInsn("Unknown cmr field ");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
        mv.visitLdcInsn(" on entity bean of type ");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V");
        mv.visitInsn(ATHROW);

        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Add a CMP field to the class.  The field is created
     * with private scope.
     *
     * @param cmpField The Cmp field defined in the metadata.
     */
    private void createField(CmpField cmpField) {
        FieldVisitor fv = cw.visitField(ACC_PRIVATE,
                cmpField.getName(),
                cmpField.getDescriptor(),
                null,
                null);
        fv.visitEnd();
    }

   
    /**
     * Generate a concrete getter field for a CMP field. 
     * At this point, we're just generating a simple
     * accessor for the field, given the type.  The
     * JPA engine when it makes this implementation class
     * a managed class define whatever additional logic
     * might be required.
     *
     * @param cmpField The CMP field backing this getter method.
     */
    private void createGetter(CmpField cmpField) {
        String methodName = cmpField.getGetterMethod().getName();
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, "()" + cmpField.getDescriptor(), null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, implClassName, cmpField.getName(), cmpField.getDescriptor());
        mv.visitInsn(cmpField.getType().getOpcode(IRETURN));
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Generate the getter name for a CMR property.
     *
     * @param propertyName
     *               The name of the CMR property.
     *
     * @return The string name of the getter method for the
     *         property.
     */
    private static String getterName(String propertyName) {
        return "get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
    }

   
    /**
     * Get the getter method for this CMP field.  This
     * will be either get<Name> or is<Name> depending on
     * what abstract method is defined on the base bean
     * class.
     *
     * @param propertyName The name of the CMP field.
     *
     * @return The name to be used for generating this method.
     */
    private Method getterMethod(String propertyName) {
        String getterName = "get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
        try {
            // check to see if we have the getter as an abstract class.  This might be an "is" method.
            return beanClass.getMethod(getterName, new Class[0]);
        } catch (NoSuchMethodException e) {
        }
       
        // we're just going to assume this is the valid name.  Other validation should already have been
        // performed prior to this.
        getterName = "is" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
        try {
            // check to see if we have the getter as an abstract class.  This might be an "is" method.
            return beanClass.getMethod(getterName, new Class[0]);
        } catch (NoSuchMethodException e) {
        }
        return null;
    }

   
    /**
     * Generate a concrete setter field for a CMP field. 
     * At this point, we're just generating a simple
     * accessor for the field, given the type.  The
     * JPA engine when it makes this implementation class
     * a managed class define whatever additional logic
     * might be required.
     *
     * @param cmpField The CMP field backing this setter method.
     */
    private void createSetter(CmpField cmpField) {
        String methodName = setterName(cmpField.getName());
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, "(" + cmpField.getDescriptor() + ")V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(cmpField.getType().getOpcode(ILOAD), 1);
        mv.visitFieldInsn(PUTFIELD, implClassName, cmpField.getName(), cmpField.getDescriptor());
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    private String setterName(String propertyName) {
        return "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
    }

    /**
     * Create a simple internal method for obtaining the
     * primary key.  There are 2 possibilities for handling
     * the primary key here:
     *
     * 1)  There is a defined primary key field.  The
     * contents of that field are returned.
     *
     * 2)  The primary key is provided by the container. 
     * This is a long value stored in a private, generated
     * field.  This field is returned as a generated
     * wrappered Long.
     *
     * 3)  A primary key class has been provided.  An instance
     * of this class is instantiated, and code is generated
     * that will copy all of the CMP fields from the EJB
     * into the primary key instance.
     */
    private void createSimplePrimaryKeyGetter() {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "OpenEJB_getPrimaryKey", "()Ljava/lang/Object;", null, null);
        mv.visitCode();
       
        // the primary key is identifed as a field.  We just return that value directly.
        if (pkField != null) {
            // push the pk field
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, implClassName, pkField.getName(), pkField.getDescriptor());

            // return the pk field (from the stack)
            mv.visitInsn(pkField.getType().getOpcode(IRETURN));
        } else if (Object.class.equals(primKeyClass)) {
            // this is a container-generated primary key.  It's a long value stored in
            // a generated field.  We return that value, wrappered in a Long instance.
           
            // push the pk field
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, implClassName, UNKNOWN_PK_NAME, UNKNOWN_PK_TYPE.getDescriptor());

            // return the pk field (from the stack)
            mv.visitInsn(UNKNOWN_PK_TYPE.getOpcode(IRETURN));
        } else {
            // We have a primary key class defined.  For every field that matches one of the
            // defined CMP fields, we generate code to copy that value into the corresponding
            // field of the primary key class.
            String pkImplName = primKeyClass.getName().replace('.', '/');

            // new Pk();
            mv.visitTypeInsn(NEW, pkImplName);
            mv.visitInsn(DUP);
            mv.visitMethodInsn(INVOKESPECIAL, pkImplName, "<init>", "()V");
            mv.visitVarInsn(ASTORE, 1);
            mv.visitVarInsn(ALOAD, 1);

            // copy each field from the ejb to the pk class
            for (Field field : primKeyClass.getFields()) {
                CmpField cmpField = cmpFields.get(field.getName());

                // only process the cmp fields
                if (cmpField == null) {
                    continue;
                }

                // verify types match... this should have been caught by the verifier, but
                // check again since generated code is so hard to debug
                if (!cmpField.getType().getClassName().equals(field.getType().getName())) {
                    throw new IllegalArgumentException("Primary key " + cmpField.getName() + " is type " + cmpField.getType().getClassName() + " but CMP field is type " + field.getType().getName());
                }

                // push the value from the cmp bean
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, implClassName, cmpField.getName(), cmpField.getDescriptor());
                // set matching field in the pk class to the value on the stack
                mv.visitFieldInsn(PUTFIELD, pkImplName, cmpField.getName(), cmpField.getDescriptor());
                mv.visitVarInsn(ALOAD, 1);
            }

            // return the Pk();
            mv.visitInsn(ARETURN);
        }

        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Create the CMR fields defined for this object.  This
     * creates a pair of fields for each CMR field.  The
     * first field is the real field containing the object
     * data.  The second field will be an accessor object
     * that's instantiated when the fields are first
     * initialized.  The accessor field gets created with
     * the same name and "Cmr" concatenated to the end
     * of the field name.
     *
     * @param cmrField The CMR field descriptor.
     */
    private void createCmrFields(CmrField cmrField) {
        FieldVisitor fv = cw.visitField(ACC_PRIVATE,
                cmrField.getName(),
                cmrField.getDescriptor(),
                cmrField.getGenericSignature(),
                null);
        fv.visitEnd();

        fv = cw.visitField(ACC_PRIVATE + ACC_TRANSIENT,
                cmrField.getName() + "Cmr",
                cmrField.getAccessorDescriptor(),
                cmrField.getAccessorGenericSignature(),
                null);
        fv.visitEnd();
    }

    /**
     * Initialize the CMR fields associated with a CMR
     * definition.  This initializes two fields per CMR
     * defined field:  1)  The CMR field itself (which might
     * be initialized to an instance of a defined type) and 2)
     * the appropriate CMD accessor that handles the
     * different types of relationship.
     *
     * @param mv       The method context we're initializing in.
     * @param cmrField The CMR field to process.
     */
    private void initCmrFields(MethodVisitor mv, CmrField cmrField) {
        // this.${cmrField.name} = new ${cmrField.initialValueType}();
        Type initialValueType = cmrField.getInitialValueType();
        if (initialValueType != null) {
            mv.visitVarInsn(ALOAD, 0);
            mv.visitTypeInsn(NEW, initialValueType.getInternalName());
            mv.visitInsn(DUP);
            mv.visitMethodInsn(INVOKESPECIAL, initialValueType.getInternalName(), "<init>", "()V");
            mv.visitFieldInsn(PUTFIELD, implClassName, cmrField.getName(), cmrField.getDescriptor());
        }

        // this.${cmrField.name}Cmr = new ${cmrField.accessorType}<${cmrField.type}, ${cmrField.proxyType}>(this,
        //         ${cmrField.name},
        //         ${cmrField.type},
        //         ${cmrField.relatedName});
        mv.visitVarInsn(ALOAD, 0);
        mv.visitTypeInsn(NEW, cmrField.getAccessorInternalName());
        mv.visitInsn(DUP);

        // arg0: EntityBean source = this
        mv.visitVarInsn(ALOAD, 0);

        // arg1: String sourceProperty - "b"
        mv.visitLdcInsn(cmrField.getName());

        // arg2: Class<Bean> relatedType = BBean_BBean
        mv.visitLdcInsn(cmrField.getType());

        // arg3: String relatedProperty
        if (cmrField.getRelatedName() != null) {
            mv.visitLdcInsn(cmrField.getRelatedName());
        } else {
            mv.visitInsn(ACONST_NULL);
        }

        // invoke
        mv.visitMethodInsn(INVOKESPECIAL,
                cmrField.getAccessorInternalName(),
                "<init>",
                "(Ljavax/ejb/EntityBean;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;)V");

        // bCmr = result
        mv.visitFieldInsn(PUTFIELD,
                implClassName,
                cmrField.getName() + "Cmr",
                cmrField.getAccessorDescriptor());
    }

    /**
     * Create a getter method for the CMR field.  This
     * will used the accessor object initialized into the
     * name + "Cmr" field that was already generated and
     * initialized at object creation.  The accessor
     * object manages the object relationship.
     *
     * @param cmrField The field we're generating.
     */
    private void createCmrGetter(CmrField cmrField) {
        // a synthentic method essentially means this is a relationship with
        // no back reference.  We don't generate a getter method for this
        if (cmrField.isSynthetic()) {
            return;
        }

        String methodName = getterName(cmrField.getName());
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, "()" + cmrField.getProxyDescriptor(), null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName() + "Cmr", cmrField.getAccessorDescriptor());
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName(), cmrField.getDescriptor());
       
        // return this.${cmrField.name}Cmr.get(this.${cmdField.name}); 
        // this takes the value stored in the CMR field (which might be a single value or
        // a Set or Collection), and hands it to the appropriate accessor.
        mv.visitMethodInsn(INVOKEVIRTUAL, cmrField.getAccessorInternalName(), "get", cmrField.getCmrStyle().getGetterDescriptor());
        // if the style is a single value, then we're going to need to cast this
        // to the target class before returning. 
        if (cmrField.getCmrStyle() == CmrStyle.SINGLE) {
            mv.visitTypeInsn(CHECKCAST, cmrField.getProxyType().getInternalName());
        }
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

   
    /**
     * Generate a setter method for a CMR field.  The
     * setter method will delegate the setting responsibility
     * to the accessor object store the associated Cmr field.
     *
     * @param cmrField The field we're generating the setter for.
     */
    private void createCmrSetter(CmrField cmrField) {
        // a synthentic method essentially means this is a relationship with
        // no back reference.  We don't generate a getter method for this
        if (cmrField.isSynthetic()) {
            return;
        }

        String methodName = setterName(cmrField.getName());
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, "(" + cmrField.getProxyDescriptor() + ")V", null, null);
        mv.visitCode();
        // if this is a Many relationship, the CMR field contains a Set value.  The accessor
        // will process the elements in the Set, removing any existing ones, and then populating
        // the Set with the new values from the new value source.
        if (cmrField.getCmrStyle() != CmrStyle.SINGLE) {
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName() + "Cmr", cmrField.getAccessorDescriptor());
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName(), cmrField.getDescriptor());
            mv.visitVarInsn(ALOAD, 1);
            mv.visitMethodInsn(INVOKEVIRTUAL, cmrField.getAccessorInternalName(), "set", cmrField.getCmrStyle().getSetterDescriptor());
            mv.visitInsn(RETURN);
        } else {
            // this is a single value.  We pass the existing value and the old value to
            // the accessor, then must cast the accessor return value to the target type
            // so we can store it in the real CMR field.
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName() + "Cmr", cmrField.getAccessorDescriptor());
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName(), cmrField.getDescriptor());
            mv.visitVarInsn(ALOAD, 1);
            mv.visitMethodInsn(INVOKEVIRTUAL, cmrField.getAccessorInternalName(), "set", cmrField.getCmrStyle().getSetterDescriptor());
            mv.visitTypeInsn(CHECKCAST, cmrField.getType().getInternalName());
            mv.visitFieldInsn(PUTFIELD, implClassName, cmrField.getName(), cmrField.getDescriptor());
            mv.visitInsn(RETURN);
        }
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Generate the OpenEJB_deleted() logic for a
     * CMR field.  This handles the cascade from the referencing   
     * object to the CMR fields for the object.  This method generates the
     * CMR logic inline inside the object OpenEJB_deleted() method.
     *
     * @param mv       The method context we're operating within.
     * @param cmrField The CMD field containing the deleted value.
     */
    private void createOpenEJB_deleted(MethodVisitor mv, CmrField cmrField) {
        // this.${cmrField.name}Cmr.deleted(this.${cmrField.name});
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName() + "Cmr", cmrField.getAccessorDescriptor());
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName(), cmrField.getDescriptor());
        mv.visitMethodInsn(INVOKEVIRTUAL, cmrField.getAccessorInternalName(), "deleted", cmrField.getCmrStyle().getDeletedDescriptor());
    }

    /**
     * Generate the OpenEJB_addCmr logic for an individual
     * CMR field.  Each CMR field has a test against the
     * property name, which is passed to the wrappering
     * addCmr method.  This results in a series of
     * if blocks for each defined CMD property. 
     *
     * @param mv       The method we're generating within.
     * @param cmrField The CMR field definition.
     */
    private void createOpenEJB_addCmr(MethodVisitor mv, CmrField cmrField) {
        // if (${cmrField.name}.equals(arg1))
        mv.visitLdcInsn(cmrField.getName());
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
        // if not equal jump to end
        Label end = new Label();
        mv.visitJumpInsn(IFEQ, end);

        // collection style relationship.  Generate the code to add this object to the
        // collection already anchored in the CMR field. 
        if (cmrField.getCmrStyle() != CmrStyle.SINGLE) {
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName(), cmrField.getDescriptor());
            mv.visitVarInsn(ASTORE, 3);
            mv.visitVarInsn(ALOAD, 3);
            Label fieldNotNull = new Label();
            mv.visitJumpInsn(IFNONNULL, fieldNotNull);
            // lazy creation of the collection type if not already created.
            mv.visitTypeInsn(NEW, cmrField.getInitialValueType().getInternalName());
            mv.visitInsn(DUP);
            mv.visitMethodInsn(INVOKESPECIAL, cmrField.getInitialValueType().getInternalName(), "<init>", "()V");
            mv.visitVarInsn(ASTORE, 3);
            mv.visitLabel(fieldNotNull);

            // ${cmrField.name}.add(arg2)
            mv.visitVarInsn(ALOAD, 3);
            mv.visitVarInsn(ALOAD, 2);
            mv.visitMethodInsn(INVOKEINTERFACE,
                    cmrField.getCmrStyle().getCollectionType().getInternalName(),
                    "add",
                    "(Ljava/lang/Object;)Z");
            mv.visitInsn(POP);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 3);
            // unconditionally set the CMR field to the collection.  This is either the
            // original one on entry, or a new one for first access.
            mv.visitFieldInsn(PUTFIELD, implClassName, cmrField.getName(), cmrField.getDescriptor());

            // return null;
            mv.visitInsn(ACONST_NULL);
            mv.visitInsn(ARETURN);
        } else {
            // push: this.${cmrField.name};
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName(), cmrField.getDescriptor());

            // this.${cmrField.name} = (${cmrField.type}) bean;
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 2);
            mv.visitTypeInsn(CHECKCAST, cmrField.getType().getInternalName());
            mv.visitFieldInsn(PUTFIELD, implClassName, cmrField.getName(), cmrField.getDescriptor());

            // return pushed value above
            mv.visitInsn(ARETURN);
        }

        // end of if statement
        mv.visitLabel(end);
    }

//    private void createPrintln(MethodVisitor mv, String message) {
//        mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
//        mv.visitLdcInsn(message);
//        mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
//    }

//    private void createPrintField(MethodVisitor mv, String fieldName, String descriptor) {
//        mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
//        mv.visitLdcInsn(fieldName + "=");
//        mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V");
//
//        mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
//        mv.visitVarInsn(ALOAD, 0);
//        mv.visitFieldInsn(GETFIELD, implClassName, fieldName, descriptor);
//        mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V");
//    }

   
    /**
     * Emit the remove logic for an individual CMR field.
     * Like the addCmr logic, each field is guarded by an
     * if test on the property name. 
     *
     * @param mv
     * @param cmrField
     */
    private void createOpenEJB_removeCmr(MethodVisitor mv, CmrField cmrField) {
        // if (${cmrField.name}.equals(arg1))
        mv.visitLdcInsn(cmrField.getName());
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
        // if not equal jump to end
        Label end = new Label();
        mv.visitJumpInsn(IFEQ, end);
       
        // collection valued CMR field.  Remove the object from the collection.
        if (cmrField.getCmrStyle() != CmrStyle.SINGLE) {
            // ${cmrField.name}.remove(arg2)
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName(), cmrField.getDescriptor());
            mv.visitVarInsn(ALOAD, 2);
            mv.visitMethodInsn(INVOKEINTERFACE,
                    cmrField.getCmrStyle().getCollectionType().getInternalName(),
                    "remove",
                    "(Ljava/lang/Object;)Z");
            mv.visitInsn(POP);

            // return;
            mv.visitInsn(RETURN);
        } else {
            // single valued, so just null out the field.
           
            // this.${cmrField.name} = null;
            mv.visitVarInsn(ALOAD, 0);
            mv.visitInsn(ACONST_NULL);
            mv.visitFieldInsn(PUTFIELD, implClassName, cmrField.getName(), cmrField.getDescriptor());

            // return;
            mv.visitInsn(RETURN);
        }

        // end of if statement
        mv.visitLabel(end);
    }

    /**
     * Generate a concrete implementation of an abstract
     * ejbSelectxxxx method.
     *
     * @param selectMethod
     *               The abstract definition for the method we're generating.
     */
    private void createSelectMethod(Method selectMethod) {
        Class<?> returnType = selectMethod.getReturnType();
       
        Method executeMethod = EjbSelect.getSelectMethod(returnType);
       
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, selectMethod.getName(), Type.getMethodDescriptor(selectMethod), null, getExceptionTypes(selectMethod));
        mv.visitCode();

        // push deploymentInfo
        mv.visitFieldInsn(GETSTATIC, implClassName, "deploymentInfo", "Ljava/lang/Object;");

        // push method signature
        mv.visitLdcInsn(getSelectMethodSignature(selectMethod));

        // push return type, but only if the executeMethod is not going to be for void or
        // one of the primitives.
        if (!returnType.isPrimitive()) {
            mv.visitLdcInsn(returnType.getName());
        }

        // new Object[]
        mv.visitIntInsn(BIPUSH, selectMethod.getParameterTypes().length);
        mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");

        // object[i] = arg${i}
        int i = 0;
        for (Class<?> parameterType : selectMethod.getParameterTypes()) {
            // push arguement i on stack
            mv.visitInsn(DUP);
            bipush(mv, i);
            mv.visitVarInsn(Type.getType(parameterType).getOpcode(ILOAD), i + 1);

            // convert argument on stack to an Object
            Convert.toObjectFrom(mv, parameterType);

            // store it into the array
            mv.visitInsn(AASTORE);

            if (long.class.equals(parameterType) || double.class.equals(parameterType)) {
                // longs and doubles are double wide
                i = i + 2;
            } else {
                i++;
            }
        }

        // EjbSelect.execute_xxxx(deploymentInfo, signature, [returnType.] args[]);
        mv.visitMethodInsn(INVOKESTATIC,
                Type.getInternalName(executeMethod.getDeclaringClass()),
                executeMethod.getName(),
                Type.getMethodDescriptor(executeMethod));

        // if this is a void type, we just return.  Otherwise, the return type
        // needs to match the type returned from the method call
        if (!Void.TYPE.equals(returnType)) {
            // if this is a non-primitive return type, then the returned
            // object will need to be cast to the appropriate return type for
            // the verifier.  The primitive types all have the proper type on the
            // stack already
            if (!returnType.isPrimitive()) {
                // convert return type
                Convert.fromObjectTo(mv, returnType);
            }
           
            // And generate the appropriate return for the type
            mv.visitInsn(Type.getReturnType(selectMethod).getOpcode(IRETURN));
        } else {
            // void return is just a RETURN.
            mv.visitInsn(RETURN);
        }

        // close method
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    private String getSelectMethodSignature(Method selectMethod) {
        StringBuilder signature = new StringBuilder();
        signature.append(selectMethod.getName());
        if (selectMethod.getParameterTypes().length > 0) {
            signature.append('(');
            boolean first = true;
            for (Class<?> parameterType : selectMethod.getParameterTypes()) {
                if (!first) signature.append(',');
                signature.append(parameterType.getCanonicalName());
                first = false;
            }
            signature.append(')');
        }
        return signature.toString();
    }

    private static String[] getExceptionTypes(Method method) {
        List<String> types = new ArrayList<String>(method.getExceptionTypes().length);
        for (Class<?> exceptionType : method.getExceptionTypes()) {
            types.add(Type.getInternalName(exceptionType));
        }
        return types.toArray(new String[types.size()]);
    }

    private static void bipush(MethodVisitor mv, int i) {
        switch(i) {
            case -1:
                mv.visitInsn(ICONST_M1);
                break;
            case 0:
                mv.visitInsn(ICONST_0);
                break;
            case 1:
                mv.visitInsn(ICONST_1);
                break;
            case 2:
                mv.visitInsn(ICONST_2);
                break;
            case 3:
                mv.visitInsn(ICONST_3);
                break;
            case 4:
                mv.visitInsn(ICONST_4);
                break;
            case 5:
                mv.visitInsn(ICONST_5);
                break;
            default:
                mv.visitIntInsn(BIPUSH, i);
        }

    }
   
   
    /**
     * Helper class to handle common type conversions
     * in generated code.
     */
    private static class Convert {
        /**
         * Generate code to performing boxing of primitive types
         * into a wrapper class instance. 
         *
         * @param mv     The method currently being emitted.
         * @param from   The class we're converting from.
         */
        public static void toObjectFrom(MethodVisitor mv, Class from) {
            // we only handler boxing for the primitive types.
            if (from.isPrimitive()) {
                Convert conversion = getConversion(from);
                // the only conversion that will be trouble here is void. 
                if (conversion == null)
                {
                    throw new NullPointerException("conversion is null " + from.getName() + " " + from.isPrimitive());
                }
                conversion.primitiveToObject(mv);
            }
        }

        /**
         * Handle a conversion from one object type to another.  If
         * There are 3 possible conversions:
         *
         * 1)  The to class is Object.  This can be handled
         * without conversion.  This option is a NOP.
         * 2)  The to class is a reference type (non-primitive).  This conversion
         * is a cast operation (which might fail at run time).
         * 3)  The to class is a primitive type.  This is
         * an unboxing operation.
         *
         * @param mv     The method currently being constructed.
         * @param to     The target class for the conversion.
         */
        public static void fromObjectTo(MethodVisitor mv, Class to) {
            if (to.equals(Object.class)) {
                // direct assignment will work
            } else if (!to.isPrimitive()) {
                mv.visitTypeInsn(CHECKCAST, Type.getInternalName(to));
            } else {
                Convert conversion = getConversion(to);
                {
                    if (conversion == null)
                        throw new NullPointerException("unsupported conversion for EJB select return type " + to.getName());
                }
                conversion.objectToPrimitive(mv);
            }
        }

        private static Map<Class, Convert> conversionsByPrimitive = new HashMap<Class, Convert>();

        public static Convert getConversion(Class primitive) {
            if (!primitive.isPrimitive()) {
                throw new IllegalArgumentException(primitive.getName() + " is not a primitive class");
            }
            return conversionsByPrimitive.get(primitive);
        }

        public static final Convert BOOLEAN = new Convert(boolean.class, Boolean.class, "booleanValue");
        public static final Convert CHAR = new Convert(char.class, Character.class, "charValue");
        public static final Convert BYTE = new Convert(byte.class, Byte.class, "byteValue");
        public static final Convert SHORT = new Convert(short.class, Short.class, "shortValue");
        public static final Convert INT = new Convert(int.class, Integer.class, "intValue");
        public static final Convert LONG = new Convert(long.class, Long.class, "longValue");
        public static final Convert FLOAT = new Convert(float.class, Float.class, "floatValue");
        public static final Convert DOUBLE = new Convert(double.class, Double.class, "doubleValue");

        private Type objectType;
        private final Method toPrimitive;
        private final Method toObject;

        private Convert(Class primitiveClass, Class objectClass, String toPrimitiveMethodName) {
            objectType = Type.getType(objectClass);

            try {
                toObject = objectClass.getMethod("valueOf", primitiveClass);
                toPrimitive = objectClass.getMethod(toPrimitiveMethodName);
            } catch (NoSuchMethodException e) {
                throw new OpenEJBRuntimeException(e);
            }

            conversionsByPrimitive.put(primitiveClass, this);
        }

        public void primitiveToObject(MethodVisitor mv) {
            mv.visitMethodInsn(INVOKESTATIC, objectType.getInternalName(), toObject.getName(), Type.getMethodDescriptor(toObject));
        }

        public void objectToPrimitive(MethodVisitor mv) {
            mv.visitTypeInsn(CHECKCAST, objectType.getInternalName());
            mv.visitMethodInsn(INVOKEVIRTUAL, objectType.getInternalName(), toPrimitive.getName(), Type.getMethodDescriptor(toPrimitive));
        }

    }

    public void createEjbActivate() {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "ejbActivate", "()V", null, null);
        mv.visitCode();
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 1);
        mv.visitEnd();
    }

    public void createEjbLoad() {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "ejbLoad", "()V", null, null);
        mv.visitCode();
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 1);
        mv.visitEnd();
    }

    public void createEjbPassivate() {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "ejbPassivate", "()V", null, null);
        mv.visitCode();
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 1);
        mv.visitEnd();
    }

    public void createEjbRemove() {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "ejbRemove", "()V", null, null);
        mv.visitCode();
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 1);
        mv.visitEnd();
    }

    public void createEjbStore() {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "ejbStore", "()V", null, null);
        mv.visitCode();
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 1);
        mv.visitEnd();
    }

    public void createSetEntityContext() {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "setEntityContext", "(Ljavax/ejb/EntityContext;)V", null, null);
        mv.visitCode();
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 2);
        mv.visitEnd();
    }

    public void createUnsetEntityContext() {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "unsetEntityContext", "()V", null, null);
        mv.visitCode();
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 1);
        mv.visitEnd();
    }
}
TOP

Related Classes of org.apache.openejb.core.cmp.cmp2.Cmp2Generator

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.