1
2
3
4
5
6
7
8
9 package ca.uhn.cache.util;
10
11 import java.lang.reflect.InvocationTargetException;
12 import java.lang.reflect.Method;
13 import java.text.MessageFormat;
14
15
16 /***
17 * Implements double-dispatching using reflection.
18 *
19 * @author <a href="mailto:alexei.guevara@uhn.on.ca">Alexei Guevara</a>
20 * @version $Revision: 1.1 $ updated on $Date: 2005/01/24 22:51:49 $ by $Author: bryan_tripp $
21 */
22 public final class MultiDispatch {
23
24 /***
25 */
26 private MultiDispatch() {
27 }
28
29 /***
30 * Invoked a method in a callee using "double dispatche".
31 *
32 * class A {}
33 * class A1 extends A {}
34 * class A2 extends A {}
35 *
36 * class Callee {
37 * Object methodA( A1 a1) {};
38 * Object methodA( A2 a2) {};
39 * }
40 *
41 * A a = new A1();
42 *
43 * Callee callee = new Callee();
44 *
45 * //the next statement will invoke Callee.methodA( A1 a1 )
46 * Object retVal = DoubleDispatch.dispatch( callee, "methodA", a );
47 *
48 * @param theCallee The callee instance.
49 * @param theCalleeMethodName The callee method name.
50 * @param theArg1 The caller.
51 * @return The return value of the called method.
52 *
53 * @throws Throwable ...
54 *
55 * @precondition theCallee has method with signature $theCalleeMethodName( theArg1.class )
56 */
57 public static final Object dispatch( Object theCallee, String theCalleeMethodName, Object theArg1 )
58 throws Throwable {
59
60
61 Object retVal = null;
62
63 Class arg1Clazz = theArg1.getClass();
64 Class calleeClazz = theCallee.getClass();
65
66 try {
67 Method calleeMethod = findMethod( calleeClazz, theCalleeMethodName, new Class[] { arg1Clazz } );
68 if ( calleeMethod == null ) {
69 throw new NoSuchMethodException(
70 MessageFormat.format(
71 "* {0}.{1}( {2} )",
72 new Object[] { calleeClazz.getName(), theCalleeMethodName, arg1Clazz.getName() } ) );
73 }
74 try {
75 retVal = calleeMethod.invoke( theCallee, new Object[] { theArg1 } );
76 }
77 catch (IllegalArgumentException e) {
78 throw e;
79 }
80 catch (IllegalAccessException e) {
81 throw e;
82 }
83 catch (InvocationTargetException e) {
84 throw e.getCause();
85 }
86 }
87 catch (SecurityException e) {
88 throw e;
89 }
90 catch (NoSuchMethodException e) {
91 throw e;
92 }
93
94 return retVal;
95 }
96
97 /***
98 * @param theCallee The callee instance.
99 * @param theCalleeMethodName The callee method name.
100 * @param theArg1 The arg 1.
101 * @param theArg2 The arg 2.
102 * @return The return value of the called method.
103 *
104 * @throws Throwable ...
105 *
106 * @precondition theCallee has method with signature $theCalleeMethodName( theArg1.class )
107 */
108 public static final Object dispatch( Object theCallee, String theCalleeMethodName, Object theArg1, Object theArg2 )
109 throws Throwable {
110
111
112 Object retVal = null;
113
114 Class arg1Clazz = (theArg1==null) ? (null) : (theArg1.getClass());
115 Class arg2Clazz = (theArg2==null) ? (null) : (theArg2.getClass());
116 Class calleeClazz = theCallee.getClass();
117
118 try {
119 Method calleeMethod = findMethod( calleeClazz, theCalleeMethodName, new Class[] { arg1Clazz, arg2Clazz } );
120 if ( calleeMethod == null ) {
121 throw new NoSuchMethodException(
122 MessageFormat.format(
123 "* {0}.{1}( {2}, {3} )",
124 new Object[] {
125 calleeClazz.getName(),
126 theCalleeMethodName,
127 (arg1Clazz==null) ? ("*") : (arg1Clazz.getName()),
128 (arg2Clazz==null) ? ("*") : (arg2Clazz.getName())} ) );
129 }
130 try {
131 retVal = calleeMethod.invoke( theCallee, new Object[] { theArg1, theArg2 } );
132 }
133 catch (IllegalArgumentException e) {
134 throw e;
135 }
136 catch (IllegalAccessException e) {
137 throw e;
138 }
139 catch (InvocationTargetException e) {
140 throw e.getCause();
141 }
142 }
143 catch (SecurityException e) {
144 throw e;
145 }
146 catch (NoSuchMethodException e) {
147 throw e;
148 }
149
150 return retVal;
151 }
152
153 private static Method findMethod( Class theClazz, String theMethodName, Class[] theParameterTypes ) {
154 Method retVal = null;
155
156 Method[] methods = theClazz.getMethods();
157 methods:for (int i = 0; i < methods.length; i++) {
158 Method method = methods[i];
159
160 Class[] methodParamTypes = method.getParameterTypes();
161
162 if ( !method.getName().equals( theMethodName ) ) {
163 continue methods;
164 }
165
166 if ( method.getParameterTypes().length != theParameterTypes.length ) {
167 continue methods;
168 }
169
170 parameters:for (int j = 0; j < methodParamTypes.length; j++) {
171 if ( theParameterTypes[j] == null ) {
172 continue;
173 }
174
175 Class methodParamType = methodParamTypes[j];
176 if ( !theParameterTypes[j].equals( methodParamType ) ) {
177 continue methods;
178 }
179 }
180 retVal = method;
181 break;
182 }
183
184 return retVal;
185 }
186
187 }