1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.river.reggie.proxy;
19
20 import java.io.ByteArrayOutputStream;
21 import java.io.DataOutputStream;
22 import java.io.IOException;
23 import java.io.InvalidObjectException;
24 import java.io.ObjectInputStream;
25 import java.io.ObjectOutputStream;
26 import java.io.Serializable;
27 import java.lang.reflect.Proxy;
28 import java.rmi.MarshalException;
29 import java.rmi.UnmarshalException;
30 import java.security.DigestOutputStream;
31 import java.security.MessageDigest;
32 import java.security.NoSuchAlgorithmException;
33 import java.util.StringTokenizer;
34 import org.apache.river.api.io.AtomicSerial;
35 import org.apache.river.api.io.AtomicSerial.GetArg;
36 import org.apache.river.proxy.CodebaseProvider;
37 import org.apache.river.proxy.MarshalledWrapper;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 @AtomicSerial
54 public class ServiceType implements Serializable {
55
56 private static final long serialVersionUID = 2L;
57 private static final ServiceType[] empty = {};
58
59
60
61
62
63
64
65 private final String name;
66
67
68
69
70
71 protected final long hash;
72
73
74
75
76
77 protected final ServiceType superclass;
78
79
80
81
82
83
84
85 protected final ServiceType[] interfaces;
86
87 private static long check(GetArg arg) throws IOException {
88 String name = (String) arg.get("name", null);
89 if (name == null)
90 throw new InvalidObjectException("name cannot be null");
91 long hash = arg.get("hash", 0L);
92 if (hash == 0) {
93 try {
94 hash = computeHash(name);
95 } catch (Exception e) {
96 throw new UnmarshalException("unable to calculate the type"
97 + " hash for " + name, e);
98 }
99 }
100 Object superclass = arg.get("superclass", null);
101 if (superclass != null && !(superclass instanceof ServiceType)){
102 throw new InvalidObjectException(
103 "superclass must be instances of ServiceType");
104 }
105 Object interfaces = arg.get("interfaces", null);
106
107 if (interfaces != null && !(interfaces instanceof ServiceType[])){
108 throw new InvalidObjectException(
109 "interfaces must be instances of ServiceType[]");
110 }
111 return hash;
112 }
113
114 ServiceType(GetArg arg) throws IOException {
115 this(arg,check(arg));
116 }
117
118 private ServiceType(GetArg arg, long hash) throws IOException{
119 name = (String) arg.get("name", null);
120 this.hash = hash;
121 superclass = (ServiceType) arg.get("superclass", null);
122 ServiceType [] interfaces = (ServiceType[]) arg.get("interfaces", null);
123 if (interfaces != null) interfaces = interfaces.clone();
124 this.interfaces = interfaces;
125 }
126
127
128
129
130
131
132 protected transient ServiceType replacement;
133
134
135
136
137 private transient boolean integrity = false;
138
139
140 public ServiceType(Class clazz,
141 ServiceType superclass,
142 ServiceType[] interfaces)
143 throws MarshalException
144 {
145 if (!Proxy.isProxyClass(clazz)) {
146 name = clazz.getName();
147 } else if (interfaces.length == 0) {
148 name = ";";
149 } else {
150 StringBuffer buf = new StringBuffer();
151 for (int i = 0; i < interfaces.length; i++) {
152 buf.append(';');
153 buf.append(interfaces[i].getName());
154 }
155 name = buf.toString();
156 }
157 this.superclass = superclass;
158 if (clazz != Object.class){
159 this.interfaces = interfaces;
160 } else {
161 this.interfaces = null;
162 }
163 try {
164 hash = computeHash(name);
165 } catch (Exception e) {
166 throw new MarshalException("unable to calculate the type hash for "
167 + name, e);
168 }
169 }
170
171
172
173
174
175 private ServiceType(ServiceType stype) {
176 name = stype.name;
177 hash = stype.hash;
178 superclass = stype.superclass == null ? null : stype.superclass.getReplacement();
179 interfaces = null;
180 }
181
182
183
184
185
186 public String getName() {
187 return name;
188 }
189
190
191 public ServiceType getSuperclass() {
192 return superclass;
193 }
194
195
196 public ServiceType[] getInterfaces() {
197 if (interfaces != null)
198 return interfaces;
199 return empty;
200 }
201
202
203 public synchronized ServiceType getReplacement() {
204 if (replacement == null)
205 replacement = new ServiceType(this);
206 return replacement;
207 }
208
209
210
211
212
213 private boolean isAssignableFrom(ServiceType[] ifaces)
214 {
215 for (int i = ifaces.length; --i >= 0; ) {
216 if (hash == ifaces[i].hash ||
217 isAssignableFrom(ifaces[i].interfaces))
218 return true;
219 }
220 return false;
221 }
222
223
224 public boolean isInterface() {
225 return (superclass == null && interfaces != null);
226 }
227
228
229
230
231
232
233
234
235
236
237 public boolean isAssignableFrom(ServiceType cls) {
238 if (hash == cls.hash)
239 return true;
240 if (isInterface()) {
241 if (cls.interfaces != null && isAssignableFrom(cls.interfaces))
242 return true;
243 for (ServiceType sup = cls.superclass;
244 sup != null && sup.interfaces != null;
245 sup = sup.superclass)
246 {
247 if (isAssignableFrom(sup.interfaces))
248 return true;
249 }
250 } else {
251 for (ServiceType sup = cls.superclass;
252 sup != null;
253 sup = sup.superclass)
254 {
255 if (hash == sup.hash)
256 return true;
257 }
258 }
259 return false;
260 }
261
262
263
264
265
266
267
268 public Class toClass(String codebase)
269 throws IOException, ClassNotFoundException
270 {
271 if (name.charAt(0) != ';') {
272 return CodebaseProvider.loadClass(
273 codebase, name, null, integrity, null);
274 }
275 StringTokenizer st = new StringTokenizer(name, ";");
276 String[] ifs = new String[st.countTokens()];
277 for (int i = 0; i < ifs.length; i++) {
278 ifs[i] = st.nextToken();
279 }
280 return CodebaseProvider.loadProxyClass(
281 codebase, ifs, null, integrity, null);
282 }
283
284
285
286
287
288
289
290
291 @Override
292 public boolean equals(Object o) {
293 if (this == o) return true;
294 if (!(o instanceof ServiceType))
295 return false;
296 ServiceType t = (ServiceType) o;
297 return hash == t.hash;
298 }
299
300
301
302
303
304 @Override
305 public int hashCode() {
306 return (int) (hash ^ (hash >>> 32));
307 }
308
309
310 @Override
311 public String toString() {
312 return getClass() + "[name=" + getName() + "]";
313 }
314
315
316
317
318
319
320
321
322 private static long computeHash(String name) throws IOException, NoSuchAlgorithmException
323 {
324 long hash = 0;
325 MessageDigest md = MessageDigest.getInstance("SHA");
326 DataOutputStream out = new DataOutputStream(
327 new DigestOutputStream(new ByteArrayOutputStream(127),md));
328 out.writeUTF(name);
329 out.flush();
330 byte[] digest = md.digest();
331 for (int i = Math.min(8, digest.length); --i >= 0; ) {
332 hash += ((long) (digest[i] & 0xFF)) << (i * 8);
333 }
334 return hash;
335 }
336
337 private void writeObject(ObjectOutputStream out) throws IOException {
338 out.defaultWriteObject();
339 }
340
341
342
343
344
345
346 private void readObject(ObjectInputStream in)
347 throws IOException, ClassNotFoundException
348 {
349 in.defaultReadObject();
350 if (name == null)
351 throw new InvalidObjectException("name cannot be null");
352 integrity = MarshalledWrapper.integrityEnforced(in);
353 if (hash == 0) {
354 throw new InvalidObjectException("hash cannot be zero");
355
356
357
358
359
360
361
362 }
363 }
364
365
366
367
368 private void readObjectNoData() throws InvalidObjectException {
369 throw new InvalidObjectException("no data");
370 }
371
372 }
373