Package org.eclipse.persistence.sdo.helper

Source Code of org.eclipse.persistence.sdo.helper.DynamicClassWriter

/*******************************************************************************
* Copyright (c) 1998, 2009 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
*     Oracle - initial API and implementation from Oracle TopLink
*     bdoughan - Mar 18/2009 - 2.0 - Dynamically generated impl classes now
*                                    implement correct interface.
******************************************************************************/ 
package org.eclipse.persistence.sdo.helper;

import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

import org.eclipse.persistence.sdo.SDOConstants;
import org.eclipse.persistence.sdo.SDODataObject;
import org.eclipse.persistence.sdo.SDOProperty;
import org.eclipse.persistence.sdo.SDOType;
import org.eclipse.persistence.sdo.helper.extension.SDOUtil;
import org.eclipse.persistence.internal.libraries.asm.ClassWriter;
import org.eclipse.persistence.internal.libraries.asm.CodeVisitor;
import org.eclipse.persistence.internal.libraries.asm.Constants;
import org.eclipse.persistence.internal.libraries.asm.Type;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;

import commonj.sdo.helper.HelperContext;

/*
* Dynamically generate the implementation class for the SDO type.  If the type has an instance
* (interface) class then the dynamically generated impl class must fully implement it.  Additionally
* a constructor and a writeReplace() method are added.
*/
public class DynamicClassWriter {
    private static final String START_PROPERTY_INDEX = "START_PROPERTY_INDEX";
    private static final String END_PROPERTY_INDEX = "END_PROPERTY_INDEX";
    private static final String GET = "get";
    private static final String SET = "set";
    private static final String LIST = "List";
    private static final String WRITE_REPLACE = "writeReplace";

    private Class parentClass;
    private String typeImplClassDescriptor;
    private SDOType type;
    private Integer startPropertyIndex;

    // hold the context containing all helpers so that we can preserve inter-helper relationships
    private HelperContext aHelperContext;

    public DynamicClassWriter(String className, SDOType type, HelperContext aContext) {
        this.aHelperContext = aContext;
        this.parentClass = SDODataObject.class;
        this.typeImplClassDescriptor = className.replace('.', '/');
        this.type = type;
        initializeParentClass();

        if(type.isSubType()) {
            try {
                Field parentEndPropertyIndexField = PrivilegedAccessHelper.getField(parentClass, END_PROPERTY_INDEX, true);
                Integer parentEndPropertyIndex = (Integer) PrivilegedAccessHelper.getValueFromField(parentEndPropertyIndexField, parentClass);
                startPropertyIndex = parentEndPropertyIndex + 1;
            } catch(NoSuchFieldException e) {
                startPropertyIndex = new Integer(0);
            } catch(IllegalAccessException e) {
                startPropertyIndex = new Integer(0);
            }
        } else {
            startPropertyIndex = new Integer(0);
        }
    }

    private void initializeParentClass() {
        if (type.isSubType()) {
            SDOType parentSDOType = (SDOType)type.getBaseTypes().get(0);
            String parentClassName = parentSDOType.getInstanceClassName() + SDOConstants.SDO_IMPL_NAME;
            try {
                parentClass = ((SDOXMLHelper)aHelperContext.getXMLHelper()).getLoader().loadClass(parentClassName, parentSDOType);
            } catch (Exception e) {
                parentClass = null;
            }
            if (parentClass == null) {
                parentClass = SDODataObject.class;
            }
        } else {
            parentClass = SDODataObject.class;
        }
    }

    public Class getParentClass() {
        return this.parentClass;
    }

    /**
     * This is where the byte codes for the generic subclass are defined and the
     * class is created dynamically from them.
     */
    public byte[] createClass() {
        ClassWriter cw = new ClassWriter(false);

        if(null == type.getInstanceClass()) {
            cw.visit(Constants.V1_5, Constants.ACC_PUBLIC + Constants.ACC_SUPER, typeImplClassDescriptor, Type.getType(parentClass).getInternalName(), null, null);
        } else {
            String[] interfaces = new String[1];
            interfaces[0] = type.getInstanceClassName().replace('.', '/');
            cw.visit(Constants.V1_5, Constants.ACC_PUBLIC + Constants.ACC_SUPER, typeImplClassDescriptor, Type.getType(parentClass).getInternalName(), interfaces, null);
            addPropertyIndices(cw);
            for(Object object: type.getDeclaredProperties()) {
                SDOProperty sdoProperty = (SDOProperty) object;
                addPropertyGetMethod(cw, sdoProperty);
                addPropertySetMethod(cw, sdoProperty);
            }
        }

        addConstructors(cw);
        addWriteReplace(cw);
        cw.visitEnd();

        return cw.toByteArray();
    }

    private void addPropertyIndices(ClassWriter cw) {
        cw.visitField(Constants.ACC_PUBLIC + Constants.ACC_FINAL + Constants.ACC_STATIC, START_PROPERTY_INDEX, "I", startPropertyIndex, null);
        int declaredPropsSize = type.getDeclaredProperties().size();

        Integer endPropertyIndex;
        if(declaredPropsSize > 0) {
            endPropertyIndex = startPropertyIndex + declaredPropsSize - 2;
        } else {
            endPropertyIndex = startPropertyIndex - 1;
        }
        cw.visitField(Constants.ACC_PUBLIC + Constants.ACC_FINAL + Constants.ACC_STATIC, END_PROPERTY_INDEX, "I", endPropertyIndex, null);
    }

    private void addConstructors(ClassWriter cw) {
        CodeVisitor mv = cw.visitMethod(Constants.ACC_PUBLIC, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[0]), new String[] { Type.getInternalName(Serializable.class) }, null);
        mv.visitVarInsn(Constants.ALOAD, 0);
        mv.visitMethodInsn(Constants.INVOKESPECIAL, Type.getType(parentClass).getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[0]));
        mv.visitInsn(Constants.RETURN);
        mv.visitMaxs(1, 1);
    }

    private void addPropertyGetMethod(ClassWriter cw, SDOProperty property) {
        String returnType = SDOUtil.getJavaTypeForProperty(property);
        String outerGetMethodName = SDOUtil.getMethodName(property.getName(), returnType);
       
        if(property.getType() == SDOConstants.SDO_BOOLEAN || property.getType() == SDOConstants.SDO_BOOLEANOBJECT){
          String booleanGetterName = SDOUtil.getBooleanGetMethodName(property.getName(), returnType);
          addPropertyGetMethodInternal(cw, property, booleanGetterName, returnType)
        }       
        addPropertyGetMethodInternal(cw, property, outerGetMethodName, returnType);       
    }
   
    private void addPropertyGetMethodInternal(ClassWriter cw, SDOProperty property, String outerGetMethodName, String returnType){
      CodeVisitor mv;
        String propertyInstanceClassDescriptor;
        if(property.isMany()) {
            propertyInstanceClassDescriptor = Type.getDescriptor(List.class);
        } else if(property.getType().isDataType()) {
            propertyInstanceClassDescriptor = Type.getDescriptor(property.getType().getInstanceClass());
        } else {
            propertyInstanceClassDescriptor = "L" + returnType.replace('.', '/') + ";";
        }
        mv = cw.visitMethod(Constants.ACC_PUBLIC, outerGetMethodName, "()" + propertyInstanceClassDescriptor, null, null);

        mv.visitVarInsn(Constants.ALOAD, 0);
        mv.visitIntInsn(Constants.BIPUSH, startPropertyIndex + property.getIndexInType());

        String builtIn = SDOUtil.getBuiltInType(returnType);
        if(null != builtIn) {
            if(property.getType().isDataType() && !builtIn.equals(LIST)) {
                mv.visitMethodInsn(Constants.INVOKEVIRTUAL, typeImplClassDescriptor, GET + builtIn, "(I)" + propertyInstanceClassDescriptor);
                int iReturnOpcode = Type.getType(property.getType().getInstanceClass()).getOpcode(Constants.IRETURN);
                mv.visitInsn(iReturnOpcode);
            } else {
                mv.visitMethodInsn(Constants.INVOKEVIRTUAL,  typeImplClassDescriptor, GET, "(I)Ljava/lang/Object;");                       
                mv.visitInsn(Constants.ARETURN);
            }
        } else {
            mv.visitMethodInsn(Constants.INVOKEVIRTUAL,  typeImplClassDescriptor, GET, "(I)Ljava/lang/Object;");                       
            mv.visitInsn(Constants.ARETURN);
        }
        mv.visitMaxs(2, 1);
    }

    private void addPropertySetMethod(ClassWriter cw, SDOProperty property) {
        String returnType = SDOUtil.getJavaTypeForProperty(property);
        String outerSetMethodName = SDOUtil.setMethodName(property.getName());

        CodeVisitor mv;
        String propertyInstanceClassDescriptor;

        if(property.isMany()) {
            propertyInstanceClassDescriptor = Type.getDescriptor(List.class);
        } else if(property.getType().isDataType()) {
            propertyInstanceClassDescriptor = Type.getDescriptor(property.getType().getInstanceClass());
        } else {
            propertyInstanceClassDescriptor = "L" + returnType.replace('.', '/') + ";";
        }
        mv = cw.visitMethod(Constants.ACC_PUBLIC, outerSetMethodName, "(" + propertyInstanceClassDescriptor + ")V", null, null);

        mv.visitVarInsn(Constants.ALOAD, 0);
        mv.visitIntInsn(Constants.BIPUSH, startPropertyIndex + property.getIndexInType());

        String builtIn = SDOUtil.getBuiltInType(returnType);
        int iLoadOpcode = Constants.ALOAD;
        if(null != builtIn) {
            if(property.getType().isDataType() && !builtIn.equals(LIST)) {
                iLoadOpcode = Type.getType(property.getType().getInstanceClass()).getOpcode(Constants.ILOAD);
                mv.visitVarInsn(iLoadOpcode, 1);
                mv.visitMethodInsn(Constants.INVOKEVIRTUAL, typeImplClassDescriptor, SET + builtIn, "(I" + propertyInstanceClassDescriptor + ")V");
            } else {
                mv.visitVarInsn(iLoadOpcode, 1);
                mv.visitMethodInsn(Constants.INVOKEVIRTUAL,  typeImplClassDescriptor, SET, "(ILjava/lang/Object;)V");                       
            }
        } else {
            mv.visitVarInsn(iLoadOpcode, 1);
            mv.visitMethodInsn(Constants.INVOKEVIRTUAL,  typeImplClassDescriptor, SET, "(ILjava/lang/Object;)V");                       
        }

        mv.visitInsn(Constants.RETURN);
        if(iLoadOpcode == Constants.DLOAD || iLoadOpcode == Constants.LLOAD) {
            mv.visitMaxs(4, 3);
        } else {
            mv.visitMaxs(3, 2);
        }
    }

    private void addWriteReplace(ClassWriter cw) {
        Method method;
        try {
            method = parentClass.getDeclaredMethod(WRITE_REPLACE, new Class[0]);
        } catch (NoSuchMethodException e) {
            return;
        }

        CodeVisitor mv = cw.visitMethod(Constants.ACC_PROTECTED, method.getName(), Type.getMethodDescriptor(method), new String[] { Type.getInternalName(ObjectStreamException.class) }, null);

        mv.visitVarInsn(Constants.ALOAD, 0);
        mv.visitMethodInsn(Constants.INVOKESPECIAL, Type.getInternalName(parentClass), method.getName(), Type.getMethodDescriptor(method));
        mv.visitInsn(Constants.ARETURN);
        mv.visitMaxs(1, 1);
    }

}
TOP

Related Classes of org.eclipse.persistence.sdo.helper.DynamicClassWriter

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.