cache asm4-generated classes; do not defer to JdkProxyFactory for interface-only proxies

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/proxy/branches/version-2.0-work@1520892 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/asm4/src/main/java/org/apache/commons/proxy2/asm4/ASM4ProxyFactory.java b/asm4/src/main/java/org/apache/commons/proxy2/asm4/ASM4ProxyFactory.java
index 2a0a9e3..e4a8d0c 100644
--- a/asm4/src/main/java/org/apache/commons/proxy2/asm4/ASM4ProxyFactory.java
+++ b/asm4/src/main/java/org/apache/commons/proxy2/asm4/ASM4ProxyFactory.java
@@ -24,6 +24,7 @@
 import org.apache.commons.proxy2.exception.ProxyFactoryException;
 import org.apache.commons.proxy2.impl.AbstractProxyClassGenerator;
 import org.apache.commons.proxy2.impl.AbstractSubclassingProxyFactory;
+import org.apache.commons.proxy2.impl.ProxyClassCache;
 import org.apache.xbean.asm4.ClassWriter;
 import org.apache.xbean.asm4.Label;
 import org.apache.xbean.asm4.MethodVisitor;
@@ -36,36 +37,38 @@
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.lang.reflect.Proxy;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.ReentrantLock;
 
 public class ASM4ProxyFactory extends AbstractSubclassingProxyFactory
 {
+	private static final ProxyClassCache PROXY_CLASS_CACHE = new ProxyClassCache(new ProxyGenerator());
+
     @Override
     public <T> T createDelegatorProxy(final ClassLoader classLoader, final ObjectProvider<?> delegateProvider, final Class<?>... proxyClasses)
     {
-        return ProxyGenerator.newProxyInstance(classLoader, new DelegatorInvocationHandler(delegateProvider), proxyClasses);
+        return createProxy(classLoader, new DelegatorInvocationHandler(delegateProvider), proxyClasses);
     }
 
     @Override
     public <T> T createInterceptorProxy(final ClassLoader classLoader, final Object target, final Interceptor interceptor, final Class<?>... proxyClasses)
     {
-        return ProxyGenerator.newProxyInstance(classLoader, new InterceptorInvocationHandler(target, interceptor), proxyClasses);
+        return createProxy(classLoader, new InterceptorInvocationHandler(target, interceptor), proxyClasses);
     }
 
     @Override
     public <T> T createInvokerProxy(final ClassLoader classLoader, final Invoker invoker, final Class<?>... proxyClasses)
     {
-        return ProxyGenerator.newProxyInstance(classLoader, new InvokerInvocationHandler(invoker), proxyClasses);
+        return createProxy(classLoader, new InvokerInvocationHandler(invoker), proxyClasses);
+    }
+
+    private <T> T createProxy(final ClassLoader classLoader, InvocationHandler invocationHandler, final Class<?>... proxyClasses)
+    {
+    	final Class<?> proxyClass = PROXY_CLASS_CACHE.getProxyClass(classLoader, proxyClasses);
+    	return ProxyGenerator.constructProxy(proxyClass, invocationHandler);
     }
 
     private static class ProxyGenerator extends AbstractProxyClassGenerator implements Opcodes
@@ -75,24 +78,46 @@
         private static final String HANDLER_NAME = "__handler";
         private static final ReentrantLock LOCK = new ReentrantLock();
 
-        public static <T> T newProxyInstance(final ClassLoader classLoader, final InvocationHandler handler, final Class<?>... classes) throws ProxyFactoryException
+        @Override
+        public Class<?> generateProxyClass(final ClassLoader classLoader, final Class<?>... proxyClasses)
         {
-            try
-            {
-                final Class<?> superclass = getSuperclass(classes);
-                if (superclass == Object.class)
-                {
-                    @SuppressWarnings("unchecked")
-					final T result = (T) Proxy.newProxyInstance(classLoader, classes, handler);
-					return result;
-                }
-                final Class<?> proxyClass = createProxy(superclass, classLoader, getImplementationMethods(classes), toInterfaces(classes));
-                return constructProxy(proxyClass, handler);
-            }
-            catch (final Exception e)
-            {
-                throw new ProxyFactoryException(e);
-            }
+        	final Class<?> superclass = getSuperclass(proxyClasses);
+        	final String proxyName = CLASSNAME_PREFIX + CLASS_NUMBER.incrementAndGet();
+			final Method[] implementationMethods = getImplementationMethods(proxyClasses);
+			final Class<?>[] interfaces = toInterfaces(proxyClasses);
+			final String classFileName = proxyName.replace('.', '/');
+
+			try
+			{
+			    return classLoader.loadClass(proxyName);
+			}
+			catch (Exception e)
+			{
+			    // no-op
+			}
+
+			LOCK.lock();
+			try
+			{
+			    try
+			    { // Try it again, another thread may have beaten this one...
+			        return classLoader.loadClass(proxyName);
+			    }
+			    catch (Exception e)
+			    {
+			        // no-op
+			    }
+
+			    final byte[] proxyBytes = generateProxy(superclass, classFileName, implementationMethods, interfaces);
+			    return Unsafe.defineClass(classLoader, superclass, proxyName, proxyBytes);
+			}
+			catch (final Exception e)
+			{
+			    throw new ProxyFactoryException(e);
+			}
+			finally {
+			    LOCK.unlock();
+			}
         }
 
         public static <T> T constructProxy(final Class<?> clazz, final java.lang.reflect.InvocationHandler handler) throws IllegalStateException
@@ -117,48 +142,6 @@
             }
         }
 
-        public static Class<?> createProxy(final Class<?> classToProxy, final ClassLoader loader, final String proxyName, final Method[] methods, final Class<?>... interfaces)
-        {
-            final String classFileName = proxyName.replace('.', '/');
-
-            try
-            {
-                return loader.loadClass(proxyName);
-            }
-            catch (Exception e)
-            {
-                // no-op
-            }
-
-            LOCK.lock();
-            try
-            {
-                try
-                { // Try it again, another thread may have beaten this one...
-                    return loader.loadClass(proxyName);
-                }
-                catch (Exception e)
-                {
-                    // no-op
-                }
-
-                final byte[] proxyBytes = generateProxy(classToProxy, classFileName, methods, interfaces);
-                return Unsafe.defineClass(loader, classToProxy, proxyName, proxyBytes);
-            }
-            catch (final Exception e)
-            {
-                throw new ProxyFactoryException(e);
-            }
-            finally {
-                LOCK.unlock();
-            }
-        }
-
-        public static Class<?> createProxy(final Class<?> classToProxy, final ClassLoader cl, final Method[] methods, final Class<?>... interfaces)
-        {
-            return createProxy(classToProxy, cl, CLASSNAME_PREFIX + CLASS_NUMBER.incrementAndGet(), methods, interfaces);
-        }
-
         public static byte[] generateProxy(final Class<?> classToProxy, final String proxyName, final Method[] methods, final Class<?>... interfaces) throws ProxyFactoryException
         {
             final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
@@ -180,15 +163,6 @@
             // push InvocationHandler fields
             cw.visitField(ACC_FINAL + ACC_PRIVATE, HANDLER_NAME, "Ljava/lang/reflect/InvocationHandler;", null, null).visitEnd();
 
-            final Map<String, List<Method>> methodMap = new HashMap<String, List<Method>>();
-
-            findMethods(classToProxy, methodMap);
-
-            for (final Class<?> anInterface : interfaces)
-            {
-                findMethods(anInterface, methodMap);
-            }
-
             for (final Method method : methods)
             {
                 processMethod(cw, method, proxyClassFileName, HANDLER_NAME);
@@ -197,53 +171,7 @@
             return cw.toByteArray();
         }
 
-        private static void findMethods(Class<?> clazz, final Map<String, List<Method>> methodMap)
-        {
-            while (clazz != null) {
-                for (final Method method : clazz.getDeclaredMethods())
-                {
-                    final int modifiers = method.getModifiers();
-
-                    if (Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers))
-                    {
-                        continue;
-                    }
-
-                    List<Method> methods = methodMap.get(method.getName());
-                    if (methods == null)
-                    {
-                        methods = new ArrayList<Method>();
-                        methods.add(method);
-                        methodMap.put(method.getName(), methods);
-                    }
-                    else if (!isOverridden(methods, method))
-                    {
-                        methods.add(method);
-                    }
-                }
-
-                clazz = clazz.getSuperclass();
-            }
-        }
-
-        private static boolean isOverridden(final List<Method> methods, final Method method)
-        {
-            for (final Method m : methods)
-            {
-                if (Arrays.equals(m.getParameterTypes(), method.getParameterTypes()))
-                {
-                    return true;
-                }
-            }
-            return false;
-        }
-
         private static void processMethod(final ClassWriter cw, final Method method, final String proxyName, final String handlerName) throws ProxyFactoryException {
-            if ("<init>".equals(method.getName()))
-            {
-                return;
-            }
-
             final Class<?> returnType = method.getReturnType();
             final Class<?>[] parameterTypes = method.getParameterTypes();
             final Class<?>[] exceptionTypes = method.getExceptionTypes();
@@ -758,12 +686,6 @@
             return className.replace('.', '/');
         }
 
-        @Override // not used ATM
-        public Class<?> generateProxyClass(final ClassLoader classLoader, final Class<?>... proxyClasses)
-        {
-            return createProxy(getSuperclass(proxyClasses), classLoader, getImplementationMethods(proxyClasses), toInterfaces(proxyClasses));
-        }
-
         private static class Unsafe
         {
             // sun.misc.Unsafe