1 package org.codehaus.groovy.runtime;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.InvocationTargetException;
5 import java.lang.reflect.Method;
6
7 /***
8 * This class is a general adapter to map a call to an Java interface
9 * to a given delegate.
10 * <p>
11 * @author Ben Yu
12 * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
13 */
14 public abstract class ConversionHandler implements InvocationHandler {
15 private Object delegate;
16
17 /***
18 * Creates a ConversionHandler with an deleagte.
19 * @param delegate the delegate
20 * @throws IllegalArgumentException if the given delegate is null
21 */
22 public ConversionHandler(Object delegate) {
23 if (delegate==null) throw new IllegalArgumentException("delegate must not be null");
24 this.delegate = delegate;
25 }
26
27 /***
28 * gets the delegate.
29 * @return the delegate
30 */
31 public Object getDelegate(){
32 return delegate;
33 }
34
35 /***
36 * This method is a default implementation for the invoke method
37 * given in Invocationhandler. Any call to an method with an
38 * declaring class that is not Object is redirected to invokeCustom.
39 * Methods like tostring, equals and hashcode are called on the class
40 * itself instead of the delegate. It is better to overwrite the
41 * invokeCustom method where the Object related methods are filtered out.
42 *
43 * @see #invokeCustom(Object, Method, Object[])
44 * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
45 *
46 * @param proxy the proxy
47 * @param method the method
48 * @param args the arguments
49 * @return the result of the invocation by method or delegate
50 * @throws Throwable any exception caused by the delegate or the method
51 */
52 public Object invoke(Object proxy, Method method, Object[] args)
53 throws Throwable {
54 if(!isObjectMethod(method)){
55 return invokeCustom(proxy,method,args);
56 }
57 try {
58 return method.invoke(this, args);
59 } catch (InvocationTargetException ite) {
60 throw ite.getTargetException();
61 }
62 }
63
64 /***
65 * This method is called for all Methods not defined on Object.
66 * The delegate should be called here.
67 *
68 * @param proxy the proxy
69 * @param method the method
70 * @param args the arguments
71 * @return the result of the invocation of the delegate
72 * @throws Throwable any exception causes by the delegate
73 * @see #invoke(Object, Method, Object[])
74 * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
75 *
76 */
77 public abstract Object invokeCustom(Object proxy, Method method, Object[] args) throws Throwable;
78
79 /***
80 * Indicates whether some other object is "equal to" this one.
81 * The delegate is used if the class of the parameter and the
82 * current class are equal. In other cases the method will return
83 * false. The exact class is here used, if inheritance is needed,
84 * this method must be overwritten.
85 *
86 * @see java.lang.Object#equals(java.lang.Object)
87 */
88 public boolean equals(Object obj) {
89 if (obj!=null && obj.getClass()==this.getClass()){
90 return (((ConversionHandler)obj).getDelegate()).equals(obj);
91 } else {
92 return false;
93 }
94 }
95
96 /***
97 * Returns a hash code value for the delegate.
98 * @see java.lang.Object#hashCode()
99 */
100 public int hashCode() {
101 return delegate.hashCode();
102 }
103
104 /***
105 * Returns a String version of the delegate.
106 * @see java.lang.Object#toString()
107 */
108 public String toString() {
109 return delegate.toString();
110 }
111
112 private static boolean isObjectMethod(Method mtd){
113 return mtd.getDeclaringClass().equals(Object.class);
114 }
115 }