Package org.datanucleus.enhancer

Source Code of org.datanucleus.enhancer.AbstractClassEnhancer

/**********************************************************************
Copyright (c) 2006 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;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.OMFContext;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.ClassMetaData;
import org.datanucleus.metadata.ClassPersistenceModifier;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.StringUtils;

/**
* Abstract representation of a class enhancer.
* To be extended by implementing enhancers.
*/
public abstract class AbstractClassEnhancer implements ClassEnhancer
{
    /** Message resource */
    protected static Localiser LOCALISER = Localiser.getInstance(
        "org.datanucleus.enhancer.Localisation", ClassEnhancer.class.getClassLoader());

    /** Class Loader Resolver to use for any loading issues. */
    protected final ClassLoaderResolver clr;

    /** MetaData for the class being enhanced. */
    protected final ClassMetaData cmd;

    /** Class name of the class being enhanced */
    public final String className;

    /** Flag specifying if the class needs updating. */
    protected boolean update = false;

    /** List of fields to be added to the class. */
    protected List<ClassField> fieldsToAdd = new ArrayList<ClassField>();

    /** List of methods to be added to the class. */
    protected List<ClassMethod> methodsToAdd = new ArrayList<ClassMethod>();

    /** Flag for whether we are initialised. */
    protected boolean initialised = false;

    /**
     * Constructor.
     * @param cmd MetaData for the class to be enhanced
     * @param clr ClassLoader resolver
     */
    public AbstractClassEnhancer(ClassMetaData cmd, ClassLoaderResolver clr)
    {
        this.clr = clr;
        this.cmd = cmd;
        this.className = cmd.getFullClassName();
    }

    /**
     * Initialisation of the information for enhancing this class.
     */
    protected void initialise()
    {
        if (initialised)
        {
            return;
        }

        initialiseFieldsList();
        initialiseMethodsList();
        initialised = true;
    }

    /**
     * Method to initialise the list of methods to add.
     */
    protected abstract void initialiseMethodsList();

    /**
     * Method to initialise the list of fields to add.
     */
    protected abstract void initialiseFieldsList();

    /**
     * Accessor for the methods required.
     * @return List of methods required for enhancement
     */
    public List<ClassMethod> getMethodsList()
    {
        return methodsToAdd;
    }

    /**
     * Accessor for the fields required.
     * @return List of fields required for enhancement
     */
    public List<ClassField> getFieldsList()
    {
        return fieldsToAdd;
    }

    /**
     * Accessor for the ClassLoaderResolver
     * @return ClassLoader resolver
     */
    public ClassLoaderResolver getClassLoaderResolver()
    {
        return clr;
    }

    public ClassMetaData getClassMetaData()
    {
        return cmd;
    }

    /**
     * Convenience method for whether this class needs to implement Detachable
     * @return Whether we need to implement the Detachable interface
     */
    protected boolean requiresDetachable()
    {
        boolean isDetachable = cmd.isDetachable();
        boolean hasPcsc = (cmd.getPersistenceCapableSuperclass() != null);

        if (!hasPcsc && isDetachable)
        {
            // No superclass and we need to be detachable
            return true;
        }
        else if (hasPcsc)
        {
            if (!cmd.getSuperAbstractClassMetaData().isDetachable() && isDetachable)
            {
                // Superclass isnt detachable, but we need to be
                return true;
            }
        }

        return false;
    }

    /**
     * Check if the class is PersistenceCapable or is going to be enhanced based on the metadata
     * @param className the class name
     * @return true if PersistenceCapable
     */
    public boolean isPersistenceCapable(String className)
    {
        if (className.equals(this.className) &&
            (cmd.getPersistenceModifier() != ClassPersistenceModifier.PERSISTENCE_AWARE))
        {
            // This is our class so yes it will be PersistenceCapable
            return true;
        }

        OMFContext omfCtx = cmd.getMetaDataManager().getOMFContext();
        Class cls = clr.classForName(className, new EnhancerClassLoader());
        if (omfCtx.getApiAdapter().isPersistable(cls))
        {
            // The specified class is already PersistenceCapable
            return true;
        }

        AbstractClassMetaData cmd = this.cmd.getMetaDataManager().getMetaDataForClass(cls, clr);
        if (cmd != null && cmd.getPersistenceModifier() == ClassPersistenceModifier.PERSISTENCE_CAPABLE)
        {
            // The specified class has MetaData and will be enhanced shortly
            return true;
        }
        return false;
    }

    /**
     * Method to save the class definition bytecode into a class file.
     * If directoryName is specified it will be written to $directoryName/className.class
     * else will overwrite the existing class.
     * @param directoryName Name of a directory (or null to overwrite the class)
     */
    public void save(String directoryName)
    throws IOException
    {
        if (!update)
        {
            // Not updated so nothing to do here
            return;
        }

        File file = null;
        if (directoryName != null)
        {
            File baseDir = new File(directoryName);
            if (!baseDir.exists())
            {
                baseDir.mkdirs();
            }
            else if (!baseDir.isDirectory())
            {
                throw new RuntimeException("not directory " + directoryName);
            }

            String sep = System.getProperty("file.separator");
            String name = cmd.getFullClassName();
            name = name.replace('.', sep.charAt(0));
            name = name + ".class";
            file = new File(directoryName, name);
            file.getParentFile().mkdirs();
            DataNucleusEnhancer.LOGGER.info(LOCALISER.msg("Enhancer.UpdateClass", file.getCanonicalPath()));
        }
        else
        {
            URL classURL = clr.getResource(className.replace('.','/') + ".class", null);
            DataNucleusEnhancer.LOGGER.info(LOCALISER.msg("Enhancer.UpdateClass", classURL));

            URL convertedPath = cmd.getMetaDataManager().getOMFContext().getPluginManager().resolveURLAsFileURL(classURL);
            if (!convertedPath.toString().equals(classURL.toString()))
            {
                DataNucleusEnhancer.LOGGER.info(LOCALISER.msg("Enhancer.UpdateClass", classURL));
            }
            file = StringUtils.getFileForFilename(convertedPath.getFile());
        }

        FileOutputStream out = null;
        try
        {
            out = new FileOutputStream(file);
            out.write(getBytes());
        }
        finally
        {
            try
            {
                out.close();
                out = null;
            }
            catch (Exception ignore)
            {
                //ignore exception in closing the stream
            }
        }
    }
}
TOP

Related Classes of org.datanucleus.enhancer.AbstractClassEnhancer

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.