1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.proxy.factory.javassist;
19
20 import javassist.CannotCompileException;
21 import javassist.CtClass;
22 import javassist.CtConstructor;
23 import javassist.CtMethod;
24 import org.apache.commons.proxy.Invocation;
25 import org.apache.commons.proxy.ProxyUtils;
26
27 import java.lang.ref.WeakReference;
28 import java.lang.reflect.Method;
29 import java.util.HashMap;
30 import java.util.Map;
31 import java.util.WeakHashMap;
32
33
34
35
36
37
38
39
40
41 public abstract class JavassistInvocation implements Invocation
42 {
43
44
45
46 private static WeakHashMap loaderToClassCache = new WeakHashMap();
47 protected final Method method;
48 protected final Object target;
49 protected final Object[] arguments;
50
51
52
53
54
55 private static String createCastExpression( Class type, String objectToCast )
56 {
57 if( !type.isPrimitive() )
58 {
59 return "( " + ProxyUtils.getJavaClassName( type ) + " )" + objectToCast;
60 }
61 else
62 {
63 return "( ( " + ProxyUtils.getWrapperClass( type ).getName() + " )" + objectToCast + " )." +
64 type.getName() + "Value()";
65 }
66 }
67
68 private static Class createInvocationClass( ClassLoader classLoader, Method interfaceMethod )
69 throws CannotCompileException
70 {
71 Class invocationClass;
72 final CtClass ctClass = JavassistUtils.createClass(
73 getSimpleName( interfaceMethod.getDeclaringClass() ) + "_" + interfaceMethod.getName() +
74 "_invocation",
75 JavassistInvocation.class );
76 final CtConstructor constructor = new CtConstructor(
77 JavassistUtils.resolve( new Class[]{ Method.class, Object.class, Object[].class } ),
78 ctClass );
79 constructor.setBody( "{\n\tsuper($$);\n}" );
80 ctClass.addConstructor( constructor );
81 final CtMethod proceedMethod = new CtMethod( JavassistUtils.resolve( Object.class ), "proceed",
82 JavassistUtils.resolve( new Class[0] ), ctClass );
83 final Class[] argumentTypes = interfaceMethod.getParameterTypes();
84 final StringBuffer proceedBody = new StringBuffer( "{\n" );
85 if( !Void.TYPE.equals( interfaceMethod.getReturnType() ) )
86 {
87 proceedBody.append( "\treturn " );
88 if( interfaceMethod.getReturnType().isPrimitive() )
89 {
90 proceedBody.append( "new " );
91 proceedBody.append( ProxyUtils.getWrapperClass( interfaceMethod.getReturnType() ).getName() );
92 proceedBody.append( "( " );
93 }
94 }
95 else
96 {
97 proceedBody.append( "\t" );
98 }
99 proceedBody.append( "( (" );
100 proceedBody.append( ProxyUtils.getJavaClassName( interfaceMethod.getDeclaringClass() ) );
101 proceedBody.append( " )target )." );
102 proceedBody.append( interfaceMethod.getName() );
103 proceedBody.append( "(" );
104 for( int i = 0; i < argumentTypes.length; ++i )
105 {
106 final Class argumentType = argumentTypes[i];
107 proceedBody.append( createCastExpression( argumentType, "arguments[" + i + "]" ) );
108 if( i != argumentTypes.length - 1 )
109 {
110 proceedBody.append( ", " );
111 }
112 }
113 if( !Void.TYPE.equals( interfaceMethod.getReturnType() ) && interfaceMethod.getReturnType().isPrimitive() )
114 {
115 proceedBody.append( ") );\n" );
116 }
117 else
118 {
119 proceedBody.append( ");\n" );
120 }
121 if( Void.TYPE.equals( interfaceMethod.getReturnType() ) )
122 {
123 proceedBody.append( "\treturn null;\n" );
124 }
125 proceedBody.append( "}" );
126 final String body = proceedBody.toString();
127 proceedMethod.setBody( body );
128 ctClass.addMethod( proceedMethod );
129 invocationClass = ctClass.toClass( classLoader );
130 return invocationClass;
131 }
132
133 private static Map getClassCache( ClassLoader classLoader )
134 {
135 Map cache = ( Map ) loaderToClassCache.get( classLoader );
136 if( cache == null )
137 {
138 cache = new HashMap();
139 loaderToClassCache.put( classLoader, cache );
140 }
141 return cache;
142 }
143
144
145
146
147
148
149
150
151
152 synchronized static Class getMethodInvocationClass( ClassLoader classLoader,
153 Method interfaceMethod )
154 throws CannotCompileException
155 {
156 final Map classCache = getClassCache( classLoader );
157 final String key = toClassCacheKey( interfaceMethod );
158 final WeakReference invocationClassRef = ( WeakReference ) classCache.get( key );
159 Class invocationClass;
160 if( invocationClassRef == null )
161 {
162 invocationClass = createInvocationClass( classLoader, interfaceMethod );
163 classCache.put( key, new WeakReference( invocationClass ) );
164 }
165 else
166 {
167 synchronized( invocationClassRef )
168 {
169 invocationClass = ( Class ) invocationClassRef.get();
170 if( invocationClass == null )
171 {
172 invocationClass = createInvocationClass( classLoader, interfaceMethod );
173 classCache.put( key, new WeakReference( invocationClass ) );
174 }
175 }
176 }
177 return invocationClass;
178 }
179
180 private static String getSimpleName( Class c )
181 {
182 final String name = c.getName();
183 final int ndx = name.lastIndexOf( '.' );
184 return ndx == -1 ? name : name.substring( ndx + 1 );
185 }
186
187 private static String toClassCacheKey( Method method )
188 {
189 return String.valueOf( method );
190 }
191
192
193
194
195
196 public JavassistInvocation( Method method, Object target, Object[] arguments )
197 {
198 this.method = method;
199 this.target = target;
200 this.arguments = arguments;
201 }
202
203
204
205
206
207 public Object[] getArguments()
208 {
209 return arguments;
210 }
211
212 public Method getMethod()
213 {
214 return method;
215 }
216
217 public Object getProxy()
218 {
219 return target;
220 }
221 }
222