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 }