1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.ipc;
20
21 import java.io.DataInput;
22 import java.io.DataOutput;
23 import java.io.IOException;
24 import java.lang.reflect.Method;
25 import java.util.Arrays;
26 import java.util.HashMap;
27
28 import org.apache.hadoop.classification.InterfaceAudience;
29 import org.apache.hadoop.io.Writable;
30 import org.apache.hadoop.io.WritableFactories;
31 import org.apache.hadoop.io.WritableFactory;
32
33 @InterfaceAudience.Private
34 public class ProtocolSignature implements Writable {
35 static {
36 WritableFactories.setFactory
37 (ProtocolSignature.class,
38 new WritableFactory() {
39 public Writable newInstance() { return new ProtocolSignature(); }
40 });
41 }
42
43 private long version;
44 private int[] methods = null;
45
46
47
48
49 public ProtocolSignature() {
50 }
51
52
53
54
55
56
57
58 public ProtocolSignature(long version, int[] methodHashcodes) {
59 this.version = version;
60 this.methods = methodHashcodes;
61 }
62
63 public long getVersion() {
64 return version;
65 }
66
67 public int[] getMethods() {
68 return methods;
69 }
70
71 @Override
72 public void readFields(DataInput in) throws IOException {
73 version = in.readLong();
74 boolean hasMethods = in.readBoolean();
75 if (hasMethods) {
76 int numMethods = in.readInt();
77 methods = new int[numMethods];
78 for (int i=0; i<numMethods; i++) {
79 methods[i] = in.readInt();
80 }
81 }
82 }
83
84 @Override
85 public void write(DataOutput out) throws IOException {
86 out.writeLong(version);
87 if (methods == null) {
88 out.writeBoolean(false);
89 } else {
90 out.writeBoolean(true);
91 out.writeInt(methods.length);
92 for (int method : methods) {
93 out.writeInt(method);
94 }
95 }
96 }
97
98
99
100
101
102
103
104
105 static int getFingerprint(Method method) {
106 int hashcode = method.getName().hashCode();
107 hashcode = hashcode + 31*method.getReturnType().getName().hashCode();
108 for (Class<?> type : method.getParameterTypes()) {
109 hashcode = 31*hashcode ^ type.getName().hashCode();
110 }
111 return hashcode;
112 }
113
114
115
116
117
118
119
120 private static int[] getFingerprints(Method[] methods) {
121 if (methods == null) {
122 return null;
123 }
124 int[] hashCodes = new int[methods.length];
125 for (int i = 0; i<methods.length; i++) {
126 hashCodes[i] = getFingerprint(methods[i]);
127 }
128 return hashCodes;
129 }
130
131
132
133
134
135
136
137
138
139 static int getFingerprint(Method[] methods) {
140 return getFingerprint(getFingerprints(methods));
141 }
142
143
144
145
146
147
148
149
150
151 static int getFingerprint(int[] hashcodes) {
152 Arrays.sort(hashcodes);
153 return Arrays.hashCode(hashcodes);
154
155 }
156 private static class ProtocolSigFingerprint {
157 private ProtocolSignature signature;
158 private int fingerprint;
159
160 ProtocolSigFingerprint(ProtocolSignature sig, int fingerprint) {
161 this.signature = sig;
162 this.fingerprint = fingerprint;
163 }
164 }
165
166
167
168
169 final private static HashMap<String, ProtocolSigFingerprint>
170 PROTOCOL_FINGERPRINT_CACHE =
171 new HashMap<String, ProtocolSigFingerprint>();
172
173
174
175
176
177
178
179
180 private static ProtocolSigFingerprint getSigFingerprint(
181 Class <? extends VersionedProtocol> protocol, long serverVersion) {
182 String protocolName = protocol.getName();
183 synchronized (PROTOCOL_FINGERPRINT_CACHE) {
184 ProtocolSigFingerprint sig = PROTOCOL_FINGERPRINT_CACHE.get(protocolName);
185 if (sig == null) {
186 int[] serverMethodHashcodes = getFingerprints(protocol.getMethods());
187 sig = new ProtocolSigFingerprint(
188 new ProtocolSignature(serverVersion, serverMethodHashcodes),
189 getFingerprint(serverMethodHashcodes));
190 PROTOCOL_FINGERPRINT_CACHE.put(protocolName, sig);
191 }
192 return sig;
193 }
194 }
195
196
197
198
199
200
201
202
203
204 static ProtocolSignature getProtocolSignature(
205 int clientMethodsHashCode,
206 long serverVersion,
207 Class<? extends VersionedProtocol> protocol) {
208
209 ProtocolSigFingerprint sig = getSigFingerprint(protocol, serverVersion);
210
211
212 if (clientMethodsHashCode == sig.fingerprint) {
213 return new ProtocolSignature(serverVersion, null);
214 }
215
216 return sig.signature;
217 }
218
219
220
221
222
223
224
225
226
227
228
229 @SuppressWarnings("unchecked")
230 public static ProtocolSignature getProtocolSignature(VersionedProtocol server,
231 String protocol,
232 long clientVersion, int clientMethodsHash) throws IOException {
233 Class<? extends VersionedProtocol> inter;
234 try {
235 inter = (Class<? extends VersionedProtocol>)Class.forName(protocol);
236 } catch (Exception e) {
237 throw new IOException(e);
238 }
239 long serverVersion = server.getProtocolVersion(protocol, clientVersion);
240 return ProtocolSignature.getProtocolSignature(
241 clientMethodsHash, serverVersion, inter);
242 }
243 }