001 package com.mockrunner.struts;
002
003 import java.lang.reflect.Method;
004 import java.util.Arrays;
005 import java.util.HashSet;
006 import java.util.Iterator;
007 import java.util.Set;
008
009 import net.sf.cglib.proxy.Enhancer;
010 import net.sf.cglib.proxy.MethodInterceptor;
011 import net.sf.cglib.proxy.MethodProxy;
012
013 import com.mockrunner.util.common.MethodUtil;
014
015 /**
016 * Helper class to generate CGLib proxies. Not meant for application use.
017 */
018 public class DynamicMockProxyGenerator
019 {
020 private Class proxiedClass;
021 private Object delegate;
022 private Class additionalInterface;
023 private Set methodsToIntercept;
024 private Set methodsToDuplicate;
025
026 public DynamicMockProxyGenerator(Class proxiedClass, Object delegate, Method[] methodsToIntercept, Method[] methodsToDuplicate)
027 {
028 this(proxiedClass, delegate, methodsToIntercept, methodsToDuplicate, null);
029 }
030
031 public DynamicMockProxyGenerator(Class proxiedClass, Object delegate, Method[] methodsToIntercept, Method[] methodsToDuplicate, Class additionalInterface)
032 {
033 this.proxiedClass = proxiedClass;
034 this.delegate = delegate;
035 this.additionalInterface = additionalInterface;
036 this.methodsToIntercept = new HashSet();
037 this.methodsToIntercept.addAll(Arrays.asList(methodsToIntercept));
038 this.methodsToDuplicate = new HashSet();
039 this.methodsToDuplicate.addAll(Arrays.asList(methodsToDuplicate));
040 }
041
042 public Object createProxy()
043 {
044 Enhancer enhancer = new Enhancer();
045 enhancer.setSuperclass(proxiedClass);
046 if(null != additionalInterface)
047 {
048 enhancer.setInterfaces(new Class[] { additionalInterface });
049 }
050 Method[] targetInterceptMethods = getActualTargetMethods(delegate, methodsToIntercept);
051 Method[] targetDuplicateMethods = getActualTargetMethods(delegate, methodsToDuplicate);
052 enhancer.setCallback(new DelegatingInterceptor(delegate, targetInterceptMethods, targetDuplicateMethods));
053 return enhancer.create();
054 }
055
056 private Method[] getActualTargetMethods(Object delegate, Set providedMethods)
057 {
058 Method[] methods = delegate.getClass().getMethods();
059 Set actualMethods = new HashSet();
060 Set tempProvidedMethods = new HashSet(providedMethods);
061 for(int ii = 0; ii < methods.length; ii++)
062 {
063 findAndAddMethod(tempProvidedMethods, methods[ii], actualMethods);
064 }
065 return (Method[])actualMethods.toArray(new Method[actualMethods.size()]);
066 }
067
068 private void findAndAddMethod(Set providedMethods, Method currentMethod, Set actualMethods)
069 {
070 Iterator iterator = providedMethods.iterator();
071 while(iterator.hasNext())
072 {
073 Method currentMethodToIntercept = (Method)iterator.next();
074 if(MethodUtil.areMethodsEqual(currentMethod, currentMethodToIntercept))
075 {
076 actualMethods.add(currentMethod);
077 iterator.remove();
078 return;
079 }
080 }
081 }
082
083 private static class DelegatingInterceptor implements MethodInterceptor
084 {
085 private Object delegate;
086 private Method[] methodsToIntercept;
087 private Method[] methodsToDuplicate;
088
089 public DelegatingInterceptor(Object delegate, Method[] methodsToIntercept, Method[] methodsToDuplicate)
090 {
091 this.delegate = delegate;
092 this.methodsToIntercept = methodsToIntercept;
093 this.methodsToDuplicate = methodsToDuplicate;
094 }
095
096 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable
097 {
098 for(int ii = 0; ii < methodsToIntercept.length; ii++)
099 {
100 if(MethodUtil.areMethodsEqual(method, methodsToIntercept[ii]))
101 {
102 return methodsToIntercept[ii].invoke(delegate, args);
103 }
104 }
105 for(int ii = 0; ii < methodsToDuplicate.length; ii++)
106 {
107 if(MethodUtil.areMethodsEqual(method, methodsToDuplicate[ii]))
108 {
109 methodsToDuplicate[ii].invoke(delegate, args);
110 }
111 }
112 return proxy.invokeSuper(obj, args);
113 }
114 }
115 }