Package org.datanucleus.enhancer.asm

Source Code of org.datanucleus.enhancer.asm.ASMClassEnhancer

/**********************************************************************
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.datanucleus.enhancer.asm;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.jdo.JDODetachedFieldAccessException;
import javax.jdo.JDOFatalInternalException;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.identity.ByteIdentity;
import javax.jdo.identity.CharIdentity;
import javax.jdo.identity.IntIdentity;
import javax.jdo.identity.LongIdentity;
import javax.jdo.identity.ObjectIdentity;
import javax.jdo.identity.ShortIdentity;
import javax.jdo.identity.StringIdentity;
import javax.jdo.spi.Detachable;
import javax.jdo.spi.JDOImplHelper;
import javax.jdo.spi.PersistenceCapable;
import javax.jdo.spi.StateManager;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.enhancer.AbstractClassEnhancer;
import org.datanucleus.enhancer.ClassField;
import org.datanucleus.enhancer.DataNucleusEnhancer;
import org.datanucleus.enhancer.asm.method.InitFieldFlags;
import org.datanucleus.enhancer.asm.method.InitFieldNames;
import org.datanucleus.enhancer.asm.method.InitFieldTypes;
import org.datanucleus.enhancer.asm.method.InitPersistenceCapableSuperclass;
import org.datanucleus.enhancer.asm.method.JdoCopyField;
import org.datanucleus.enhancer.asm.method.JdoCopyFields;
import org.datanucleus.enhancer.asm.method.JdoCopyKeyFieldsFromObjectId;
import org.datanucleus.enhancer.asm.method.JdoCopyKeyFieldsFromObjectId2;
import org.datanucleus.enhancer.asm.method.JdoCopyKeyFieldsToObjectId;
import org.datanucleus.enhancer.asm.method.JdoCopyKeyFieldsToObjectId2;
import org.datanucleus.enhancer.asm.method.JdoGetInheritedFieldCount;
import org.datanucleus.enhancer.asm.method.JdoGetManagedFieldCount;
import org.datanucleus.enhancer.asm.method.JdoGetObjectId;
import org.datanucleus.enhancer.asm.method.JdoGetPersistenceManager;
import org.datanucleus.enhancer.asm.method.JdoGetTransactionalObjectId;
import org.datanucleus.enhancer.asm.method.JdoGetVersion;
import org.datanucleus.enhancer.asm.method.JdoIsDeleted;
import org.datanucleus.enhancer.asm.method.JdoIsDetached;
import org.datanucleus.enhancer.asm.method.JdoIsDirty;
import org.datanucleus.enhancer.asm.method.JdoIsNew;
import org.datanucleus.enhancer.asm.method.JdoIsPersistent;
import org.datanucleus.enhancer.asm.method.JdoIsTransactional;
import org.datanucleus.enhancer.asm.method.JdoMakeDirty;
import org.datanucleus.enhancer.asm.method.JdoNewInstance1;
import org.datanucleus.enhancer.asm.method.JdoNewInstance2;
import org.datanucleus.enhancer.asm.method.JdoNewObjectIdInstance1;
import org.datanucleus.enhancer.asm.method.JdoNewObjectIdInstance2;
import org.datanucleus.enhancer.asm.method.JdoPreSerialize;
import org.datanucleus.enhancer.asm.method.JdoProvideField;
import org.datanucleus.enhancer.asm.method.JdoProvideFields;
import org.datanucleus.enhancer.asm.method.JdoReplaceDetachedState;
import org.datanucleus.enhancer.asm.method.JdoReplaceField;
import org.datanucleus.enhancer.asm.method.JdoReplaceFields;
import org.datanucleus.enhancer.asm.method.JdoReplaceFlags;
import org.datanucleus.enhancer.asm.method.JdoReplaceStateManager;
import org.datanucleus.enhancer.asm.method.JdoSuperClone;
import org.datanucleus.enhancer.asm.method.LoadClass;
import org.datanucleus.enhancer.asm.primarykey.PrimaryKeyGenerator;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.ClassMetaData;
import org.datanucleus.metadata.ClassPersistenceModifier;
import org.datanucleus.metadata.IdentityType;
import org.datanucleus.metadata.InvalidMetaDataException;
import org.datanucleus.metadata.MetaDataManager;
import org.datanucleus.util.Localiser;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

/**
* Class enhancer using ASM (http://asm.objectweb.org).
* Assumes that the version of ASM is 3.0 or above.
* ASM operates using a SAXParser-like "visitor-pattern". We utilise this as follows :-
* <ul>
* <li><b>enhance</b> : start with a ClassReader for the class to be enhanced, and create a JdoClassAdapter
* (attached to a ClassWriter) that will perform the modifications, and use that as a visitor for the reader
* so that the reader sends its events to the adapter. Within the JdoClassAdapter we also make use of a
* JdoMethodAdapter to update individual methods</li>
* <li><b>check</b> : take a ClassReader, and create a JdoClassChecker that performs the checks. We then set
* the checker as a visitor for the reader so that the reader sends its events to the checker.</li>
* </ul>
*/
public class ASMClassEnhancer extends AbstractClassEnhancer
{
    protected static final Localiser LOCALISER_CORE = Localiser.getInstance("org.datanucleus.Localisation",
        org.datanucleus.ClassConstants.NUCLEUS_CONTEXT_LOADER);

    public static final String FN_StateManager = "jdoStateManager";
    public static final String FN_Flag = "jdoFlags";
    public static final String FN_FieldNames = "jdoFieldNames";
    public static final String FN_FieldTypes = "jdoFieldTypes";
    public static final String FN_FieldFlags = "jdoFieldFlags";
    public static final String FN_PersistableSuperclass = "jdoPersistenceCapableSuperclass";
    public static final String FN_InheritedFieldCount = "jdoInheritedFieldCount";
    public static final String FN_DetachedState = "jdoDetachedState";
    public static final String FN_SerialVersionUID = "serialVersionUID";

    public static final String MN_GetterPrefix = "jdoGet";
    public static final String MN_SetterPrefix = "jdoSet";
    public static final String MN_FieldNamesInitMethod = "__jdoFieldNamesInit";
    public static final String MN_FieldTypesInitMethod = "__jdoFieldTypesInit";
    public static final String MN_FieldFlagsInitMethod = "__jdoFieldFlagsInit";
    public static final String MN_GetObjectId = "jdoGetObjectId";
    public static final String MN_GetTransactionalObjectId = "jdoGetTransactionalObjectId";
    public static final String MN_GetVersion = "jdoGetVersion";
    public static final String MN_IsDetached = "jdoIsDetached";
    public static final String MN_IsDetachedInternal = "jdoIsDetachedInternal";
    public static final String MN_IsDeleted = "jdoIsDeleted";
    public static final String MN_IsDirty = "jdoIsDirty";
    public static final String MN_IsNew = "jdoIsNew";
    public static final String MN_IsPersistent = "jdoIsPersistent";
    public static final String MN_IsTransactional = "jdoIsTransactional";
    public static final String MN_GetPersistenceManager = "jdoGetPersistenceManager";
    public static final String MN_PreSerialize = "jdoPreSerialize";
    public static final String MN_GetInheritedFieldCount = "__jdoGetInheritedFieldCount";
    public static final String MN_SuperClone = "jdoSuperClone";
    public static final String MN_GetManagedFieldCount = "jdoGetManagedFieldCount";
    public static final String MN_PersistableSuperclassInit = "__jdoPersistenceCapableSuperclassInit";
    public static final String MN_LoadClass = "___jdo$loadClass";
    public static final String MN_CopyField = "jdoCopyField";
    public static final String MN_CopyFields = "jdoCopyFields";
    public static final String MN_CopyKeyFieldsFromObjectId = "jdoCopyKeyFieldsFromObjectId";
    public static final String MN_CopyKeyFieldsToObjectId = "jdoCopyKeyFieldsToObjectId";
    public static final String MN_ProvideField = "jdoProvideField";
    public static final String MN_ProvideFields = "jdoProvideFields";
    public static final String MN_ReplaceField = "jdoReplaceField";
    public static final String MN_ReplaceFields = "jdoReplaceFields";
    public static final String MN_ReplaceFlags = "jdoReplaceFlags";
    public static final String MN_ReplaceStateManager = "jdoReplaceStateManager";
    public static final String MN_ReplaceDetachedState = "jdoReplaceDetachedState";
    public static final String MN_MakeDirty = "jdoMakeDirty";
    public static final String MN_MakeDirtyDetached = "jdoMakeDirtyDetached";
    public static final String MN_NewInstance = "jdoNewInstance";
    public static final String MN_NewObjectIdInstance = "jdoNewObjectIdInstance";

    public static final Class CL_Detachable = Detachable.class;
    public static final Class CL_Persistable = PersistenceCapable.class;
    public static final Class CL_ObjectIdFieldConsumer = PersistenceCapable.ObjectIdFieldConsumer.class;
    public static final Class CL_ObjectIdFieldSupplier = PersistenceCapable.ObjectIdFieldSupplier.class;
    public static final Class CL_PersistenceManager = PersistenceManager.class;
    public static final Class CL_StateManager = StateManager.class;

    public static final String CN_JDOHelper = JDOHelper.class.getName();
    public static final String CN_JDOImplHelper = JDOImplHelper.class.getName();
    public static final String CN_JDOFatalInternalException = JDOFatalInternalException.class.getName();
    public static final String CN_DetachedFieldAccessException = JDODetachedFieldAccessException.class.getName();

    public final static String ACN_StateManager = CL_StateManager.getName().replace('.', '/');
    public final static String ACN_PersistenceManager = CL_PersistenceManager.getName().replace('.', '/');
    public final static String ACN_Persistable = CL_Persistable.getName().replace('.', '/');
    public final static String ACN_Detachable = CL_Detachable.getName().replace('.', '/');
    public final static String ACN_ObjectIdFieldConsumer = CL_ObjectIdFieldConsumer.getName().replace('.', '/');
    public final static String ACN_ObjectIdFieldSupplier = CL_ObjectIdFieldSupplier.getName().replace('.', '/');
    public final static String ACN_DetachedFieldAccessException = JDODetachedFieldAccessException.class.getName().replace('.', '/');
    public final static String ACN_FatalInternalException = JDOFatalInternalException.class.getName().replace('.', '/');
    public final static String ACN_Helper = JDOHelper.class.getName().replace('.', '/');
    public final static String ACN_ImplHelper = JDOImplHelper.class.getName().replace('.', '/');

    public final static String CD_ByteIdentity = Type.getDescriptor(ByteIdentity.class);
    public final static String CD_CharIdentity = Type.getDescriptor(CharIdentity.class);
    public final static String CD_IntIdentity = Type.getDescriptor(IntIdentity.class);
    public final static String CD_LongIdentity = Type.getDescriptor(LongIdentity.class);
    public final static String CD_ShortIdentity = Type.getDescriptor(ShortIdentity.class);
    public final static String CD_StringIdentity = Type.getDescriptor(StringIdentity.class);
    public final static String CD_ObjectIdentity = Type.getDescriptor(ObjectIdentity.class);
    public final static String CD_StateManager = Type.getDescriptor(StateManager.class);
    public final static String CD_PersistenceManager = Type.getDescriptor(PersistenceManager.class);
    public final static String CD_PersistenceCapable = Type.getDescriptor(PersistenceCapable.class);
    public final static String CD_Detachable = Type.getDescriptor(CL_Detachable);
    public final static String CD_ObjectIdFieldConsumer = Type.getDescriptor(PersistenceCapable.ObjectIdFieldConsumer.class);
    public final static String CD_ObjectIdFieldSupplier = Type.getDescriptor(PersistenceCapable.ObjectIdFieldSupplier.class);
    public final static String CD_String = Type.getDescriptor(String.class);
    public final static String CD_Object = Type.getDescriptor(Object.class);

    /** Resource name of the input class (only when the class exists in a class file). */
    protected String inputResourceName;

    /** Bytes of the input class (only when enhancing generated classes with no class file). */
    protected byte[] inputBytes;

    /** Class that is being enhanced. */
    protected final Class cls;

    /** Bytes of the class (after enhancing). */
    protected byte[] classBytes = null;

    /** Bytes for any auto-generated PK class (if generated during enhancement). */
    protected byte[] pkClassBytes = null;

    /** ASM Class name for this class (replace . with /). */
    protected String asmClassName = null;

    /** Class descriptor for this class. */
    protected String classDescriptor = null;

    /**
     * Constructor for an enhancer for the class. The class is assumed to be in the CLASSPATH.
     * @param cmd MetaData for the class to be enhanced
     * @param clr ClassLoader resolver
     * @param mmgr MetaData manager
     */
    public ASMClassEnhancer(ClassMetaData cmd, ClassLoaderResolver clr, MetaDataManager mmgr)
    {
        super(cmd, clr, mmgr);

        cls = clr.classForName(cmd.getFullClassName());
        asmClassName = cmd.getFullClassName().replace('.', '/');
        classDescriptor = Type.getDescriptor(cls);
        inputResourceName = "/" + className.replace('.','/') + ".class";
    }

    /**
     * Constructor for an enhancer to enhance a class defined by the provided bytes.
     * @param cmd MetaData for the class to be enhanced
     * @param clr ClassLoader resolver
     * @param mmgr MetaData manager
     * @param classBytes Bytes of the class to enhance
     */
    public ASMClassEnhancer(ClassMetaData cmd, ClassLoaderResolver clr, MetaDataManager mmgr, byte[] classBytes)
    {
        super(cmd, clr, mmgr);

        cls = clr.classForName(cmd.getFullClassName());
        asmClassName = cmd.getFullClassName().replace('.', '/');
        classDescriptor = Type.getDescriptor(cls);
        inputBytes = classBytes;
    }

    /**
     * Convenience accessor for the class name that is stored in a particular class.
     * @param filename Name of the file
     * @return The class name
     */
    public static String getClassNameForFileName(String filename)
    {
        MyClassVisitor vis = new MyClassVisitor();
        try
        {
            new ClassReader(new FileInputStream(filename)).accept(vis, 0);
            return vis.getClassName();
        }
        catch (IOException ioe)
        {
            return null;
        }
    }

    /** Convenience class to look up the class name for a file. */
    public static class MyClassVisitor implements ClassVisitor
    {
        String className = null;
        public String getClassName()
        {
            return className;
        }

        public void visitInnerClass(String name, String outerName, String innerName, int access) { }
        public void visit(int version, int access, String name, String sig, String supername, String[] intfs)
        {
            className = name.replace('/', '.');
        }

        public AnnotationVisitor visitAnnotation(String desc, boolean visible)
        {
            return null;
        }
        public FieldVisitor visitField(int access, String name, String desc, String signature, Object value)
        {
            return null;
        }
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] excpts)
        {
            return null;
        }
        public void visitAttribute(Attribute attr) { }
        public void visitOuterClass(String owner, String name, String desc) { }
        public void visitSource(String source, String debug) { }
        public void visitEnd() { }
    }

    /**
     * Accessor for the class being enhanced.
     * @return Class being enhanced
     */
    public Class getClassEnhanced()
    {
        return cls;
    }

    /**
     * Accessor for the ASM class name
     * @return ASM class name
     */
    public String getASMClassName()
    {
        return asmClassName;
    }

    /**
     * Accessor for the class descriptor for the class being enhanced
     * @return class descriptor
     */
    public String getClassDescriptor()
    {
        return classDescriptor;
    }

    /**
     * Method to initialise the list of methods to add.
     */
    protected void initialiseMethodsList()
    {
        if (cmd.getPersistenceCapableSuperclass() == null)
        {
            // Root persistent class methods
            methodsToAdd.add(JdoCopyKeyFieldsFromObjectId.getInstance(this));
            methodsToAdd.add(JdoCopyKeyFieldsFromObjectId2.getInstance(this));
            methodsToAdd.add(JdoCopyKeyFieldsToObjectId.getInstance(this));
            methodsToAdd.add(JdoCopyKeyFieldsToObjectId2.getInstance(this));
            methodsToAdd.add(JdoGetObjectId.getInstance(this));
            methodsToAdd.add(JdoGetVersion.getInstance(this));
            methodsToAdd.add(JdoPreSerialize.getInstance(this));
            methodsToAdd.add(JdoGetPersistenceManager.getInstance(this));
            methodsToAdd.add(JdoGetTransactionalObjectId.getInstance(this));
            methodsToAdd.add(JdoIsDeleted.getInstance(this));
            methodsToAdd.add(JdoIsDirty.getInstance(this));
            methodsToAdd.add(JdoIsNew.getInstance(this));
            methodsToAdd.add(JdoIsPersistent.getInstance(this));
            methodsToAdd.add(JdoIsTransactional.getInstance(this));
            methodsToAdd.add(JdoMakeDirty.getInstance(this));
            methodsToAdd.add(JdoNewObjectIdInstance1.getInstance(this));
            methodsToAdd.add(JdoNewObjectIdInstance2.getInstance(this));
            methodsToAdd.add(JdoProvideFields.getInstance(this));
            methodsToAdd.add(JdoReplaceFields.getInstance(this));
            methodsToAdd.add(JdoReplaceFlags.getInstance(this));
            methodsToAdd.add(JdoReplaceStateManager.getInstance(this));
        }
        if (cmd.getPersistenceCapableSuperclass() != null && cmd.isRootInstantiableClass())
        {
            // This class is not the root in the inheritance tree, but is the root in terms of being instantiable
            // hence it owns the "identity", so we need real implementations of the identity enhancement methods
            methodsToAdd.add(JdoCopyKeyFieldsFromObjectId.getInstance(this));
            methodsToAdd.add(JdoCopyKeyFieldsFromObjectId2.getInstance(this));
            methodsToAdd.add(JdoCopyKeyFieldsToObjectId.getInstance(this));
            methodsToAdd.add(JdoCopyKeyFieldsToObjectId2.getInstance(this));
            methodsToAdd.add(JdoNewObjectIdInstance1.getInstance(this));
            methodsToAdd.add(JdoNewObjectIdInstance2.getInstance(this));
        }

        if (requiresDetachable())
        {
            methodsToAdd.add(JdoReplaceDetachedState.getInstance(this));
        }
        if (cmd.isDetachable() && cmd.getPersistenceCapableSuperclass() != null)
        {
            methodsToAdd.add(JdoMakeDirty.getInstance(this));
        }

        methodsToAdd.add(JdoIsDetached.getInstance(this));
        methodsToAdd.add(JdoNewInstance1.getInstance(this));
        methodsToAdd.add(JdoNewInstance2.getInstance(this));
        methodsToAdd.add(JdoReplaceField.getInstance(this));
        methodsToAdd.add(JdoProvideField.getInstance(this));
        methodsToAdd.add(JdoCopyField.getInstance(this));
        methodsToAdd.add(JdoCopyFields.getInstance(this));
        methodsToAdd.add(InitFieldNames.getInstance(this));
        methodsToAdd.add(InitFieldTypes.getInstance(this));
        methodsToAdd.add(InitFieldFlags.getInstance(this));
        methodsToAdd.add(JdoGetInheritedFieldCount.getInstance(this));
        methodsToAdd.add(JdoGetManagedFieldCount.getInstance(this));
        methodsToAdd.add(InitPersistenceCapableSuperclass.getInstance(this));
        methodsToAdd.add(LoadClass.getInstance(this));
        methodsToAdd.add(JdoSuperClone.getInstance(this));
    }

    /**
     * Method to initialise the list of fields to add.
     */
    protected void initialiseFieldsList()
    {
        if (cmd.getPersistenceCapableSuperclass() == null)
        {
            // Root persistent class fields
            fieldsToAdd.add(new ClassField(this, getStateManagerFieldName(),
                Opcodes.ACC_PROTECTED | Opcodes.ACC_TRANSIENT, CL_StateManager));
            fieldsToAdd.add(new ClassField(this, getFlagsFieldName(),
                Opcodes.ACC_PROTECTED | Opcodes.ACC_TRANSIENT, byte.class));
        }

        if (requiresDetachable())
        {
            // Detachable fields
            fieldsToAdd.add(new ClassField(this, getDetachedStateFieldName(),
                Opcodes.ACC_PROTECTED, Object[].class));
        }

        fieldsToAdd.add(new ClassField(this, getFieldFlagsFieldName(),
            Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, byte[].class));
        fieldsToAdd.add(new ClassField(this, getPersistableSuperclassFieldName(),
            Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, Class.class));
        fieldsToAdd.add(new ClassField(this, getFieldTypesFieldName(),
            Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, Class[].class));
        fieldsToAdd.add(new ClassField(this, getFieldNamesFieldName(),
            Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, String[].class));
        fieldsToAdd.add(new ClassField(this, getInheritedFieldCountFieldName(),
            Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, int.class));
    }

    /**
     * Method to enhance a classes definition.
     * @return Whether it was enhanced with no errors
     */
    public boolean enhance()
    {
        if (cmd.getPersistenceModifier() != ClassPersistenceModifier.PERSISTENCE_CAPABLE &&
            cmd.getPersistenceModifier() != ClassPersistenceModifier.PERSISTENCE_AWARE)
        {
            return false;
        }

        initialise();

        if (checkClassIsEnhanced(false))
        {
            // Already enhanced
            DataNucleusEnhancer.LOGGER.info(LOCALISER.msg("Enhancer.ClassIsAlreadyEnhanced", className));
            return true;
        }

        try
        {
            // Check for generation of PK
            if (cmd.getIdentityType() == IdentityType.APPLICATION &&
                cmd.getObjectidClass() == null && cmd.getNoOfPrimaryKeyMembers() > 1)
            {
                if (hasOption(OPTION_GENERATE_PK))
                {
                    String pkClassName = cmd.getFullClassName() + AbstractClassMetaData.GENERATED_PK_SUFFIX;
                    if (DataNucleusEnhancer.LOGGER.isDebugEnabled())
                    {
                        DataNucleusEnhancer.LOGGER.debug(LOCALISER.msg("Enhancer.GeneratePrimaryKey", cmd.getFullClassName(), pkClassName));
                    }
                    cmd.setObjectIdClass(pkClassName);
                    PrimaryKeyGenerator pkGen = new PrimaryKeyGenerator(cmd, this);
                    pkClassBytes = pkGen.generate();
                }
                else
                {
                    // Throw exception for invalid metadata
                    throw new InvalidMetaDataException(LOCALISER_CORE, "044065", cmd.getFullClassName(),
                        cmd.getNoOfPrimaryKeyMembers());
                }
            }

            // Create an adapter using a writer
            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
            JdoClassAdapter cv = new JdoClassAdapter(cw, this);
            ClassReader cr = null;
            InputStream classReaderInputStream = null;
            try
            {
                // Create a reader for the class and tell it to visit the adapter, performing the changes
                if (inputBytes != null)
                {
                    cr = new ClassReader(inputBytes);
                }
                else
                {
                    classReaderInputStream = clr.getResource(inputResourceName, null).openStream();
                    cr = new ClassReader(classReaderInputStream);
                }
                cr.accept(cv, 0);

                // Save the bytes
                classBytes = cw.toByteArray();
            }
            finally
            {
                if (classReaderInputStream != null)
                {
                    classReaderInputStream.close();
                }
            }
        }
        catch (Exception e)
        {
            DataNucleusEnhancer.LOGGER.error("Error thrown enhancing with ASMClassEnhancer", e);
            return false;
        }

        update = true;
        return true;
    }

    /**
     * Accessor for the class bytes.
     * Only has relevance to be called after enhance().
     * @return The class bytes
     */
    public byte[] getClassBytes()
    {
        return classBytes;
    }

    /**
     * Accessor for the primary-key class bytes (if generating a PK).
     * Only has relevance to be called after enhance().
     * @return The primary-key class bytes
     */
    public byte[] getPrimaryKeyClassBytes()
    {
        return pkClassBytes;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#checkEnhanced()
     */
    public boolean validate()
    {
        if (cmd.getPersistenceModifier() != ClassPersistenceModifier.PERSISTENCE_CAPABLE &&
            cmd.getPersistenceModifier() != ClassPersistenceModifier.PERSISTENCE_AWARE)
        {
            return false;
        }

        initialise();

        return checkClassIsEnhanced(true);
    }

    /**
     * Convenience method to return if a class is enhanced.
     * @param logErrors Whether to log any errors (missing methods etc) as errors (otherwise info/debug)
     * @return Whether the class is enhanced
     */
    protected boolean checkClassIsEnhanced(boolean logErrors)
    {
        try
        {
            // Create an adapter using a writer
            JdoClassChecker checker = new JdoClassChecker(this, logErrors);

            InputStream classReaderInputStream = null;
            try
            {
                // Create a reader for the class and visit it using the checker
                ClassReader cr = null;
                if (inputBytes != null)
                {
                    cr = new ClassReader(inputBytes);
                }
                else
                {
                    classReaderInputStream = clr.getResource(inputResourceName,null).openStream();
                    cr = new ClassReader(classReaderInputStream);
                }
                cr.accept(checker, 0); // [ASM Note : In 2.2 this should be "cr.accept(checker, false);"]
            }
            finally
            {
                if (classReaderInputStream != null)
                {
                    classReaderInputStream.close();
                }
            }

            return checker.isEnhanced();
        }
        catch (Exception e)
        {
            DataNucleusEnhancer.LOGGER.error("Error thrown enhancing with ASMClassEnhancer", e);
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getStateManagerFieldName()
     */
    public String getStateManagerFieldName()
    {
        return FN_StateManager;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getFlagsFieldName()
     */
    public String getFlagsFieldName()
    {
        return FN_Flag;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getFieldNamesFieldName()
     */
    public String getFieldNamesFieldName()
    {
        return FN_FieldNames;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getFieldTypesFieldName()
     */
    public String getFieldTypesFieldName()
    {
        return FN_FieldTypes;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getFieldFlagsFieldName()
     */
    public String getFieldFlagsFieldName()
    {
        return FN_FieldFlags;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getPersistableSuperclassFieldName()
     */
    public String getPersistableSuperclassFieldName()
    {
        return FN_PersistableSuperclass;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getInheritedFieldCountFieldName()
     */
    public String getInheritedFieldCountFieldName()
    {
        return FN_InheritedFieldCount;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getDetachedStateFieldName()
     */
    public String getDetachedStateFieldName()
    {
        return FN_DetachedState;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getSerialVersionUidFieldName()
     */
    public String getSerialVersionUidFieldName()
    {
        return FN_SerialVersionUID;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getFieldNamesInitMethodName()
     */
    public String getFieldNamesInitMethodName()
    {
        return MN_FieldNamesInitMethod;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getFieldTypesInitMethodName()
     */
    public String getFieldTypesInitMethodName()
    {
        return MN_FieldTypesInitMethod;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getFieldFlagsInitMethodName()
     */
    public String getFieldFlagsInitMethodName()
    {
        return MN_FieldFlagsInitMethod;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getGetObjectIdMethodName()
     */
    public String getGetObjectIdMethodName()
    {
        return MN_GetObjectId;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getGetTransactionalObjectIdMethodName()
     */
    public String getGetTransactionalObjectIdMethodName()
    {
        return MN_GetTransactionalObjectId;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getGetVersionMethodName()
     */
    public String getGetVersionMethodName()
    {
        return MN_GetVersion;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getIsDetachedMethodName()
     */
    public String getIsDetachedMethodName()
    {
        return MN_IsDetached;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getIsDetachedInternalMethodName()
     */
    public String getIsDetachedInternalMethodName()
    {
        return MN_IsDetachedInternal;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getIsDeletedMethodName()
     */
    public String getIsDeletedMethodName()
    {
        return MN_IsDeleted;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getIsDirtyMethodName()
     */
    public String getIsDirtyMethodName()
    {
        return MN_IsDirty;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getIsNewMethodName()
     */
    public String getIsNewMethodName()
    {
        return MN_IsNew;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getIsPersistentMethodName()
     */
    public String getIsPersistentMethodName()
    {
        return MN_IsPersistent;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getIsTransactionalMethodName()
     */
    public String getIsTransactionalMethodName()
    {
        return MN_IsTransactional;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getGetPersistenceManagerMethodName()
     */
    public String getGetPersistenceManagerMethodName()
    {
        return MN_GetPersistenceManager;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getPreSerializeMethodName()
     */
    public String getPreSerializeMethodName()
    {
        return MN_PreSerialize;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getGetInheritedFieldCountMethodName()
     */
    public String getGetInheritedFieldCountMethodName()
    {
        return MN_GetInheritedFieldCount;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getSuperCloneMethodName()
     */
    public String getSuperCloneMethodName()
    {
        return MN_SuperClone;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getGetManagedFieldCountMethodName()
     */
    public String getGetManagedFieldCountMethodName()
    {
        return MN_GetManagedFieldCount;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getPersistableSuperclassInitMethodName()
     */
    public String getPersistableSuperclassInitMethodName()
    {
        return MN_PersistableSuperclassInit;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getLoadClassMethodName()
     */
    public String getLoadClassMethodName()
    {
        return MN_LoadClass;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getCopyFieldMethodName()
     */
    public String getCopyFieldMethodName()
    {
        return MN_CopyField;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getCopyFieldsMethodName()
     */
    public String getCopyFieldsMethodName()
    {
        return MN_CopyFields;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getCopyKeyFieldsFromObjectIdMethodName()
     */
    public String getCopyKeyFieldsFromObjectIdMethodName()
    {
        return MN_CopyKeyFieldsFromObjectId;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getCopyKeyFieldsToObjectIdMethodName()
     */
    public String getCopyKeyFieldsToObjectIdMethodName()
    {
        return MN_CopyKeyFieldsToObjectId;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getProvideFieldMethodName()
     */
    public String getProvideFieldMethodName()
    {
        return MN_ProvideField;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getProvideFieldsMethodName()
     */
    public String getProvideFieldsMethodName()
    {
        return MN_ProvideFields;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getReplaceFieldMethodName()
     */
    public String getReplaceFieldMethodName()
    {
        return MN_ReplaceField;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getReplaceFieldsMethodName()
     */
    public String getReplaceFieldsMethodName()
    {
        return MN_ReplaceFields;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getReplaceFlagsMethodName()
     */
    public String getReplaceFlagsMethodName()
    {
        return MN_ReplaceFlags;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getReplaceStateManagerMethodName()
     */
    public String getReplaceStateManagerMethodName()
    {
        return MN_ReplaceStateManager;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getReplaceDetachedStateMethodName()
     */
    public String getReplaceDetachedStateMethodName()
    {
        return MN_ReplaceDetachedState;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getMakeDirtyMethodName()
     */
    public String getMakeDirtyMethodName()
    {
        return MN_MakeDirty;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getMakeDirtyDetachedMethodName()
     */
    public String getMakeDirtyDetachedMethodName()
    {
        return MN_MakeDirtyDetached;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getNewInstanceMethodName()
     */
    public String getNewInstanceMethodName()
    {
        return MN_NewInstance;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getNewObjectIdInstanceMethodName()
     */
    public String getNewObjectIdInstanceMethodName()
    {
        return MN_NewObjectIdInstance;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getGetMethodPrefixMethodName()
     */
    public String getGetMethodPrefixMethodName()
    {
        return MN_GetterPrefix;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getSetMethodPrefixMethodName()
     */
    public String getSetMethodPrefixMethodName()
    {
        return MN_SetterPrefix;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getHelperClassName()
     */
    public String getHelperClassName()
    {
        return CN_JDOHelper;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getImplHelperClassName()
     */
    public String getImplHelperClassName()
    {
        return CN_JDOImplHelper;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getFatalInternalExceptionClassName()
     */
    public String getFatalInternalExceptionClassName()
    {
        return CN_JDOFatalInternalException;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getDetachedFieldAccessExceptionClassName()
     */
    public String getDetachedFieldAccessExceptionClassName()
    {
        return CN_DetachedFieldAccessException;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getStateManagerAsmClassName()
     */
    public String getStateManagerAsmClassName()
    {
        return ACN_StateManager;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getPersistenceManagerAsmClassName()
     */
    public String getPersistenceManagerAsmClassName()
    {
        return ACN_PersistenceManager;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getPersistableAsmClassName()
     */
    public String getPersistableAsmClassName()
    {
        return ACN_Persistable;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getDetachableAsmClassName()
     */
    public String getDetachableAsmClassName()
    {
        return ACN_Detachable;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getObjectIdFieldConsumerAsmClassName()
     */
    public String getObjectIdFieldConsumerAsmClassName()
    {
        return ACN_ObjectIdFieldConsumer;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getObjectIdFieldSupplierAsmClassName()
     */
    public String getObjectIdFieldSupplierAsmClassName()
    {
        return ACN_ObjectIdFieldSupplier;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getDetachedFieldAccessExceptionAsmClassName()
     */
    public String getDetachedFieldAccessExceptionAsmClassName()
    {
        return ACN_DetachedFieldAccessException;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getFatalInternalExceptionAsmClassName()
     */
    public String getFatalInternalExceptionAsmClassName()
    {
        return ACN_FatalInternalException;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getHelperAsmClassName()
     */
    public String getHelperAsmClassName()
    {
        return ACN_Helper;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getImplHelperAsmClassName()
     */
    public String getImplHelperAsmClassName()
    {
        return ACN_ImplHelper;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getByteIdentityDescriptor()
     */
    public String getByteIdentityDescriptor()
    {
        return CD_ByteIdentity;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getCharIdentityDescriptor()
     */
    public String getCharIdentityDescriptor()
    {
        return CD_CharIdentity;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getIntIdentityDescriptor()
     */
    public String getIntIdentityDescriptor()
    {
        return CD_IntIdentity;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getLongIdentityDescriptor()
     */
    public String getLongIdentityDescriptor()
    {
        return CD_LongIdentity;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getShortIdentityDescriptor()
     */
    public String getShortIdentityDescriptor()
    {
        return CD_ShortIdentity;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getStringIdentityDescriptor()
     */
    public String getStringIdentityDescriptor()
    {
        return CD_StringIdentity;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getObjectIdentityDescriptor()
     */
    public String getObjectIdentityDescriptor()
    {
        return CD_ObjectIdentity;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getStateManagerDescriptor()
     */
    public String getStateManagerDescriptor()
    {
        return CD_StateManager;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getPersistenceManagerDescriptor()
     */
    public String getPersistenceManagerDescriptor()
    {
        return CD_PersistenceManager;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getPersistableDescriptor()
     */
    public String getPersistableDescriptor()
    {
        return CD_PersistenceCapable;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getDetachableDescriptor()
     */
    public String getDetachableDescriptor()
    {
        return CD_Detachable;
    }

    /**
     * Accessor for the descriptor for a SingleFieldIdentity type.
     * @param oidClassName Name of the SingleFieldIdentity class
     * @return The descriptor of the SingleFieldIdentity type
     */
    public String getSingleFieldIdentityDescriptor(String oidClassName)
    {
        if (oidClassName.equals(LongIdentity.class.getName()))
        {
            return CD_LongIdentity;
        }
        else if (oidClassName.equals(IntIdentity.class.getName()))
        {
            return CD_IntIdentity;
        }
        else if (oidClassName.equals(StringIdentity.class.getName()))
        {
            return CD_StringIdentity;
        }
        else if (oidClassName.equals(ShortIdentity.class.getName()))
        {
            return CD_ShortIdentity;
        }
        else if (oidClassName.equals(CharIdentity.class.getName()))
        {
            return CD_CharIdentity;
        }
        else if (oidClassName.equals(ByteIdentity.class.getName()))
        {
            return CD_ByteIdentity;
        }
        else if (oidClassName.equals(ObjectIdentity.class.getName()))
        {
            return CD_ObjectIdentity;
        }
        return null;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getTypeDescriptorForSingleFieldIdentityGetKey(java.lang.String)
     */
    public String getTypeDescriptorForSingleFieldIdentityGetKey(String oidClassName)
    {
        if (oidClassName.equals(LongIdentity.class.getName()))
        {
            return Type.LONG_TYPE.getDescriptor();
        }
        else if (oidClassName.equals(IntIdentity.class.getName()))
        {
            return Type.INT_TYPE.getDescriptor();
        }
        else if (oidClassName.equals(ShortIdentity.class.getName()))
        {
            return Type.SHORT_TYPE.getDescriptor();
        }
        else if (oidClassName.equals(CharIdentity.class.getName()))
        {
            return Type.CHAR_TYPE.getDescriptor();
        }
        else if (oidClassName.equals(ByteIdentity.class.getName()))
        {
            return Type.BYTE_TYPE.getDescriptor();
        }
        else if (oidClassName.equals(StringIdentity.class.getName()))
        {
            return CD_String;
        }
        else if (oidClassName.equals(ObjectIdentity.class.getName()))
        {
            return CD_Object;
        }
        return null;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getTypeNameForUseWithSingleFieldIdentity(java.lang.String)
     */
    public String getTypeNameForUseWithSingleFieldIdentity(String oidClassName)
    {
        if (oidClassName == null)
        {
            return null;
        }
        else if (oidClassName.equals(ByteIdentity.class.getName()))
        {
            return "Byte";
        }
        else if (oidClassName.equals(CharIdentity.class.getName()))
        {
            return "Char";
        }
        else if (oidClassName.equals(IntIdentity.class.getName()))
        {
            return "Int";
        }
        else if (oidClassName.equals(LongIdentity.class.getName()))
        {
            return "Long";
        }
        else if (oidClassName.equals(ShortIdentity.class.getName()))
        {
            return "Short";
        }
        else if (oidClassName.equals(StringIdentity.class.getName()))
        {
            return "String";
        }
        return "Object";
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getObjectIdFieldConsumerDescriptor()
     */
    public String getObjectIdFieldConsumerDescriptor()
    {
        return CD_ObjectIdFieldConsumer;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getObjectIdFieldSupplierDescriptor()
     */
    public String getObjectIdFieldSupplierDescriptor()
    {
        return CD_ObjectIdFieldSupplier;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getPersistenceManagerClass()
     */
    public Class getPersistenceManagerClass()
    {
        return CL_PersistenceManager;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getStateManagerClass()
     */
    public Class getStateManagerClass()
    {
        return CL_StateManager;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getPersistableClass()
     */
    public Class getPersistableClass()
    {
        return CL_Persistable;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getDetachableClass()
     */
    public Class getDetachableClass()
    {
        return CL_Detachable;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getObjectIdFieldSupplierClass()
     */
    public Class getObjectIdFieldSupplierClass()
    {
        return CL_ObjectIdFieldSupplier;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getObjectIdFieldConsumerClass()
     */
    public Class getObjectIdFieldConsumerClass()
    {
        return CL_ObjectIdFieldConsumer;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.enhancer.ClassEnhancer#getObjectIdentityClass()
     */
    public Class getObjectIdentityClass()
    {
        return ObjectIdentity.class;
    }
}
TOP

Related Classes of org.datanucleus.enhancer.asm.ASMClassEnhancer

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.