1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.perfectjpattern.core.extras.delegate;
22
23 import java.lang.reflect.*;
24 import java.util.*;
25
26 import org.apache.commons.lang.*;
27 import org.perfectjpattern.core.api.extras.delegate.*;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 @SuppressWarnings("unchecked")
48 public abstract
49 class AbstractDelegator<I>
50 implements IDelegator<I>
51 {
52
53
54
55
56
57
58
59
60
61
62 protected
63 AbstractDelegator(Class aReturnClass, Class... aParameters)
64 {
65 theReturn = aReturnClass;
66 theArguments = aParameters;
67 }
68
69
70
71
72
73
74
75
76
77
78 protected
79 AbstractDelegator(Class<I> anInterface)
80 {
81 Method myMethod = findMethod(anInterface);
82
83 theReturn = myMethod.getReturnType();
84 theArguments = myMethod.getParameterTypes();
85 }
86
87
88
89
90
91
92
93
94
95
96
97
98 @SuppressWarnings("unchecked")
99 protected boolean
100 isSuitableMethod(Method aTestMethod, Class aReturnClass,
101 Class... anArguments)
102 {
103 Class[] myMethodArgs = aTestMethod.getParameterTypes();
104
105 for (int i = 0; i < myMethodArgs.length; i++)
106 {
107 Class myArgument = myMethodArgs[i];
108
109 if (!myArgument.isAssignableFrom(anArguments[i]))
110 {
111 return false;
112 }
113 }
114
115 return isValidReturn(aTestMethod, aReturnClass);
116 }
117
118
119
120
121
122
123
124
125
126 @SuppressWarnings("unchecked")
127 protected boolean
128 isValidReturn(Method aTestMethod, Class aReturnClass)
129 {
130 return (aReturnClass == null
131 || aTestMethod.getReturnType() == aReturnClass
132 || aTestMethod.getReturnType().equals(aReturnClass)
133 || aReturnClass.isAssignableFrom(aTestMethod.getReturnType()));
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147 @SuppressWarnings("unchecked")
148 protected static Method[]
149 findMethod(Class aTargetClass, String aMethodName,
150 int aNumberOfArguments)
151 {
152 Method[] myPossibilities = aTargetClass.getMethods();
153 List myHolder = new ArrayList();
154
155 for (int i = 0; i < myPossibilities.length; i++)
156 {
157 Method myPossibility = myPossibilities[i];
158
159 if (myPossibility.getName().equals(aMethodName) &&
160 myPossibility.getParameterTypes().length ==
161 aNumberOfArguments && Modifier.isPublic(myPossibility.
162 getModifiers()))
163 {
164 myHolder.add(myPossibility);
165 }
166 }
167
168 return (Method[]) myHolder.toArray(EMPTY_METHOD_ARRAY);
169 }
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185 @SuppressWarnings("unchecked")
186 protected Method
187 findMethod(Class aTargetClass, String aMethodName,
188 AbstractDelegator aDelegator)
189 throws IllegalArgumentException, UnsupportedOperationException
190 {
191 Class[] myArguments = aDelegator.getArguments();
192 Class myReturnClass = aDelegator.getReturn();
193
194 try
195 {
196 Method myReturn = aTargetClass.getMethod(aMethodName, myArguments);
197
198 Validate.isTrue(isValidReturn(myReturn, myReturnClass),
199 "Requested method returns wrong type.");
200
201 Validate.isTrue(Modifier.isPublic(myReturn.getModifiers()),
202 "Requested method is not public.");
203
204 return myReturn;
205 }
206 catch (SecurityException anException)
207 {
208
209 }
210 catch (NoSuchMethodException anException)
211 {
212
213 }
214
215 Method[] myPossibilities = findMethod(aTargetClass, aMethodName,
216 myArguments.length);
217
218 for (int i = 0; i < myPossibilities.length; i++)
219 {
220 Method myPossibility = myPossibilities[i];
221
222 if (isSuitableMethod(myPossibility, myReturnClass, myArguments))
223 {
224 return myPossibility;
225 }
226 }
227
228 throw new UnsupportedOperationException("No suitable method found.");
229 }
230
231
232
233
234
235
236
237
238
239
240
241 protected static Method
242 findMethod(Class anInterface)
243 {
244 Validate.notNull(anInterface, "'anInterface' must not be null");
245 Validate.isTrue(anInterface.isInterface(),
246 "DelegateTemplate must be constructed with an interface");
247
248 Method[] myMethods = anInterface.getMethods();
249 Method myReturn = null;
250
251 for (int i = 0; i < myMethods.length; i++)
252 {
253 Method myTest = myMethods[i];
254
255 if (Modifier.isAbstract(myTest.getModifiers()))
256 {
257 Validate.isTrue(myReturn == null, "DelegateTemplate must be " +
258 "constructed with an interface implementing exactly one " +
259 "method!");
260
261 myReturn = myTest;
262 }
263 }
264
265 Validate.notNull(myReturn, "DelegateTemplate must be constructed " +
266 "with an interface implementing exactly one method!");
267
268 return myReturn;
269 }
270
271
272
273
274
275
276
277 protected Class
278 getReturn()
279 {
280 return theReturn;
281 }
282
283
284
285
286
287
288
289 protected Class[]
290 getArguments()
291 {
292 return theArguments;
293 }
294
295
296
297
298 protected
299 class DelegateProxy
300 implements IDelegate, InvocationHandler
301 {
302
303
304
305
306
307
308
309
310
311
312
313 public
314 DelegateProxy(Object aTarget, Class aTargetClass, String aMethodName,
315 AbstractDelegator aTemplate)
316 throws UnsupportedOperationException
317 {
318 theTarget = aTarget;
319
320 Method myMethod =
321 findMethod(aTargetClass, aMethodName, aTemplate);
322 theMethod = myMethod;
323 }
324
325
326
327
328
329 public Object
330 invoke(Object aProxy, Method aMethod, Object[] anArguments)
331 {
332 return invoke(anArguments);
333 }
334
335
336
337
338
339 public Object
340 invoke(Object... anArguments)
341 throws IllegalArgumentException, UnsupportedOperationException
342 {
343 validateArgs(anArguments, getArguments());
344
345 try
346 {
347 Object myReturn = getMethod().invoke(getTarget(), anArguments);
348
349 return myReturn;
350 }
351 catch (IllegalAccessException anException)
352 {
353 throw new UnsupportedOperationException(
354 anException.getMessage());
355 }
356 catch (InvocationTargetException anException)
357 {
358 throw new UnsupportedOperationException(anException.getCause());
359 }
360 }
361
362
363
364
365
366
367
368
369
370
371
372
373
374 protected void
375 validateArgs(Object[] anArguments, Class[] anExpectedArguments)
376 throws IllegalArgumentException
377 {
378 Validate.notNull(anExpectedArguments,
379 "'anExpectedArguments' must not be null");
380
381 Validate.isTrue((anArguments == null && anExpectedArguments.length
382 == 0) || (anArguments != null && anArguments.length ==
383 anExpectedArguments.length), "Delegator required '" +
384 anExpectedArguments.length + "' arguments");
385
386 if (anArguments != null)
387 {
388 for (int i = 0; i < anArguments.length; i++)
389 {
390 Validate.isTrue(anExpectedArguments[i].isInstance(
391 anArguments[i]), "Argument '" + i + "' must be of " +
392 "type '" + anExpectedArguments[i].getName() + "'");
393 }
394 }
395 }
396
397
398
399
400
401
402
403 protected Method
404 getMethod()
405 {
406 return theMethod;
407 }
408
409
410
411
412
413
414
415 protected Object
416 getTarget()
417 {
418 return theTarget;
419 }
420
421
422
423
424 private final Method theMethod;
425 private final Object theTarget;
426 }
427
428
429
430
431 private static final Method[] EMPTY_METHOD_ARRAY = {};
432
433 private final Class theReturn;
434 private final Class[] theArguments;
435 }