Package org.jpox.enhancer.bcel

Source Code of org.jpox.enhancer.bcel.BCELImplementationGenerator

/**********************************************************************
Copyright (c) 2005 Erik Bengtson 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.bcel;

import java.util.ArrayList;
import java.util.List;

import javax.jdo.JDOException;

import org.apache.bcel.Constants;
import org.apache.bcel.Repository;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.FieldGen;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.Type;
import org.jpox.ClassLoaderResolver;
import org.jpox.JDOClassLoaderResolver;
import org.jpox.enhancer.AbstractImplementationGenerator;
import org.jpox.enhancer.ClassEnhancer;
import org.jpox.enhancer.EnhancerClassLoader;
import org.jpox.enhancer.bcel.metadata.BCELClassMetaData;
import org.jpox.metadata.AbstractClassMetaData;
import org.jpox.metadata.AbstractMemberMetaData;
import org.jpox.metadata.ClassMetaData;
import org.jpox.metadata.InterfaceMetaData;
import org.jpox.util.ClassUtils;

/**
* Implementation generator using BCEL bytecode manipulation library.
*
* @version $Revision: 1.17 $
*/
public class BCELImplementationGenerator extends AbstractImplementationGenerator implements Constants
{
    /** factory for JVM instructions **/
    private final InstructionFactory factory;

    /** constant class pool **/
    private final ConstantPoolGen constantPool;

    /** Class generator **/
    private final ClassGen classGen;

    /** generated java class **/
    private JavaClass javaClass;

    /**
     * Constructor for an implementation of a persistent interface.
     * @param interfaceMetaData MetaData for the interface
     * @param implClassName Name of the implementation class to generate (omitting packages)
     */
    public BCELImplementationGenerator(InterfaceMetaData interfaceMetaData, String implClassName)
    {
        super(interfaceMetaData, implClassName);

        List interfaces = new ArrayList();
        InterfaceMetaData imd = interfaceMetaData;
        do
        {
            interfaces.add(imd.getFullClassName());
            imd = (InterfaceMetaData) imd.getSuperAbstractClassMetaData();
        }
        while (imd != null);

        // Start the class
        this.classGen = new ClassGen(fullClassName, fullSuperclassName, className + ".java", ACC_PUBLIC | ACC_SUPER,
            (String[])interfaces.toArray(new String[interfaces.size()]));
        this.constantPool = classGen.getConstantPool();
        this.factory = new InstructionFactory(classGen, constantPool);

        // Create fields, default ctor, and methods
        createPropertyFields();
        createDefaultConstructor();
        createPropertyMethods();

        // End the class
        javaClass = classGen.getJavaClass();
        bytes = javaClass.getBytes();
    }

    /**
     * Constructor for an implementation of an abstract class.
     * @param classMetaData MetaData for the abstract class
     * @param implClassName Name of the implementation class to generate (omitting packages)
     */
    public BCELImplementationGenerator(ClassMetaData classMetaData, String implClassName)
    {
        super(classMetaData, implClassName);
        fullSuperclassName = classMetaData.getFullClassName();
        throw new JDOException(
            "JPOX doesnt currently support generating implementations of abstract classes with the BCEL generator");
    }

    /**
     * Enhance the implementation for use in the persistence process.
     * @param clr ClassLoaderResolver the loader of the interface/abstract class
     */
    public void enhance(ClassLoaderResolver clr)
    {
        // Make sure we have a JPOXRepository
        org.apache.bcel.util.Repository rep = Repository.getRepository();
        if (rep == null || !(rep instanceof JPOXRepository))
        {
            Repository.setRepository(new JPOXRepository(clr));
        }

        // define the generated class in the classloader so we populate the metadata
        EnhancerClassLoader loader = new EnhancerClassLoader();
        loader.defineClass(fullClassName, getBytes(), clr);

        // Create MetaData for the implementation
        ClassMetaData implementationCmd = new BCELClassMetaData((InterfaceMetaData)inputCmd, className, javaClass);
        ClassLoaderResolver genclr = new JDOClassLoaderResolver(loader);
        implementationCmd.populate(genclr, null);
        implementationCmd.initialise();

        //enhance the class
        ClassEnhancer gen = new BCELClassEnhancer(implementationCmd, genclr);
        gen.enhance();
        bytes = gen.getBytes();
    }

    /**
     * Create the fields.
     * @param acmd AbstractClassMetaData
     */
    protected void createPropertyFields(AbstractClassMetaData acmd)
    {
        if (acmd == null)
        {
            return;
        }
        FieldGen field;

        AbstractMemberMetaData[] propertyMetaData = acmd.getManagedMembers();
        for (int i=0; i<propertyMetaData.length; i++)
        {
            field = new FieldGen(ACC_PRIVATE,
                BCELUtils.getBCELTypeFromJavaType(propertyMetaData[i].getTypeName()),
                propertyMetaData[i].getName(), constantPool);
            classGen.addField(field.getField());
        }
    }

    /**
     * Create a default constructor, assuming that there is no persistent superclass.
     */
    protected void createDefaultConstructor()
    {
        InstructionList il = new InstructionList();
        MethodGen method = new MethodGen(ACC_PUBLIC, Type.VOID, Type.NO_ARGS, new String[]{}, "<init>",
            this.fullClassName, il, constantPool);

        il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
        il.append(factory.createInvoke(fullSuperclassName, "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
        il.append(InstructionFactory.createReturn(Type.VOID));
        method.setMaxStack();
        method.setMaxLocals();
        classGen.addMethod(method.getMethod());
        il.dispose();
    }

    /**
     * Create a getter method for a /property.
     * @param mmd MetaData for the property
     */
    protected void createGetter(AbstractMemberMetaData mmd)
    {
        boolean isBoolean = mmd.getTypeName().equals("boolean");
        String getterName = ClassUtils.getJavaBeanGetterName(mmd.getName(), isBoolean);
        String typeName = mmd.getTypeName();
        Type objectType = BCELUtils.getBCELTypeFromJavaType(typeName);
        InstructionList il = new InstructionList();
        MethodGen method = new MethodGen(ACC_PUBLIC, objectType, Type.NO_ARGS, new String[]{},
            getterName, this.fullClassName, il, constantPool);

        il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
        il.append(factory.createFieldAccess(this.fullClassName, mmd.getName(), objectType, Constants.GETFIELD));
        il.append(InstructionFactory.createReturn(objectType));
        method.setMaxStack();
        method.setMaxLocals();
        classGen.addMethod(method.getMethod());
        il.dispose();
    }

    /**
     * Create a setter method for a property.
     * @param mmd MetaData for the property
     */
    protected void createSetter(AbstractMemberMetaData mmd)
    {
        String setterName = ClassUtils.getJavaBeanSetterName(mmd.getName());
        String typeName = mmd.getTypeName();
        Type objectType = BCELUtils.getBCELTypeFromJavaType(typeName);
        InstructionList il = new InstructionList();
        MethodGen method = new MethodGen(ACC_PUBLIC, Type.VOID, new Type[]{objectType}, new String[]{"arg0"},
            setterName, this.fullClassName, il, constantPool);

        il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
        il.append(InstructionFactory.createLoad(objectType, 1));
        il.append(factory.createFieldAccess(this.fullClassName, mmd.getName(), objectType, Constants.PUTFIELD));
        il.append(InstructionFactory.createReturn(Type.VOID));
        method.setMaxStack();
        method.setMaxLocals();
        classGen.addMethod(method.getMethod());
        il.dispose();
    }
}
TOP

Related Classes of org.jpox.enhancer.bcel.BCELImplementationGenerator

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.