1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.river.discovery;
20
21 import java.lang.reflect.Method;
22 import java.util.Collections;
23 import java.util.Iterator;
24 import java.util.Set;
25 import java.util.HashSet;
26 import net.jini.core.constraint.ConnectionAbsoluteTime;
27 import net.jini.core.constraint.ConnectionRelativeTime;
28 import net.jini.core.constraint.ConstraintAlternatives;
29 import net.jini.core.constraint.InvocationConstraint;
30 import net.jini.core.constraint.InvocationConstraints;
31 import net.jini.core.constraint.MethodConstraints;
32 import net.jini.io.UnsupportedConstraintException;
33
34
35
36
37
38
39
40
41
42
43
44 public class DiscoveryConstraints {
45
46
47 public static final Method multicastRequestMethod;
48
49 public static final Method multicastAnnouncementMethod;
50
51 public static final Method unicastDiscoveryMethod;
52 static {
53 try {
54 multicastRequestMethod = DiscoveryConstraints.class.getMethod(
55 "multicastRequest", (Class<?>[]) null);
56 multicastAnnouncementMethod = DiscoveryConstraints.class.getMethod(
57 "multicastAnnouncement", (Class<?>[]) null);
58 unicastDiscoveryMethod = DiscoveryConstraints.class.getMethod(
59 "unicastDiscovery", (Class<?>[]) null);
60 } catch (NoSuchMethodException e) {
61 throw new AssertionError(e);
62 }
63 }
64
65 private static final Set<DiscoveryProtocolVersion> supportedProtocols = new HashSet<DiscoveryProtocolVersion>(2);
66 static {
67 supportedProtocols.add(DiscoveryProtocolVersion.ONE);
68 supportedProtocols.add(DiscoveryProtocolVersion.TWO);
69 }
70
71 private final InvocationConstraints unfulfilled;
72 private final Set<DiscoveryProtocolVersion> protocolVersions;
73 private final int preferredProtocolVersion;
74 private final ConnectionAbsoluteTime connectionAbsoluteTime;
75 private final MulticastMaxPacketSize maxPacketSize;
76 private final MulticastTimeToLive timeToLive;
77 private final UnicastSocketTimeout socketTimeout;
78 private final int hashcode;
79
80 @Override
81 public int hashCode() {
82 return hashcode;
83 }
84
85 @Override
86 public boolean equals(Object o){
87 if ( o == null ) return false;
88 if ( o == this ) return true;
89 if ( o.hashCode() != hashcode) return false;
90 if ( o instanceof DiscoveryConstraints) {
91 DiscoveryConstraints that = (DiscoveryConstraints) o;
92 if ( unfulfilled != null ) {
93 if ( !unfulfilled.equals(that.unfulfilled) ) return false;
94 } else if ( unfulfilled != that.unfulfilled) return false;
95 if ( protocolVersions != null ) {
96 if ( !protocolVersions.equals(that.protocolVersions) ) return false;
97 } else if ( protocolVersions!= that.protocolVersions) return false;
98 if ( connectionAbsoluteTime != null ) {
99 if ( !connectionAbsoluteTime.equals(that.connectionAbsoluteTime) ) return false;
100 } else if ( connectionAbsoluteTime != that.connectionAbsoluteTime) return false;
101 if (preferredProtocolVersion != that.preferredProtocolVersion) return false;
102 if ( maxPacketSize != null ) {
103 if ( !maxPacketSize.equals(that.maxPacketSize) ) return false;
104 } else if ( maxPacketSize != that.maxPacketSize) return false;
105 if ( timeToLive != null ) {
106 if ( !timeToLive.equals(that.timeToLive) ) return false;
107 } else if ( timeToLive != that.timeToLive) return false;
108 if ( socketTimeout != null ) {
109 if ( !socketTimeout.equals(that.socketTimeout) ) return false;
110 } else if ( socketTimeout != that.socketTimeout) return false;
111 return true;
112 }
113 return false;
114 }
115
116
117
118
119
120 public static void multicastRequest() {
121 }
122
123
124
125
126
127 public static void multicastAnnouncement() {
128 }
129
130
131
132
133
134 public static void unicastDiscovery() {
135 }
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154 public static DiscoveryConstraints process(
155 InvocationConstraints constraints)
156 throws UnsupportedConstraintException
157 {
158 return new DiscoveryConstraints(constraints);
159 }
160
161 private DiscoveryConstraints(InvocationConstraints constraints)
162 throws UnsupportedConstraintException
163 {
164 unfulfilled = new InvocationConstraints(
165 getUnfulfilled(constraints.requirements()),
166 getUnfulfilled(constraints.preferences()));
167
168 ConstraintReducer<DiscoveryProtocolVersion> cr =
169 new ConstraintReducer<DiscoveryProtocolVersion>(DiscoveryProtocolVersion.class);
170 protocolVersions = cr.reduce(
171 new InvocationConstraints(constraints.requirements(), null));
172 if (!protocolVersions.isEmpty() &&
173 intersect(protocolVersions, supportedProtocols).isEmpty())
174 {
175 throw new UnsupportedConstraintException(
176 "no supported protocols: " + protocolVersions);
177 }
178 preferredProtocolVersion = chooseProtocolVersion(
179 protocolVersions, cr.reduce(constraints), unfulfilled);
180 Set<MulticastMaxPacketSize> mmps
181 = new MulticastMaxPacketSizeReducer().reduce(constraints);
182 maxPacketSize = mmps.isEmpty() ? null : getElement(mmps);
183 Set<MulticastTimeToLive> mttl
184 = new ConstraintReducer<MulticastTimeToLive>(
185 MulticastTimeToLive.class).reduce(constraints);
186 timeToLive = mttl.isEmpty() ? null : getElement(mttl);
187 Set<UnicastSocketTimeout> ust
188 = new ConstraintReducer<UnicastSocketTimeout>(
189 UnicastSocketTimeout.class).reduce(constraints);
190 socketTimeout = ust.isEmpty() ? null : getElement(ust);
191 InvocationConstraints absConstraints
192 = new InvocationConstraints(
193 constraints.requirements(),
194 constraints.preferences()).makeAbsolute();
195 Set<ConnectionAbsoluteTime> cat
196 = new ConnectionAbsoluteTimeReducer().reduce(absConstraints);
197 connectionAbsoluteTime = cat.isEmpty() ? null : getElement(cat);
198 int hash = 7;
199 hash = 41 * hash + this.unfulfilled.hashCode();
200 hash = 41 * hash + this.protocolVersions.hashCode();
201 hash = 41 * hash + this.preferredProtocolVersion;
202 hash = 41 * hash + (this.connectionAbsoluteTime != null ? this.connectionAbsoluteTime.hashCode() : 0);
203 hash = 41 * hash + (this.maxPacketSize != null ? this.maxPacketSize.hashCode() : 0);
204 hash = 41 * hash + (this.timeToLive != null ? this.timeToLive.hashCode() : 0);
205 hash = 41 * hash + (this.socketTimeout != null ? this.socketTimeout.hashCode() : 0);
206 hashcode = hash;
207 }
208
209
210
211
212
213
214
215 public int chooseProtocolVersion() {
216 return preferredProtocolVersion;
217 }
218
219
220
221
222
223
224
225
226
227
228
229 public void checkProtocolVersion(int version)
230 throws UnsupportedConstraintException
231 {
232 if (!(protocolVersions.isEmpty() ||
233 protocolVersions.contains(
234 DiscoveryProtocolVersion.getInstance(version))))
235 {
236 throw new UnsupportedConstraintException(
237 "disallowed protocol: " + version);
238 }
239 }
240
241
242
243
244
245
246
247
248
249
250 public long getConnectionDeadline(long defaultValue) {
251 return connectionAbsoluteTime != null ?
252 connectionAbsoluteTime.getTime() : defaultValue;
253 }
254
255
256
257
258
259
260
261
262
263 public int getMulticastMaxPacketSize(int defaultValue) {
264 return (maxPacketSize != null) ?
265 maxPacketSize.getSize() : defaultValue;
266 }
267
268
269
270
271
272
273
274
275
276 public int getMulticastTimeToLive(int defaultValue) {
277 return (timeToLive != null) ?
278 timeToLive.getTimeToLive() : defaultValue;
279 }
280
281
282
283
284
285
286
287
288
289 public int getUnicastSocketTimeout(int defaultValue) {
290 return (socketTimeout != null) ?
291 socketTimeout.getTimeout() : defaultValue;
292 }
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307 public InvocationConstraints getUnfulfilledConstraints() {
308 return unfulfilled;
309 }
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330 private static class ConstraintReducer<T extends InvocationConstraint> {
331
332 private final Class<T> targetClass;
333
334
335
336
337
338 ConstraintReducer(Class<T> targetClass) {
339 this.targetClass = targetClass;
340 }
341
342
343
344
345
346
347
348 @SuppressWarnings("unchecked")
349 Set<T> reduce(InvocationConstraints constraints)
350 throws UnsupportedConstraintException
351 {
352 Set<T> reduced = reduce(null, constraints.requirements(), true);
353 reduced = reduce(reduced, constraints.preferences(), false);
354 return (reduced != null) ? reduced : Collections.EMPTY_SET;
355 }
356
357
358
359
360
361
362
363
364
365
366
367 Set<T> reduce0(Set<T> reduced, Set<T> toReduce) {
368 return (reduced != null) ? intersect(reduced, toReduce) : toReduce;
369 }
370
371 @SuppressWarnings("unchecked")
372 private Set<T> reduce(Set<T> reduced, Set<InvocationConstraint> constraints, boolean required)
373 throws UnsupportedConstraintException
374 {
375 for (Iterator<InvocationConstraint> i = constraints.iterator(); i.hasNext(); ) {
376 InvocationConstraint c = i.next();
377 Set<T> toReduce = Collections.EMPTY_SET;
378 if (targetClass.isInstance(c)) {
379 toReduce = Collections.singleton((T) c);
380 } else if (c instanceof ConstraintAlternatives) {
381 toReduce = getTargetInstances(
382 ((ConstraintAlternatives) c).elements());
383 }
384 if (!toReduce.isEmpty()) {
385 Set<T> s = reduce0(reduced, toReduce);
386 if (!s.isEmpty()) {
387 reduced = s;
388 } else if (required) {
389 throw new UnsupportedConstraintException(
390 "constraints conflict: " + constraints);
391 }
392 }
393 }
394 return reduced;
395 }
396
397 @SuppressWarnings("unchecked")
398 private Set<T> getTargetInstances(Set<InvocationConstraint> set) {
399 Set<T> instances = Collections.EMPTY_SET;
400 for (Iterator<InvocationConstraint> i = set.iterator(); i.hasNext(); ) {
401 InvocationConstraint obj = i.next();
402 if (targetClass.isInstance(obj)) {
403 if (instances.isEmpty()) {
404 instances = new HashSet<T>();
405 }
406 instances.add((T) obj);
407 }
408 }
409 return instances;
410 }
411 }
412
413
414
415
416
417
418 private abstract static class MaxValueReducer<T extends InvocationConstraint>
419 extends ConstraintReducer<T>
420 {
421 MaxValueReducer(Class<T> targetClass) {
422 super(targetClass);
423 }
424
425 abstract long getValue(InvocationConstraint ic);
426 abstract T getConstraintInstance(long value);
427
428
429
430
431
432
433
434
435
436 @Override
437 Set<T> reduce0(Set<T> reduced, Set<T> toReduce) {
438 long value = 0;
439 for (Iterator<T> i = toReduce.iterator(); i.hasNext(); ) {
440 value = Math.max(
441 value, getValue( i.next()));
442 }
443 if (reduced != null) {
444 value = Math.min(
445 value,
446 getValue( getElement(reduced)));
447 }
448 return Collections.singleton((T) getConstraintInstance(value));
449 }
450 }
451
452 private static class MulticastMaxPacketSizeReducer
453 extends MaxValueReducer<MulticastMaxPacketSize>
454 {
455 MulticastMaxPacketSizeReducer() {
456 super(MulticastMaxPacketSize.class);
457 }
458
459 @Override
460 long getValue(InvocationConstraint maxPacketSize) {
461 return ((MulticastMaxPacketSize) maxPacketSize).getSize();
462 }
463
464 @Override
465 MulticastMaxPacketSize getConstraintInstance(long value) {
466 if (value > Integer.MAX_VALUE) {
467
468
469 throw new AssertionError("Value too large " + value);
470 }
471 return new MulticastMaxPacketSize((int)value);
472 }
473 }
474
475 private static class ConnectionAbsoluteTimeReducer extends MaxValueReducer<ConnectionAbsoluteTime> {
476 ConnectionAbsoluteTimeReducer() {
477 super(ConnectionAbsoluteTime.class);
478 }
479
480 @Override
481 long getValue(InvocationConstraint absTime) {
482 return ((ConnectionAbsoluteTime) absTime).getTime();
483 }
484
485 @Override
486 ConnectionAbsoluteTime getConstraintInstance(long value) {
487 return new ConnectionAbsoluteTime(value);
488 }
489 }
490
491 private static Set<InvocationConstraint> getUnfulfilled(Set<InvocationConstraint> constraints) {
492 Set<InvocationConstraint> unfulfilled = new HashSet<InvocationConstraint>(constraints.size());
493 for (Iterator<InvocationConstraint> i = constraints.iterator(); i.hasNext(); ) {
494 InvocationConstraint c = i.next();
495 if (c instanceof ConstraintAlternatives) {
496 Set<InvocationConstraint> s = ((ConstraintAlternatives) c).elements();
497 Set<InvocationConstraint> u = getUnfulfilled(s);
498 if (u.size() == s.size()) {
499 unfulfilled.add(c);
500 }
501 } else if (!(c instanceof DiscoveryProtocolVersion ||
502 c instanceof MulticastMaxPacketSize ||
503 c instanceof MulticastTimeToLive ||
504 c instanceof UnicastSocketTimeout ||
505 c instanceof ConnectionAbsoluteTime ||
506 c instanceof ConnectionRelativeTime))
507 {
508 unfulfilled.add(c);
509 }
510 }
511 return unfulfilled;
512 }
513
514 private static int chooseProtocolVersion(Set<DiscoveryProtocolVersion> protocolVersions,
515 Set<DiscoveryProtocolVersion> protocolVersionPrefs,
516 InvocationConstraints unfulfilled)
517 {
518 DiscoveryProtocolVersion bias = DiscoveryProtocolVersion.TWO;
519 Set[] sets = { protocolVersionPrefs, protocolVersions };
520 for (int i = 0, l = sets.length; i < l; i++) {
521 @SuppressWarnings("unchecked")
522 Set<DiscoveryProtocolVersion> s = sets[i];
523 if (s.contains(bias)) {
524 return bias.getVersion();
525 }
526 if (!(s = intersect(s, supportedProtocols)).isEmpty()) {
527 return ( getElement(s)).getVersion();
528 }
529 }
530 return bias.getVersion();
531 }
532
533 private static <T> Set<T> intersect(Set<T> s1, Set s2) {
534 @SuppressWarnings("unchecked")
535 Set<T> intersection = Collections.EMPTY_SET;
536 for (Iterator<T> i = s1.iterator(); i.hasNext(); ) {
537 T obj = i.next();
538 if (s2.contains(obj)) {
539 if (intersection.isEmpty()) {
540 intersection = new HashSet<T>();
541 }
542 intersection.add(obj);
543 }
544 }
545 return intersection;
546 }
547
548 private static <T> T getElement(Set<T> s) {
549 return s.iterator().next();
550 }
551 }