1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package jgroup.relacs.rmi;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.DataOutputStream;
23 import java.io.IOException;
24 import java.lang.reflect.Method;
25 import java.security.AccessController;
26 import java.security.DigestOutputStream;
27 import java.security.MessageDigest;
28 import java.security.NoSuchAlgorithmException;
29 import java.security.PrivilegedAction;
30 import java.util.HashMap;
31 import java.util.Iterator;
32
33 import jgroup.core.InternalGMIListener;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public final class ServerMethodTable
49 {
50
51
52
53
54 private HashMap table;
55 private HashMap invertedTable;
56 private HashMap serverTable;
57
58
59
60
61
62
63
64
65
66
67 public ServerMethodTable()
68 {
69 table = new HashMap();
70 invertedTable = new HashMap();
71 serverTable = new HashMap();
72 }
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 public void addMethods(Object server, Class gmiListenerClass)
90 {
91
92
93
94
95 Class[] interfaces = server.getClass().getInterfaces();
96 for (int i = 0; i < interfaces.length; i++) {
97 if (gmiListenerClass.isAssignableFrom(interfaces[i])) {
98 Method methods[] = interfaces[i].getMethods();
99 for (int j = 0; j < methods.length; j++) {
100
101
102
103
104
105
106
107
108 if (gmiListenerClass.equals(InternalGMIListener.class)) {
109 Class retType = methods[j].getReturnType();
110 if (!(retType.toString().equals("void") || retType.equals(Object.class))) {
111 throw new IllegalArgumentException(
112 "Return type for methods in the internal interfaces must be Object or void:\n"
113 + methods[j]);
114 }
115 }
116 String name = getMethodNameAndDescriptor(methods[j]);
117 Long hashLong = new Long(computeInfo(methods[j]));
118 table.put(hashLong, methods[j]);
119 serverTable.put(hashLong, server);
120 invertedTable.put(name, hashLong);
121 }
122 }
123 }
124 }
125
126
127
128
129
130 public Method get(long hash)
131 {
132 Long hashLong = new Long(hash);
133 return (Method) table.get(hashLong);
134 }
135
136
137
138
139
140 public long get(Method m)
141 {
142 Long hashLong = (Long) invertedTable.get(getMethodNameAndDescriptor(m));
143 return hashLong.longValue();
144 }
145
146
147
148
149
150
151 public Object getServer(long hash)
152 {
153 return serverTable.get(new Long(hash));
154 }
155
156
157
158
159
160
161 public String toString()
162 {
163 StringBuilder buf = new StringBuilder("ServerMethodTable[");
164 for (Iterator iter = table.keySet().iterator(); iter.hasNext();) {
165 Long hash = (Long) iter.next();
166 buf.append("\n");
167 buf.append(hash);
168 buf.append(" -> ");
169 buf.append(((Method) table.get(hash)).getName());
170 buf.append("; server=");
171 buf.append(serverTable.get(hash).getClass().getName());
172 }
173 buf.append("]");
174 return buf.toString();
175 }
176
177
178
179
180
181
182
183
184
185
186 static long computeInfo(final Method method)
187 {
188
189
190
191
192
193 AccessController.doPrivileged(new PrivilegedAction() {
194 public Object run() {
195 method.setAccessible(true);
196 return null;
197 }
198 });
199
200 return computeHash(method);
201 }
202
203
204
205
206
207
208 static long computeHash(Method m)
209 {
210 long hash = 0;
211 ByteArrayOutputStream sink = new ByteArrayOutputStream(127);
212 try {
213 MessageDigest md = MessageDigest.getInstance("SHA");
214 DataOutputStream out = new DataOutputStream(
215 new DigestOutputStream(sink, md));
216
217 String s = getMethodNameAndDescriptor(m);
218
219 out.writeUTF(s);
220
221
222 out.flush();
223 byte hasharray[] = md.digest();
224 for (int i = 0; i < Math.min(8, hasharray.length); i++) {
225 hash += ((long) (hasharray[i] & 0xFF)) << (i * 8);
226 }
227 } catch (IOException ignore) {
228
229 hash = -1;
230 } catch (NoSuchAlgorithmException complain) {
231 throw new SecurityException(complain.getMessage());
232 }
233 return hash;
234 }
235
236
237
238
239
240
241
242
243
244
245 static String getMethodNameAndDescriptor(Method m)
246 {
247 StringBuilder desc = new StringBuilder(m.getName());
248 desc.append("(");
249 Class[] paramTypes = m.getParameterTypes();
250 for (int i = 0; i < paramTypes.length; i++) {
251 desc.append(getTypeDescriptor(paramTypes[i]));
252 }
253 desc.append(")");
254 Class returnType = m.getReturnType();
255 if (returnType == void.class) {
256 desc.append("V");
257 } else {
258 desc.append(getTypeDescriptor(returnType));
259 }
260 return desc.toString();
261 }
262
263
264
265
266
267 static String getTypeDescriptor(Class type)
268 {
269 if (type.isPrimitive()) {
270 if (type == int.class) {
271 return "I";
272 } else if (type == boolean.class) {
273 return "Z";
274 } else if (type == byte.class) {
275 return "B";
276 } else if (type == char.class) {
277 return "C";
278 } else if (type == short.class) {
279 return "S";
280 } else if (type == long.class) {
281 return "J";
282 } else if (type == float.class) {
283 return "F";
284 } else if (type == double.class) {
285 return "D";
286 } else if (type == void.class) {
287 return "V";
288 } else {
289 throw new Error("unrecognized primitive type: " + type);
290 }
291 } else if (type.isArray()) {
292
293
294
295
296
297
298
299 return type.getName().replace('.', '/');
300 } else {
301 return "L" + type.getName().replace('.', '/') + ";";
302 }
303 }
304
305 }