You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by jc...@apache.org on 2005/09/01 06:19:12 UTC

svn commit: r265645 - in /jakarta/commons/sandbox/proxy/trunk/src: java/org/apache/commons/proxy/factory/ java/org/apache/commons/proxy/factory/cglib/ java/org/apache/commons/proxy/factory/javassist/ java/org/apache/commons/proxy/factory/reflect/ java/...

Author: jcarman
Date: Wed Aug 31 21:19:02 2005
New Revision: 265645

URL: http://svn.apache.org/viewcvs?rev=265645&view=rev
Log:
Refactored ProxyFactory support classes and JavassistProxyFactory implementation.

Added:
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyClassGenerator.java   (with props)
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyFactory.java   (contents, props changed)
      - copied, changed from r265575, jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/AbstractProxyFactory.java
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/MethodSignature.java   (contents, props changed)
      - copied, changed from r265575, jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/MethodSignature.java
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassCache.java   (with props)
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassGenerator.java   (with props)
    jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/util/
    jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/util/TestMethodSignature.java   (contents, props changed)
      - copied, changed from r265575, jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/TestMethodSignature.java
Removed:
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/AbstractProxyFactory.java
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/MethodSignature.java
    jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/TestMethodSignature.java
Modified:
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/cglib/CglibProxyFactory.java
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistMethodInvocation.java
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/reflect/ReflectionProxyFactory.java

Modified: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/cglib/CglibProxyFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/cglib/CglibProxyFactory.java?rev=265645&r1=265644&r2=265645&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/cglib/CglibProxyFactory.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/cglib/CglibProxyFactory.java Wed Aug 31 21:19:02 2005
@@ -22,7 +22,7 @@
 import org.aopalliance.intercept.MethodInterceptor;
 import org.aopalliance.intercept.MethodInvocation;
 import org.apache.commons.proxy.ObjectProvider;
-import org.apache.commons.proxy.factory.AbstractProxyFactory;
+import org.apache.commons.proxy.factory.util.AbstractProxyFactory;
 
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Method;

Modified: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistMethodInvocation.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistMethodInvocation.java?rev=265645&r1=265644&r2=265645&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistMethodInvocation.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistMethodInvocation.java Wed Aug 31 21:19:02 2005
@@ -21,12 +21,13 @@
 import javassist.CtConstructor;
 import javassist.CtMethod;
 import org.aopalliance.intercept.MethodInvocation;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 
+import java.lang.ref.WeakReference;
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Method;
 import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
 
 /**
  * @author James Carman
@@ -34,13 +35,12 @@
  */
 public abstract class JavassistMethodInvocation implements MethodInvocation
 {
-    // TODO: Make sure this doesn't cause memory leaks in application servers!
-    private static final HashMap<CacheKey,Class> invocationClassCache = new HashMap<CacheKey,Class>();
-    private static final Log log = LogFactory.getLog( JavassistMethodInvocation.class );
+    private static WeakHashMap<ClassLoader, Map<String, WeakReference<Class>>> loaderToClassCache = new WeakHashMap<ClassLoader, Map<String, WeakReference<Class>>>();
+
     protected final Method method;
     protected final Object target;
     protected final Object[] arguments;
-
+    
     public JavassistMethodInvocation( Method method, Object target, Object[] arguments )
     {
         this.method = method;
@@ -68,106 +68,99 @@
         return method;
     }
 
+    private static Map<String, WeakReference<Class>> getClassCache( ClassLoader classLoader )
+    {
+        Map<String, WeakReference<Class>> cache = loaderToClassCache.get( classLoader );
+        if( cache == null )
+        {
+            cache = new HashMap<String, WeakReference<Class>>();
+            loaderToClassCache.put( classLoader, cache );
+        }
+        return cache;
+    }
 
+    private static String toClassCacheKey( Method method )
+    {
+        return String.valueOf( method );
+    }
 
     public synchronized static Class getMethodInvocationClass( ClassLoader classLoader, Method interfaceMethod )
             throws CannotCompileException
     {
-        final CacheKey key = new CacheKey( classLoader, interfaceMethod );
-        Class invocationClass = ( Class ) invocationClassCache.get( key );
-        if( invocationClass == null )
-        {
-            log.debug( "Generating method invocation class for method " + interfaceMethod + "..." );
-            final CtClass ctClass = JavassistUtils.createClass(
-                    interfaceMethod.getDeclaringClass().getSimpleName() + "_" + interfaceMethod.getName() +
-                    "_invocation",
-                    JavassistMethodInvocation.class );
-            final CtConstructor constructor = new CtConstructor(
-                    JavassistUtils.resolve( new Class[]{Method.class, Object.class, Object[].class} ), ctClass );
-            constructor.setBody( "{\n\tsuper($$);\n}" );
-            ctClass.addConstructor( constructor );
-            final CtMethod proceedMethod = new CtMethod( JavassistUtils.resolve( Object.class ), "proceed",
-                                                         JavassistUtils.resolve( new Class[0] ), ctClass );
-            final Class[] argumentTypes = interfaceMethod.getParameterTypes();
-            final StringBuffer proceedBody = new StringBuffer( "{\n" );
-            if( !Void.TYPE.equals( interfaceMethod.getReturnType() ) )
-            {
-                proceedBody.append( "\treturn " );
-            }
-            else
-            {
-                proceedBody.append( "\t" );
-            }
-            proceedBody.append( "( (" );
-            proceedBody.append( interfaceMethod.getDeclaringClass().getName() );
-            proceedBody.append( " )target )." );
-            proceedBody.append( interfaceMethod.getName() );
-            proceedBody.append( "(" );
-            for( int i = 0; i < argumentTypes.length; ++i )
+        final Map<String, WeakReference<Class>> classCache = getClassCache( classLoader );
+        final String key = toClassCacheKey( interfaceMethod );
+        final WeakReference<Class> invocationClassRef = classCache.get( key );
+        Class invocationClass;
+        if( invocationClassRef == null )
+        {
+            invocationClass = createInvocationClass( classLoader, interfaceMethod );
+            classCache.put( key, new WeakReference<Class>( invocationClass ) );
+        }
+        else
+        {
+            synchronized( invocationClassRef )
             {
-                proceedBody.append( "(" );
-                proceedBody.append( argumentTypes[i].getName() );
-                proceedBody.append( ")arguments[" );
-                proceedBody.append( i );
-                proceedBody.append( "]" );
-                if( i != argumentTypes.length - 1 )
+                invocationClass = invocationClassRef.get();
+                if( invocationClass == null )
                 {
-                    proceedBody.append( ", " );
+                    invocationClass = createInvocationClass( classLoader, interfaceMethod );
+                    classCache.put( key, new WeakReference<Class>( invocationClass ) );
                 }
             }
-            proceedBody.append( ");\n" );
-            if( Void.TYPE.equals( interfaceMethod.getReturnType() ) )
-            {
-                proceedBody.append( "\treturn null;\n" );
-            }
-            proceedBody.append( "}" );
-            proceedMethod.setBody( proceedBody.toString() );
-            ctClass.addMethod( proceedMethod );
-            invocationClass = ctClass.toClass( classLoader );
-            invocationClassCache.put( key, invocationClass );
         }
         return invocationClass;
     }
 
-    private static class CacheKey
+    private static Class createInvocationClass( ClassLoader classLoader, Method interfaceMethod )
+            throws CannotCompileException
     {
-        private final ClassLoader classLoader;
-        private final Method method;
-
-        public CacheKey( ClassLoader classLoader, Method method )
+        Class invocationClass;
+        final CtClass ctClass = JavassistUtils.createClass(
+                interfaceMethod.getDeclaringClass().getSimpleName() + "_" + interfaceMethod.getName() +
+                "_invocation",
+                JavassistMethodInvocation.class );
+        final CtConstructor constructor = new CtConstructor(
+                JavassistUtils.resolve( new Class[]{Method.class, Object.class, Object[].class} ), ctClass );
+        constructor.setBody( "{\n\tsuper($$);\n}" );
+        ctClass.addConstructor( constructor );
+        final CtMethod proceedMethod = new CtMethod( JavassistUtils.resolve( Object.class ), "proceed",
+                                                     JavassistUtils.resolve( new Class[0] ), ctClass );
+        final Class[] argumentTypes = interfaceMethod.getParameterTypes();
+        final StringBuffer proceedBody = new StringBuffer( "{\n" );
+        if( !Void.TYPE.equals( interfaceMethod.getReturnType() ) )
         {
-            this.classLoader = classLoader;
-            this.method = method;
+            proceedBody.append( "\treturn " );
         }
-
-        public boolean equals( Object o )
+        else
         {
-            if( this == o )
-            {
-                return true;
-            }
-            if( o == null || getClass() != o.getClass() )
-            {
-                return false;
-            }
-            final CacheKey cacheKey = ( CacheKey ) o;
-            if( !classLoader.equals( cacheKey.classLoader ) )
-            {
-                return false;
-            }
-            if( !method.equals( cacheKey.method ) )
+            proceedBody.append( "\t" );
+        }
+        proceedBody.append( "( (" );
+        proceedBody.append( interfaceMethod.getDeclaringClass().getName() );
+        proceedBody.append( " )target )." );
+        proceedBody.append( interfaceMethod.getName() );
+        proceedBody.append( "(" );
+        for( int i = 0; i < argumentTypes.length; ++i )
+        {
+            proceedBody.append( "(" );
+            proceedBody.append( argumentTypes[i].getName() );
+            proceedBody.append( ")arguments[" );
+            proceedBody.append( i );
+            proceedBody.append( "]" );
+            if( i != argumentTypes.length - 1 )
             {
-                return false;
+                proceedBody.append( ", " );
             }
-            return true;
         }
-
-        public int hashCode()
+        proceedBody.append( ");\n" );
+        if( Void.TYPE.equals( interfaceMethod.getReturnType() ) )
         {
-            int result;
-            result = classLoader.hashCode();
-            result = 29 * result + method.hashCode();
-            return result;
+            proceedBody.append( "\treturn null;\n" );
         }
+        proceedBody.append( "}" );
+        proceedMethod.setBody( proceedBody.toString() );
+        ctClass.addMethod( proceedMethod );
+        invocationClass = ctClass.toClass( classLoader );
+        return invocationClass;
     }
 }

Modified: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java?rev=265645&r1=265644&r2=265645&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java Wed Aug 31 21:19:02 2005
@@ -23,13 +23,11 @@
 import org.aopalliance.intercept.MethodInterceptor;
 import org.apache.commons.proxy.ObjectProvider;
 import org.apache.commons.proxy.exception.ProxyFactoryException;
-import org.apache.commons.proxy.factory.AbstractProxyFactory;
+import org.apache.commons.proxy.factory.util.AbstractProxyClassGenerator;
+import org.apache.commons.proxy.factory.util.AbstractProxyFactory;
+import org.apache.commons.proxy.factory.util.ProxyClassCache;
 
 import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
 
 /**
  * A <a href="http://www.jboss.org/products/javassist">Javassist</a>-based {@link org.apache.commons.proxy.ProxyFactory}
@@ -40,182 +38,116 @@
  */
 public class JavassistProxyFactory extends AbstractProxyFactory
 {
-    // TODO: Make sure this doesn't cause memory leaks in application servers!
-    private static HashMap<ProxyClassDescriptor, Class> delegatingProxyClassCache = new HashMap<ProxyClassDescriptor, Class>();
-    // TODO: Make sure this doesn't cause memory leaks in application servers!
-    private static HashMap<ProxyClassDescriptor, Class> interceptingProxyClassCache = new HashMap<ProxyClassDescriptor, Class>();
+    private static final ProxyClassCache delegatingProxyClassCache = new ProxyClassCache(
+            new DelegatingProxyClassGenerator() );
+    private static final ProxyClassCache interceptingProxyClassCache = new ProxyClassCache(
+            new InterceptingProxyClassGenerator() );
 
     public Object createInterceptingProxy( ClassLoader classLoader, Object target, MethodInterceptor interceptor,
                                            Class... proxyInterfaces )
     {
-        synchronized( interceptingProxyClassCache )
+        try
         {
-            final Method[] methods = getImplementationMethods( proxyInterfaces );
-            final ProxyClassDescriptor key = new ProxyClassDescriptor( methods, classLoader );
-            Class clazz = interceptingProxyClassCache.get( key );
-            if( clazz == null )
-            {
-                log.debug( "Generating intercepting proxy class for interfaces " + Arrays.asList( proxyInterfaces ) +
-                           " using class loader " + classLoader + "..." );
-                try
-                {
-                    final CtClass proxyClass = JavassistUtils.createClass();
-                    JavassistUtils.addInterfaces( proxyClass, proxyInterfaces );
-                    JavassistUtils.addField( Method[].class, "methods", proxyClass );
-                    JavassistUtils.addField( Object.class, "target", proxyClass );
-                    JavassistUtils.addField( MethodInterceptor.class, "interceptor", proxyClass );
-                    final CtConstructor proxyConstructor = new CtConstructor(
-                            JavassistUtils.resolve(
-                                    new Class[]{Method[].class, Object.class, MethodInterceptor.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 = JavassistMethodInvocation
-                                .getMethodInvocationClass( classLoader, methods[i] );
-                        final String body = "{\n\t return ( $r ) interceptor.invoke( new " + invocationClass.getName() +
-                                            "( methods[" + i + "], target, $args ) );\n }";
-                        method.setBody( body );
-                        proxyClass.addMethod( method );
-                    }
-                    clazz = proxyClass.toClass( classLoader );
-                    interceptingProxyClassCache.put( key, clazz );
-                }
-                catch( CannotCompileException e )
-                {
-                    throw new ProxyFactoryException( "Could not compile class.", e );
-                }
-            }
-            try
-            {
-                return clazz.getConstructor( Method[].class, Object.class, MethodInterceptor.class )
-                        .newInstance( methods, target, interceptor );
-            }
-            catch( Exception e )
-            {
-                throw new ProxyFactoryException( "Unable to instantiate proxy class instance.", e );
+            final Class clazz = interceptingProxyClassCache.getProxyClass( classLoader, proxyInterfaces );
+            final Method[] methods = AbstractProxyClassGenerator.getImplementationMethods( proxyInterfaces );
+            return clazz.getConstructor( Method[].class, Object.class, MethodInterceptor.class )
+                    .newInstance( methods, target, interceptor );
+        }
+        catch( Exception e )
+        {
+            throw new ProxyFactoryException( "Unable to instantiate proxy class instance.", e );
 
-            }
         }
     }
 
     public Object createDelegatingProxy( ClassLoader classLoader, ObjectProvider targetProvider,
                                          Class... proxyInterfaces )
     {
-        synchronized( delegatingProxyClassCache )
+        try
         {
-            final Method[] methods = getImplementationMethods( proxyInterfaces );
-            final ProxyClassDescriptor key = new ProxyClassDescriptor( methods, classLoader );
-            Class clazz = delegatingProxyClassCache.get( key );
-            if( clazz == null )
-            {
-                log.debug( "Generating delegating proxy class for interfaces " + Arrays.asList( proxyInterfaces ) +
-                           " using class loader " + classLoader + "..." );
-                try
-                {
-                    final CtClass proxyClass = JavassistUtils.createClass();
-                    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 );
-                    addMethods( proxyInterfaces, proxyClass, new DelegatingMethodBodyProvider() );
-                    clazz = proxyClass.toClass( classLoader );
-                    delegatingProxyClassCache.put( key, clazz );
-                }
-                catch( CannotCompileException e )
-                {
-                    throw new ProxyFactoryException( "Could not compile class.", e );
-                }
-            }
-            try
-            {
-                return clazz.getConstructor( ObjectProvider.class ).newInstance( targetProvider );
-            }
-            catch( Exception e )
-            {
-                throw new ProxyFactoryException( "Unable to instantiate proxy from generated proxy class.", e );
-            }
-        }
-    }
-
-    private void addMethods( Class[] proxyInterfaces, CtClass proxyClass, MethodBodyProvider methodBodyProvider )
-            throws CannotCompileException
-    {
-        JavassistUtils.addInterfaces( proxyClass, proxyInterfaces );
-        final Method[] methods = getImplementationMethods( proxyInterfaces );
-        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 );
-            ctMethod.setBody( methodBodyProvider.getMethodBody( method ) );
-            proxyClass.addMethod( ctMethod );
+            final Class clazz = delegatingProxyClassCache.getProxyClass( classLoader, proxyInterfaces );
+            return clazz.getConstructor( ObjectProvider.class ).newInstance( targetProvider );
         }
-    }
-
-    private interface MethodBodyProvider
-    {
-        public String getMethodBody( Method method );
-    }
-
-    private class DelegatingMethodBodyProvider implements MethodBodyProvider
-    {
-        public String getMethodBody( Method method )
+        catch( Exception e )
         {
-            return "{ return ( $r ) ( ( " + method.getDeclaringClass().getName() + " )provider.getDelegate() )." +
-                   method.getName() + "($$); }";
+            throw new ProxyFactoryException( "Unable to instantiate proxy from generated proxy class.", e );
         }
     }
 
-    private static class ProxyClassDescriptor
+    private static class InterceptingProxyClassGenerator extends AbstractProxyClassGenerator
     {
-        private final List<Method> methods;
-        private final ClassLoader classLoader;
-
-        public ProxyClassDescriptor( Method[] methods, ClassLoader classLoader )
-        {
-            this.methods = new ArrayList<Method>( Arrays.asList( methods ) );
-            this.classLoader = classLoader;
-        }
-
-        public boolean equals( Object o )
+        public Class generateProxyClass( ClassLoader classLoader, Class... proxyInterfaces )
         {
-            if( this == o )
+            try
             {
-                return true;
+                final CtClass proxyClass = JavassistUtils.createClass();
+                final Method[] methods = getImplementationMethods( proxyInterfaces );
+                JavassistUtils.addInterfaces( proxyClass, proxyInterfaces );
+                JavassistUtils.addField( Method[].class, "methods", proxyClass );
+                JavassistUtils.addField( Object.class, "target", proxyClass );
+                JavassistUtils.addField( MethodInterceptor.class, "interceptor", proxyClass );
+                final CtConstructor proxyConstructor = new CtConstructor(
+                        JavassistUtils.resolve(
+                                new Class[]{Method[].class, Object.class, MethodInterceptor.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 = JavassistMethodInvocation
+                            .getMethodInvocationClass( classLoader, methods[i] );
+                    final String body = "{\n\t return ( $r ) interceptor.invoke( new " + invocationClass.getName() +
+                                        "( methods[" + i + "], target, $args ) );\n }";
+                    method.setBody( body );
+                    proxyClass.addMethod( method );
+                }
+                return proxyClass.toClass( classLoader );
             }
-            if( o == null || getClass() != o.getClass() )
+            catch( CannotCompileException e )
             {
-                return false;
+                throw new ProxyFactoryException( "Could not compile class.", e );
             }
-            final ProxyClassDescriptor that = ( ProxyClassDescriptor ) o;
-            if( classLoader != null ? !classLoader.equals( that.classLoader ) : that.classLoader != null )
+        }
+    }
+
+    private static class DelegatingProxyClassGenerator extends AbstractProxyClassGenerator
+    {
+        public Class generateProxyClass( ClassLoader classLoader, Class... proxyInterfaces )
+        {
+            try
             {
-                return false;
+                final CtClass proxyClass = JavassistUtils.createClass();
+                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, proxyInterfaces );
+                final Method[] methods = getImplementationMethods( proxyInterfaces );
+                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 );
+                    ctMethod.setBody( "{ return ( $r ) ( ( " + method.getDeclaringClass().getName() +
+                                      " )provider.getDelegate() )." +
+                                      method.getName() + "($$); }" );
+                    proxyClass.addMethod( ctMethod );
+                }
+                return proxyClass.toClass( classLoader );
             }
-            if( methods != null ? !methods.equals( that.methods ) : that.methods != null )
+            catch( CannotCompileException e )
             {
-                return false;
+                throw new ProxyFactoryException( "Could not compile class.", e );
             }
-            return true;
-        }
-
-        public int hashCode()
-        {
-            int result;
-            result = ( methods != null ? methods.hashCode() : 0 );
-            result = 29 * result + ( classLoader != null ? classLoader.hashCode() : 0 );
-            return result;
         }
     }
 }

Modified: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/reflect/ReflectionProxyFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/reflect/ReflectionProxyFactory.java?rev=265645&r1=265644&r2=265645&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/reflect/ReflectionProxyFactory.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/reflect/ReflectionProxyFactory.java Wed Aug 31 21:19:02 2005
@@ -18,7 +18,7 @@
 
 import org.aopalliance.intercept.MethodInterceptor;
 import org.apache.commons.proxy.ObjectProvider;
-import org.apache.commons.proxy.factory.AbstractProxyFactory;
+import org.apache.commons.proxy.factory.util.AbstractProxyFactory;
 
 import java.lang.reflect.Proxy;
 

Added: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyClassGenerator.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyClassGenerator.java?rev=265645&view=auto
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyClassGenerator.java (added)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyClassGenerator.java Wed Aug 31 21:19:02 2005
@@ -0,0 +1,52 @@
+/* $Id$
+ *
+ * Copyright 2005 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.commons.proxy.factory.util;
+
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author James Carman
+ * @version 1.0
+ */
+public abstract class AbstractProxyClassGenerator implements ProxyClassGenerator
+{
+    public static Method[] getImplementationMethods( Class... proxyInterfaces )
+    {
+        final Set<MethodSignature> signatures = new HashSet<MethodSignature>();
+        final List<Method> resultingMethods = new LinkedList<Method>();
+        for( int i = 0; i < proxyInterfaces.length; i++ )
+        {
+            Class proxyInterface = proxyInterfaces[i];
+            final Method[] methods = proxyInterface.getDeclaredMethods();
+            for( int j = 0; j < methods.length; j++ )
+            {
+                final MethodSignature signature = new MethodSignature( methods[j] );
+                if( !signatures.contains( signature ) )
+                {
+                    signatures.add( signature );
+                    resultingMethods.add( methods[j] );
+                }
+            }
+        }
+        final Method[] results = new Method[resultingMethods.size()];
+        return resultingMethods.toArray( results );
+    }
+}

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyClassGenerator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyClassGenerator.java
------------------------------------------------------------------------------
    svn:keywords = Id

Copied: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyFactory.java (from r265575, jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/AbstractProxyFactory.java)
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyFactory.java?p2=jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyFactory.java&p1=jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/AbstractProxyFactory.java&r1=265575&r2=265645&rev=265645&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/AbstractProxyFactory.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyFactory.java Wed Aug 31 21:19:02 2005
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.commons.proxy.factory;
+package org.apache.commons.proxy.factory.util;
 
 import org.aopalliance.intercept.MethodInterceptor;
 import org.apache.commons.logging.Log;
@@ -57,27 +57,5 @@
     public Object createDelegatingProxy( ObjectProvider targetProvider, Class... proxyInterfaces )
     {
         return createDelegatingProxy( Thread.currentThread().getContextClassLoader(), targetProvider, proxyInterfaces );
-    }
-
-    protected Method[] getImplementationMethods( Class... proxyInterfaces )
-    {
-        final Set<MethodSignature> signatures = new HashSet<MethodSignature>();
-        final List<Method> resultingMethods = new LinkedList<Method>();
-        for( int i = 0; i < proxyInterfaces.length; i++ )
-        {
-            Class proxyInterface = proxyInterfaces[i];
-            final Method[] methods = proxyInterface.getDeclaredMethods();
-            for( int j = 0; j < methods.length; j++ )
-            {
-                final MethodSignature signature = new MethodSignature( methods[j] );
-                if( !signatures.contains( signature ) )
-                {
-                    signatures.add( signature );
-                    resultingMethods.add( methods[j] );
-                }
-            }
-        }
-        final Method[] results = new Method[resultingMethods.size()];
-        return resultingMethods.toArray( results );
     }
 }

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/AbstractProxyFactory.java
------------------------------------------------------------------------------
    svn:keywords = Id

Copied: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/MethodSignature.java (from r265575, jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/MethodSignature.java)
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/MethodSignature.java?p2=jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/MethodSignature.java&p1=jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/MethodSignature.java&r1=265575&r2=265645&rev=265645&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/MethodSignature.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/MethodSignature.java Wed Aug 31 21:19:02 2005
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.commons.proxy.factory;
+package org.apache.commons.proxy.factory.util;
 
 import java.lang.reflect.Method;
 import java.util.Arrays;

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/MethodSignature.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/MethodSignature.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassCache.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassCache.java?rev=265645&view=auto
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassCache.java (added)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassCache.java Wed Aug 31 21:19:02 2005
@@ -0,0 +1,89 @@
+/* $Id$
+ *
+ * Copyright 2005 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.commons.proxy.factory.util;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * @author James Carman
+ * @version 1.0
+ */
+public class ProxyClassCache
+{
+    private final Map<ClassLoader, Map<String, WeakReference<Class>>> loaderToClassCache = new WeakHashMap<ClassLoader, Map<String, WeakReference<Class>>>();
+    private final ProxyClassGenerator proxyClassGenerator;
+
+    public ProxyClassCache( ProxyClassGenerator proxyClassGenerator )
+    {
+        this.proxyClassGenerator = proxyClassGenerator;
+    }
+
+    public synchronized Class getProxyClass( ClassLoader classLoader, Class... proxyInterfaces )
+    {
+        final Map<String, WeakReference<Class>> classCache = getClassCache( classLoader );
+        final String key = toClassCacheKey( proxyInterfaces );
+        Class proxyClass;
+        WeakReference<Class> proxyClassReference = classCache.get( key );
+        if( proxyClassReference == null )
+        {
+            proxyClass = proxyClassGenerator.generateProxyClass( classLoader, proxyInterfaces );
+            classCache.put( key, new WeakReference<Class>( proxyClass ) );
+        }
+        else
+        {
+            synchronized( proxyClassReference )
+            {
+                proxyClass = proxyClassReference.get();
+                if( proxyClass == null )
+                {
+                    proxyClass = proxyClassGenerator.generateProxyClass( classLoader, proxyInterfaces );
+                    classCache.put( key, new WeakReference<Class>( proxyClass ) );
+                }
+            }
+        }
+        return proxyClass;
+    }
+
+    private String toClassCacheKey( Class... proxyInterfaces )
+    {
+        final StringBuffer sb = new StringBuffer();
+        for( int i = 0; i < proxyInterfaces.length; i++ )
+        {
+            Class proxyInterface = proxyInterfaces[i];
+            sb.append( proxyInterface.getName() );
+            if( i != proxyInterfaces.length - 1 )
+            {
+                sb.append( "," );
+            }
+        }
+        return sb.toString();
+    }
+
+    private Map<String, WeakReference<Class>> getClassCache( ClassLoader classLoader )
+    {
+        Map<String, WeakReference<Class>> cache = loaderToClassCache.get( classLoader );
+        if( cache == null )
+        {
+            cache = new HashMap<String, WeakReference<Class>>();
+            loaderToClassCache.put( classLoader, cache );
+        }
+        return cache;
+    }
+}

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassCache.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassGenerator.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassGenerator.java?rev=265645&view=auto
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassGenerator.java (added)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassGenerator.java Wed Aug 31 21:19:02 2005
@@ -0,0 +1,26 @@
+/* $Id$
+ *
+ * Copyright 2005 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.commons.proxy.factory.util;
+
+/**
+ * @author James Carman
+ * @version 1.0
+ */
+public interface ProxyClassGenerator
+{
+    public Class generateProxyClass( ClassLoader classLoader, Class... proxyInterfaces );
+}

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassGenerator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/util/ProxyClassGenerator.java
------------------------------------------------------------------------------
    svn:keywords = Id

Copied: jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/util/TestMethodSignature.java (from r265575, jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/TestMethodSignature.java)
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/util/TestMethodSignature.java?p2=jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/util/TestMethodSignature.java&p1=jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/TestMethodSignature.java&r1=265575&r2=265645&rev=265645&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/TestMethodSignature.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/util/TestMethodSignature.java Wed Aug 31 21:19:02 2005
@@ -14,10 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.commons.proxy.factory;
+package org.apache.commons.proxy.factory.util;
 import junit.framework.TestCase;
 import org.apache.commons.proxy.util.DuplicateEcho;
 import org.apache.commons.proxy.util.Echo;
+import org.apache.commons.proxy.factory.util.MethodSignature;
 
 public class TestMethodSignature extends TestCase
 {

Propchange: jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/util/TestMethodSignature.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/util/TestMethodSignature.java
------------------------------------------------------------------------------
    svn:keywords = Id



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org