Package org.apache.commons.proxy.factory.javassist

Source Code of org.apache.commons.proxy.factory.javassist.JavassistProxyFactory

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.commons.proxy.factory.javassist;

import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtMethod;
import org.apache.commons.proxy.Interceptor;
import org.apache.commons.proxy.Invoker;
import org.apache.commons.proxy.ObjectProvider;
import org.apache.commons.proxy.exception.ProxyFactoryException;
import org.apache.commons.proxy.factory.util.AbstractProxyClassGenerator;
import org.apache.commons.proxy.factory.util.AbstractSubclassingProxyFactory;
import org.apache.commons.proxy.factory.util.ProxyClassCache;

import java.lang.reflect.Method;

/**
* A <a href="http://www.jboss.org/products/javassist">Javassist</a>-based {@link org.apache.commons.proxy.ProxyFactory}
* implementation.
* <p/>
* <b>Dependencies</b>: <ul> <li>Javassist version 3.0 or greater</li> </ul> </p>
*
* @author James Carman
* @since 1.0
*/
public class JavassistProxyFactory extends AbstractSubclassingProxyFactory
{
//----------------------------------------------------------------------------------------------------------------------
// Fields
//----------------------------------------------------------------------------------------------------------------------
    private static final ProxyClassCache delegatingProxyClassCache = new ProxyClassCache(
            new DelegatingProxyClassGenerator() );
    private static final ProxyClassCache interceptorProxyClassCache = new ProxyClassCache(
            new InterceptorProxyClassGenerator() );
    private static final ProxyClassCache invocationHandlerProxyClassCache = new ProxyClassCache(
            new InvokerProxyClassGenerator() );

//----------------------------------------------------------------------------------------------------------------------
// ProxyFactory Implementation
//----------------------------------------------------------------------------------------------------------------------

    public Object createDelegatorProxy( ClassLoader classLoader, ObjectProvider targetProvider,
                                        Class[] proxyClasses )
    {
        try
        {
            final Class clazz = delegatingProxyClassCache.getProxyClass( classLoader, proxyClasses );
            return clazz.getConstructor( new Class[]{ ObjectProvider.class } )
                    .newInstance( new Object[]{ targetProvider } );
        }
        catch( Exception e )
        {
            throw new ProxyFactoryException( "Unable to instantiate proxy from generated proxy class.", e );
        }
    }

    public Object createInterceptorProxy( ClassLoader classLoader, Object target, Interceptor interceptor,
                                          Class[] proxyClasses )
    {
        try
        {
            final Class clazz = interceptorProxyClassCache.getProxyClass( classLoader, proxyClasses );
            final Method[] methods = AbstractProxyClassGenerator.getImplementationMethods( proxyClasses );
            return clazz.getConstructor( new Class[]{ Method[].class, Object.class, Interceptor.class } )
                    .newInstance( new Object[]{ methods, target, interceptor } );
        }
        catch( Exception e )
        {
            throw new ProxyFactoryException( "Unable to instantiate proxy class instance.", e );
        }
    }

    public Object createInvokerProxy( ClassLoader classLoader, Invoker invoker,
                                      Class[] proxyClasses )
    {
        try
        {
            final Class clazz = invocationHandlerProxyClassCache.getProxyClass( classLoader, proxyClasses );
            final Method[] methods = AbstractProxyClassGenerator.getImplementationMethods( proxyClasses );
            return clazz.getConstructor( new Class[]{ Method[].class, Invoker.class } )
                    .newInstance( new Object[]{ methods, invoker } );
        }
        catch( Exception e )
        {
            throw new ProxyFactoryException( "Unable to instantiate proxy from generated proxy class.", e );
        }
    }

//----------------------------------------------------------------------------------------------------------------------
// Inner Classes
//----------------------------------------------------------------------------------------------------------------------

    private static class InvokerProxyClassGenerator extends AbstractProxyClassGenerator
    {
        public Class generateProxyClass( ClassLoader classLoader, Class[] proxyClasses )
        {
            try
            {
                final CtClass proxyClass = JavassistUtils.createClass( getSuperclass( proxyClasses ) );
                final Method[] methods = getImplementationMethods( proxyClasses );
                JavassistUtils.addInterfaces( proxyClass, toInterfaces( proxyClasses ) );
                JavassistUtils.addField( Method[].class, "methods", proxyClass );
                JavassistUtils.addField( Invoker.class, "invoker", proxyClass );
                final CtConstructor proxyConstructor = new CtConstructor(
                        JavassistUtils.resolve(
                                new Class[]{ Method[].class, Invoker.class } ),
                        proxyClass );
                proxyConstructor
                        .setBody( "{\n\tthis.methods = $1;\n\tthis.invoker = $2; }" );
                proxyClass.addConstructor( proxyConstructor );
                for( int i = 0; i < methods.length; ++i )
                {
                    final CtMethod method = new CtMethod( JavassistUtils.resolve( methods[i].getReturnType() ),
                                                          methods[i].getName(),
                                                          JavassistUtils.resolve( methods[i].getParameterTypes() ),
                                                          proxyClass );
                    final String body = "{\n\t return ( $r ) invoker.invoke( this, methods[" + i +
                                        "], $args );\n }";
                    method.setBody( body );
                    proxyClass.addMethod( method );
                }
                return proxyClass.toClass( classLoader );
            }
            catch( CannotCompileException e )
            {
                throw new ProxyFactoryException( "Could not compile class.", e );
            }
        }
    }

    private static class InterceptorProxyClassGenerator extends AbstractProxyClassGenerator
    {
        public Class generateProxyClass( ClassLoader classLoader, Class[] proxyClasses )
        {
            try
            {
                final CtClass proxyClass = JavassistUtils.createClass( getSuperclass( proxyClasses ) );
                final Method[] methods = getImplementationMethods( proxyClasses );
                JavassistUtils.addInterfaces( proxyClass, toInterfaces( proxyClasses ) );
                JavassistUtils.addField( Method[].class, "methods", proxyClass );
                JavassistUtils.addField( Object.class, "target", proxyClass );
                JavassistUtils.addField( Interceptor.class, "interceptor", proxyClass );
                final CtConstructor proxyConstructor = new CtConstructor(
                        JavassistUtils.resolve(
                                new Class[]{ Method[].class, Object.class, Interceptor.class } ),
                        proxyClass );
                proxyConstructor
                        .setBody(
                                "{\n\tthis.methods = $1;\n\tthis.target = $2;\n\tthis.interceptor = $3; }" );
                proxyClass.addConstructor( proxyConstructor );
                for( int i = 0; i < methods.length; ++i )
                {
                    final CtMethod method = new CtMethod( JavassistUtils.resolve( methods[i].getReturnType() ),
                                                          methods[i].getName(),
                                                          JavassistUtils.resolve( methods[i].getParameterTypes() ),
                                                          proxyClass );
                    final Class invocationClass = JavassistInvocation
                            .getMethodInvocationClass( classLoader, methods[i] );
                    final String body = "{\n\t return ( $r ) interceptor.intercept( new " + invocationClass.getName() +
                                        "( methods[" + i + "], target, $args ) );\n }";
                    method.setBody( body );
                    proxyClass.addMethod( method );

                }
                return proxyClass.toClass( classLoader );
            }
            catch( CannotCompileException e )
            {
                throw new ProxyFactoryException( "Could not compile class.", e );
            }
        }
    }

    private static class DelegatingProxyClassGenerator extends AbstractProxyClassGenerator
    {
        public Class generateProxyClass( ClassLoader classLoader, Class[] proxyClasses )
        {
            try
            {
                final CtClass proxyClass = JavassistUtils.createClass( getSuperclass( proxyClasses ) );
                JavassistUtils.addField( ObjectProvider.class, "provider", proxyClass );
                final CtConstructor proxyConstructor = new CtConstructor(
                        JavassistUtils.resolve( new Class[]{ ObjectProvider.class } ),
                        proxyClass );
                proxyConstructor.setBody( "{ this.provider = $1; }" );
                proxyClass.addConstructor( proxyConstructor );
                JavassistUtils.addInterfaces( proxyClass, toInterfaces( proxyClasses ) );
                final Method[] methods = getImplementationMethods( proxyClasses );
                for( int i = 0; i < methods.length; ++i )
                {
                    final Method method = methods[i];
                    final CtMethod ctMethod = new CtMethod( JavassistUtils.resolve( method.getReturnType() ),
                                                            method.getName(),
                                                            JavassistUtils.resolve( method.getParameterTypes() ),
                                                            proxyClass );
                    final String body = "{ return ( $r ) ( ( " + method.getDeclaringClass().getName() +
                                        " )provider.getObject() )." +
                                        method.getName() + "($$); }";
                    ctMethod.setBody( body );
                    proxyClass.addMethod( ctMethod );

                }
                return proxyClass.toClass( classLoader );
            }
            catch( CannotCompileException e )
            {
                throw new ProxyFactoryException( "Could not compile class.", e );
            }
        }
    }
}
TOP

Related Classes of org.apache.commons.proxy.factory.javassist.JavassistProxyFactory

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.