Package org.apache.avalon.fortress.impl.factory

Source Code of org.apache.avalon.fortress.impl.factory.BCELWrapperGenerator$BCELClassLoader

/*
* Copyright 2003-2004 The Apache Software Foundation
* 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.
*/

package org.apache.avalon.fortress.impl.factory;

import java.security.ProtectionDomain;

import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.Type;
import org.apache.bcel.util.ClassLoaderRepository;
import org.apache.bcel.util.Repository;

/**
* Create the BCELWrapper for the component.
* The generated wrapper classes will be assigned the same ProtectionDomain as
*  the actual classes which they are wrapping.  This simplifies the
*  configuration of a SecurityManager by making the existence of the BCEL
*  generated classes transparent to the policy file author.
*
* @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
*/
final class BCELWrapperGenerator
{
    /**
     * The BCEL util.Repository instance to use when loading JavaClass instances.
     * Default is to use util.ClassLoaderRepository with thread context classloader.
     */
    private Repository m_repository = null;

    /**
     * The suffix to be appended to the name of the wrapped class when creating
     * the name of the wrapper class.
     */
    private static final String WRAPPER_CLASS_SUFFIX = "$BCELWrapper";

    /**
     * The name of the superclass of the wrapper class to be generated.
     */
    private static final String WRAPPER_SUPERCLASS_NAME = "org.apache.avalon.fortress.impl.handler.AbstractReleasableComponent";

    /**
     * The name of the interface each generated wrapper class has to implement.
     */
    private static final String WRAPPER_CLASS_INTERFACE_NAME =
        WrapperClass.class.getName();

    /**
     * The <code>BCELCodeGenerator</code> to use for
     * byte code generation.
     */
    private final BCELCodeGenerator m_codeGenerator;

    /**
     * The <code>ClassGen</code> instance to use for byte code generation.
     */
    private ClassGen m_classGenerator = null;

    /**
     * The <code>ClassLoader</code> to use when loading a class generated by this
     * <code>BCELWrapperGenerator</code>.
     */
    private final BCELClassLoader m_bcelClassLoader;

    /**
     * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
     */
    private final class BCELClassLoader extends ClassLoader
    {
        /**
         * The <i>byte code</i> representing the wrapper class created by the
         * enclosing <code>BCELWrapperGenerated</code>. This field will be
         * managed by the <code>BCELWrapperGenerator</code>.
         */
        private byte[] m_byteCode = null;
       
        /**
         * The ProtectionDomain to use for the newly generated class.  When a
         *  SecurityManager is set, this will determine what privileges this
         *  class will have.
         */
        private ProtectionDomain m_protectionDomain;

        /**
         * Constructs a <code>BCELClassLoader</code> with the specified class
         * loader as its parent.
         *
         * @param parent The parent <code>ClassLoader</code>
         */
        public BCELClassLoader( final ClassLoader parent )
        {
            super( parent );
        }

        /**
         * Constructs a <code>BCELClassLoader</code> with no parent.
         *
         */
        public BCELClassLoader()
        {
            super();
        }

        /**
         *
         * @see java.lang.ClassLoader#findClass(String)
         */
        protected Class findClass( final String name ) throws ClassNotFoundException
        {
            // Check if the requested class falls within the domain of
            // the BCELWrapperGenerator
            if ( name.endsWith( WRAPPER_CLASS_SUFFIX ) )
            {
                Class clazz = super.defineClass(
                    name,
                    m_byteCode,
                    0,
                    m_byteCode.length,
                    m_protectionDomain );
               
                return clazz;
            }

            return super.findClass( name );
        }

        /**
         * Passes in data needed to create and initialze the new class when
         *  findClass is called by the <code>BCELWrapperGenerator</code>.
         * This method will be called by the <code>BCELWrapperGenerator</code>
         * prior to asking this class loader for the generated wrapper class.
         *
         * @param byteCode The <code>byte code</code> to use when loading
         *                  the generated class
         * @param protectionDomain The ProtectionDomain to use when loading
         *                         the generated class.
         *
         * @throws IllegalArgumentException If <code>byteCode</code> is null or
         *          empty
         */
        private void setup( final byte[] byteCode, final ProtectionDomain protectionDomain )
            throws IllegalArgumentException
        {
            if ( byteCode == null || byteCode.length == 0 )
            {
                final String message =
                    "Parameter byteCode must neither be <null> nor empty.";
                throw new IllegalArgumentException( message );
            }

            m_byteCode = byteCode;
            m_protectionDomain = protectionDomain;
        }

        /**
         * Clears the data used to generate a class to free up memory.
         * This method will be called by the <code>BCELWrapperGenerator</code>
         * immediately after this class loader has returned the generated wrapper
         * class.
         */
        private void tearDown()
        {
            m_byteCode = null;
            m_protectionDomain = null;
        }

        /**
         * Returns the <code>byte code</code> to use when loading a generated
         * class.
         *
         * @return The <code>byte code</code> for defining the generated class
         */
        private byte[] getByteCode()
        {
            return m_byteCode;
        }
    } // End BCELClassLoader

    /**
     * No-args default constructor.
     */
    public BCELWrapperGenerator()
    {
        m_codeGenerator = new BCELCodeGenerator();
        ClassLoader contextClassLoader =
                Thread.currentThread().getContextClassLoader();
        m_repository = new ClassLoaderRepository( contextClassLoader );
        m_bcelClassLoader =
            new BCELClassLoader( contextClassLoader );
    }

    /**
     */
    public synchronized Class createWrapper( final Class classToWrap ) throws Exception
    {
        if ( classToWrap == null )
        {
            final String message = "Class to wrap must not be <null>.";
            throw new IllegalArgumentException( message );
        }
       
        // Use the same ProtectionDomain as the class being wrapped.
        ProtectionDomain protectionDomain = classToWrap.getProtectionDomain();

        // Guess work interfaces ...
        final Class[] interfacesToImplement =
            AbstractObjectFactory.guessWorkInterfaces( classToWrap );

        // Get JavaClasses as required by BCEL for the wrapped class and its interfaces
        final JavaClass javaClassToWrap = lookupClass( classToWrap );
        final JavaClass[] javaInterfacesToImplement =
            lookupClasses( interfacesToImplement );

        // The name of the wrapper class to be generated
        final String wrapperClassName =
            classToWrap.getName() + WRAPPER_CLASS_SUFFIX;

        Class generatedClass;
        synchronized ( Type.class )
        {
            // Create BCEL class generator
            m_classGenerator =
                new ClassGen(
                    wrapperClassName,
                    WRAPPER_SUPERCLASS_NAME,
                    null,
                    Constants.ACC_FINAL
                |Constants.ACC_PUBLIC
                |Constants.ACC_SUPER,
                    extractInterfaceNames( interfacesToImplement ) );

            // Initialize method-field generator
            m_codeGenerator.init(
                wrapperClassName,
                WRAPPER_SUPERCLASS_NAME,
                javaClassToWrap,
                m_classGenerator );

            final byte[] byteCode = buildWrapper( javaInterfacesToImplement );
            m_bcelClassLoader.setup( byteCode, protectionDomain );
            try
            {
                generatedClass = m_bcelClassLoader.loadClass( wrapperClassName );
            }
            finally
            {
                m_bcelClassLoader.tearDown();
            }
        }

        return generatedClass;
    }

    /**
     * Takes a <code>Class</code> instance as a its parameter and returns corresponding
     * the <code>JavaClass</code> instance as used by <b>BCEL</b>.
     *
     * @param clazz The <code>Class</code> instance we want to turn into a
     *               <code>JavaClass</code>
     * @return The <code>JavaClass</code> representing the given <code>Class</code>
     *          instance
     */
    private JavaClass lookupClass( final Class clazz ) throws Exception
    {
        String className = clazz.getName();
        try
        {
            JavaClass jClazz = m_repository.findClass( className );
            if ( jClazz == null )
            return m_repository.loadClass( className );
            else
            return jClazz;
        } catch ( ClassNotFoundException e ) { return null; }
    }

    /**
     * Takes an array of <code>Class</code> instances and returns an array holding
     * the corresponding <code>JavaClass</code> instances as used by <b>BCEL</b>.
     *
     * @param classes      An array holding <code>Class</code> instances we
     *                      want to turn into <code>JavaClass</code> instances
     * @return JavaClass[] An array of <code>JavaClass</code> instances representing
     *                      the given <code>Class</code> instances
     */
    private JavaClass[] lookupClasses( final Class[] classes ) throws Exception
    {
        final JavaClass[] javaClasses = new JavaClass[classes.length];
        for ( int i = 0; i < classes.length; ++i )
        {
            javaClasses[i] = lookupClass( classes[i] );
        }

        return javaClasses;
    }

    /**
     * Takes an array of <code>Class</code> instances supposed to represent
     * interfaces and returns a list of the names of those interfaces.
     *
     * @param interfaces An array of <code>Class</code> instances
     * @return String[]  An array of the names of those <code>Class</code> instances
     */
    private String[] extractInterfaceNames( final Class[] interfaces )
    {
        final String[] ifaceNames = new String[interfaces.length + 1];
        for ( int i = 0; i < interfaces.length; ++i )
        {
            ifaceNames[i] = interfaces[i].getName();
        }
        // Add interface WrapperClass to the list of interfaces to be implemented
        ifaceNames[ifaceNames.length - 1] = WRAPPER_CLASS_INTERFACE_NAME;

        return ifaceNames;
    }

    /**
     * Generates the wrapper byte code for a given interface.
     *
     * @param interfacesToImplement The interfaces we want to generate wrapper
     *                               byte code for
     * @return byte[] The generated byte code
     */
    private byte[] buildWrapper( final JavaClass[] interfacesToImplement ) throws Exception
    {
        // Create field for the wrapped class
        m_classGenerator.addField( m_codeGenerator.createWrappedClassField() );

        // Create default constructor
        m_classGenerator.addMethod( m_codeGenerator.createDefaultConstructor() );

        //Create field accessor for wrapped class instance
        m_classGenerator.addMethod(
            m_codeGenerator.createWrappedClassAccessor() );

        // Implement interfaces
        Method[] interfaceMethods = m_codeGenerator.createImplementation( interfacesToImplement );

        for ( int j = 0; j < interfaceMethods.length; ++j )
        {
            m_classGenerator.addMethod( interfaceMethods[j] );
        }

        return m_classGenerator.getJavaClass().getBytes();
    }
}
TOP

Related Classes of org.apache.avalon.fortress.impl.factory.BCELWrapperGenerator$BCELClassLoader

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.