Package org.jpox.enhancer

Source Code of org.jpox.enhancer.Enhancer$EnhancerClassLoader

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

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;

import org.jpox.ClassLoaderResolver;
import org.jpox.OMFContext;
import org.jpox.PersistenceConfiguration;
import org.jpox.exceptions.ClassNotResolvedException;
import org.jpox.exceptions.JPOXException;
import org.jpox.metadata.AbstractClassMetaData;
import org.jpox.metadata.MetaDataFactory;
import org.jpox.metadata.MetaDataManager;
import org.jpox.plugin.PluginManager;
import org.jpox.util.ClassUtils;
import org.jpox.util.JPOXLogger;
import org.jpox.util.Localiser;
import org.jpox.util.StringUtils;

import org.jpox.metadata.ClassMetaData;

/**
* Class that will enhance a class at runtime called via the ClassTransformer.
*/
public class Enhancer
{
    /** Message resource */
    protected static Localiser LOCALISER = Localiser.getInstance("org.jpox.enhancer.Localisation",
        ClassEnhancer.class.getClassLoader());

    private Constructor classEnhancerConstructor;

    /** API adapter to use for enhancement. */
    private String api;

    /** The symbolic name of the ClassEnhancer to use (default is ASM currently). */
    private String enhancerName = "ASM";

    private ClassLoaderResolver clr;
    private PluginManager pluginMgr;
    private OMFContext omfContext;
   
    /** if this enhancer is initialized, once initialized settings cannot be changed **/
    private boolean initialized = false;
   
    private static Class[] CLASS_ENHANCER_CONSTRUCTOR_ARGS_TYPES = new Class[] {ClassMetaData.class, ClassLoaderResolver.class, byte[].class};
   
    /**
     *  This classloader is used to load any classes that are necessary during enhancement process,
     *  and avoid using application classloaders to load classes
     */
    public class EnhancerClassLoader extends ClassLoader
    {
        EnhancerClassLoader(ClassLoader loader)
        {
            super(loader);
        }
        protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException
        {
            if( name.startsWith("java."))
            {
                //we cannot reload these classes due to security constraints
                return super.loadClass(name, resolve);
            }
            Class c = super.findLoadedClass(name);
            if( c != null )
            {
                return c;
            }
            String resource = StringUtils.replaceAll(name, ".", "/")+".class";
           
            try
            {
                //read the class bytes, and define the class
                URL url = super.getResource(resource);
                if( url == null)
                {
                    throw new ClassNotFoundException(name);
                }
                InputStream is = url.openStream();
                try
                {
                    ByteArrayOutputStream os = new ByteArrayOutputStream();
                    byte[] b = new byte[2048];
                    int count;
                    while((count = is.read(b,0,2048))!=-1)
                    {
                        os.write(b,0,count);
                    }
                    byte[] bytes = os.toByteArray();
                    return defineClass(name, bytes, 0, bytes.length);
                }
                finally
                {
                    if( is!= null)
                    {
                        is.close();
                    }
                }
            }
            catch (SecurityException e)
            {
                return super.loadClass(name, resolve);
            }   
            catch (IOException e)
            {
                throw new ClassNotFoundException(name, e);
            }
        }
    }
    public Enhancer(PersistenceConfiguration config)
    {
        omfContext = new OMFContext(config);
        omfContext.getMetaDataManager().setEnhancing();
        api = omfContext.getPersistenceConfiguration().getStringProperty("org.jpox.persistenceApiName");
        pluginMgr = omfContext.getPluginManager();
        clr = omfContext.getClassLoaderResolver(null);
    }

    public Enhancer()
    {
        this(new PersistenceConfiguration() {});
    }
   
    public byte[] enhance(final String className, byte[] classdefinition, ClassLoader loader)
    {
        initialize();
        //we load unenhanced versions of classes from the EnhancerClassLoader
        clr.setPrimary(new EnhancerClassLoader(loader));
        try
        {
            Class clazz = null;
            try
            {
                clazz = clr.classForName(className);
            }
            catch (ClassNotResolvedException e1)
            {
                JPOXLogger.ENHANCER.debug(StringUtils.getStringFromStackTrace(e1));
                return null;
            }
            AbstractClassMetaData acmd = omfContext.getMetaDataManager().getMetaDataForClass(clazz, clr);
           
            if( acmd == null )
            {
                //metadata or class not found, ignore.
                //happens in two conditions:
                //-class not in classpath
                //-class does not have metadata or annotation, so it's not supposed to be persistent
                JPOXLogger.ENHANCER.debug("Class "+className+" cannot be enhanced because no metadata has been found.");
                return null;
            }
            // Create a ClassEnhancer to enhance this class
            ClassEnhancer classEnhancer = null;
            try
            {
                classEnhancer = (ClassEnhancer)classEnhancerConstructor.newInstance(new Object[] {acmd, clr,classdefinition});
            }
            catch (InvocationTargetException e)
            {
                e.printStackTrace();
                // Error creating the ClassEnhancer
                String msg = LOCALISER.msg("Enhancer.ClassEnhancer.ConstructorError",
                    enhancerName, classEnhancerConstructor.getDeclaringClass().getName(), e.getTargetException());
                JPOXLogger.ENHANCER.error(msg, e);
                return null;
            }
            catch (Exception e)
            {
                e.printStackTrace();
                // Error creating the ClassEnhancer
                String msg = LOCALISER.msg("Enhancer.ClassEnhancer.ConstructorError",
                    enhancerName, classEnhancerConstructor.getDeclaringClass().getName(), e.getMessage());
                JPOXLogger.ENHANCER.error(msg, e);
                return null;
            }
            classEnhancer.enhance();
            return classEnhancer.getBytes();
           
        }
        catch(Throwable ex)
        {
            JPOXLogger.ENHANCER.error(StringUtils.getStringFromStackTrace(ex));
        }
        return null;
    }
   
    private synchronized void initialize()
    {
        if (initialized)
        {
            return;
        }
        String metadataFactory = getClassEnhancerMetadataFactoryName();
        if (!StringUtils.isWhitespace(metadataFactory))
        {
            try
            {
                Class factoryCls = clr.classForName(metadataFactory,Enhancer.class.getClassLoader());
                MetaDataFactory factory = (MetaDataFactory)ClassUtils.newInstance(factoryCls,
                    new Class[] {MetaDataManager.class}, new Object[] {omfContext.getMetaDataManager()});
                omfContext.getMetaDataManager().setMetaDataFactory(factory);
            }
            catch (Exception e)
            {
                JPOXLogger.ENHANCER.error(StringUtils.getStringFromStackTrace(e));
            }
        }
        initialiazeClassEnhancerClass();
        initialized = true;
    }
   
    /**
     * Accessor for the ClassEnhancer class.
     * @param clr ClassLoader resolver
     * @return The class of the ClassEnhancer
     */
    private void initialiazeClassEnhancerClass()
    {
        if (classEnhancerConstructor != null)
        {
            // We already have the class
            return;
        }

        Class classEnhancerClass;
       
        String className = null;
        try
        {
            className = (String) pluginMgr.getAttributeValueForExtension("org.jpox.enhancer.enhancer",
                new String[]{"name", "api"}, new String[]{ enhancerName, api}, "class-name");
            classEnhancerClass = clr.classForName(className,Enhancer.class.getClassLoader());
        }
        catch (Exception e)
        {
            throw new JPOXException(LOCALISER.msg("Enhancer.ClassEnhancer.ClassNotFound", enhancerName, className), e);
        }
        try
        {
            classEnhancerConstructor = classEnhancerClass.getConstructor(CLASS_ENHANCER_CONSTRUCTOR_ARGS_TYPES);
        }
        catch (Exception e)
        {
            String msg = LOCALISER.msg("Enhancer.ClassEnhancer.ConstructorNotFound",
                enhancerName, classEnhancerClass.getName(), e.getMessage());
            JPOXLogger.ENHANCER.error(msg, e);
        }
    }
   
    public void setApi(String api)
    {
        this.api = api;
    }
   
    public void setEnhancerName(String enhancerName)
    {
        this.enhancerName = enhancerName;
    }
   
    /**
     * Accessor for the name of the MetaDataFactory for this ClassEnhancer (if any).
     * @return MetaData factory class name for the ClassEnhancer
     */
    private String getClassEnhancerMetadataFactoryName()
    {
        // Find the "metadata-factory" attribute for this ClassEnhancer/API
        try
        {
            return (String) pluginMgr.getAttributeValueForExtension("org.jpox.enhancer.enhancer",
                new String[]{"name", "api"}, new String[]{ enhancerName, api}, "metadata-factory");
        }
        catch (Exception e)
        {
            throw new JPOXException(LOCALISER.msg("Enhancer.ClassEnhancer.TestClassConstructionFailure", enhancerName, e));
        }
    }
}
TOP

Related Classes of org.jpox.enhancer.Enhancer$EnhancerClassLoader

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.