1
2 package javax.jmdns.impl;
3
4 import java.util.Collection;
5 import java.util.concurrent.ConcurrentHashMap;
6 import java.util.concurrent.ConcurrentMap;
7 import java.util.concurrent.Semaphore;
8 import java.util.concurrent.TimeUnit;
9 import java.util.concurrent.locks.ReentrantLock;
10 import java.util.logging.Level;
11 import java.util.logging.Logger;
12
13 import javax.jmdns.impl.constants.DNSState;
14 import javax.jmdns.impl.tasks.DNSTask;
15
16
17
18
19
20
21
22 public interface DNSStatefulObject {
23
24
25
26
27
28
29
30
31
32 public static final class DNSStatefulObjectSemaphore {
33 private static Logger logger = Logger.getLogger(DNSStatefulObjectSemaphore.class.getName());
34
35 private final String _name;
36
37 private final ConcurrentMap<Thread, Semaphore> _semaphores;
38
39
40
41
42
43 public DNSStatefulObjectSemaphore(String name) {
44 super();
45 _name = name;
46 _semaphores = new ConcurrentHashMap<Thread, Semaphore>(50);
47 }
48
49
50
51
52
53
54
55 public void waitForEvent(long timeout) {
56 Thread thread = Thread.currentThread();
57 Semaphore semaphore = _semaphores.get(thread);
58 if (semaphore == null) {
59 semaphore = new Semaphore(1, true);
60 semaphore.drainPermits();
61 _semaphores.putIfAbsent(thread, semaphore);
62 }
63 semaphore = _semaphores.get(thread);
64 try {
65 semaphore.tryAcquire(timeout, TimeUnit.MILLISECONDS);
66 } catch (InterruptedException exception) {
67 logger.log(Level.FINER, "Exception ", exception);
68 }
69 }
70
71
72
73
74 public void signalEvent() {
75 Collection<Semaphore> semaphores = _semaphores.values();
76 for (Semaphore semaphore : semaphores) {
77 semaphore.release();
78 semaphores.remove(semaphore);
79 }
80 }
81
82 @Override
83 public String toString() {
84 StringBuilder aLog = new StringBuilder(1000);
85 aLog.append("Semaphore: ");
86 aLog.append(this._name);
87 if (_semaphores.size() == 0) {
88 aLog.append(" no semaphores.");
89 } else {
90 aLog.append(" semaphores:\n");
91 for (Thread thread : _semaphores.keySet()) {
92 aLog.append("\tThread: ");
93 aLog.append(thread.getName());
94 aLog.append(' ');
95 aLog.append(_semaphores.get(thread));
96 aLog.append('\n');
97 }
98 }
99 return aLog.toString();
100 }
101
102 }
103
104 public static class DefaultImplementation extends ReentrantLock implements DNSStatefulObject {
105 private static Logger logger = Logger.getLogger(DefaultImplementation.class.getName());
106
107 private static final long serialVersionUID = -3264781576883412227L;
108
109 private volatile JmDNSImpl _dns;
110
111 protected volatile DNSTask _task;
112
113 protected volatile DNSState _state;
114
115 private final DNSStatefulObjectSemaphore _announcing;
116
117 private final DNSStatefulObjectSemaphore _canceling;
118
119 public DefaultImplementation() {
120 super();
121 _dns = null;
122 _task = null;
123 _state = DNSState.PROBING_1;
124 _announcing = new DNSStatefulObjectSemaphore("Announce");
125 _canceling = new DNSStatefulObjectSemaphore("Cancel");
126 }
127
128
129
130
131 @Override
132 public JmDNSImpl getDns() {
133 return this._dns;
134 }
135
136 protected void setDns(JmDNSImpl dns) {
137 this._dns = dns;
138 }
139
140
141
142
143 @Override
144 public void associateWithTask(DNSTask task, DNSState state) {
145 if (this._task == null && this._state == state) {
146 this.lock();
147 try {
148 if (this._task == null && this._state == state) {
149 this.setTask(task);
150 }
151 } finally {
152 this.unlock();
153 }
154 }
155 }
156
157
158
159
160 @Override
161 public void removeAssociationWithTask(DNSTask task) {
162 if (this._task == task) {
163 this.lock();
164 try {
165 if (this._task == task) {
166 this.setTask(null);
167 }
168 } finally {
169 this.unlock();
170 }
171 }
172 }
173
174
175
176
177 @Override
178 public boolean isAssociatedWithTask(DNSTask task, DNSState state) {
179 this.lock();
180 try {
181 return this._task == task && this._state == state;
182 } finally {
183 this.unlock();
184 }
185 }
186
187 protected void setTask(DNSTask task) {
188 this._task = task;
189 }
190
191
192
193
194
195 protected void setState(DNSState state) {
196 this.lock();
197 try {
198 this._state = state;
199 if (this.isAnnounced()) {
200 _announcing.signalEvent();
201 }
202 if (this.isCanceled()) {
203 _canceling.signalEvent();
204
205 _announcing.signalEvent();
206 }
207 } finally {
208 this.unlock();
209 }
210 }
211
212
213
214
215 @Override
216 public boolean advanceState(DNSTask task) {
217 boolean result = true;
218 if (this._task == task) {
219 this.lock();
220 try {
221 if (this._task == task) {
222 this.setState(this._state.advance());
223 } else {
224 logger.warning("Trying to advance state whhen not the owner. owner: " + this._task + " perpetrator: " + task);
225 }
226 } finally {
227 this.unlock();
228 }
229 }
230 return result;
231 }
232
233
234
235
236 @Override
237 public boolean revertState() {
238 boolean result = true;
239 if (!this.willCancel()) {
240 this.lock();
241 try {
242 if (!this.willCancel()) {
243 this.setState(this._state.revert());
244 this.setTask(null);
245 }
246 } finally {
247 this.unlock();
248 }
249 }
250 return result;
251 }
252
253
254
255
256 @Override
257 public boolean cancelState() {
258 boolean result = false;
259 if (!this.willCancel()) {
260 this.lock();
261 try {
262 if (!this.willCancel()) {
263 this.setState(DNSState.CANCELING_1);
264 this.setTask(null);
265 result = true;
266 }
267 } finally {
268 this.unlock();
269 }
270 }
271 return result;
272 }
273
274
275
276
277 @Override
278 public boolean closeState() {
279 boolean result = false;
280 if (!this.willClose()) {
281 this.lock();
282 try {
283 if (!this.willClose()) {
284 this.setState(DNSState.CLOSING);
285 this.setTask(null);
286 result = true;
287 }
288 } finally {
289 this.unlock();
290 }
291 }
292 return result;
293 }
294
295
296
297
298 @Override
299 public boolean recoverState() {
300 boolean result = false;
301 this.lock();
302 try {
303 this.setState(DNSState.PROBING_1);
304 this.setTask(null);
305 } finally {
306 this.unlock();
307 }
308 return result;
309 }
310
311
312
313
314 @Override
315 public boolean isProbing() {
316 return this._state.isProbing();
317 }
318
319
320
321
322 @Override
323 public boolean isAnnouncing() {
324 return this._state.isAnnouncing();
325 }
326
327
328
329
330 @Override
331 public boolean isAnnounced() {
332 return this._state.isAnnounced();
333 }
334
335
336
337
338 @Override
339 public boolean isCanceling() {
340 return this._state.isCanceling();
341 }
342
343
344
345
346 @Override
347 public boolean isCanceled() {
348 return this._state.isCanceled();
349 }
350
351
352
353
354 @Override
355 public boolean isClosing() {
356 return this._state.isClosing();
357 }
358
359
360
361
362 @Override
363 public boolean isClosed() {
364 return this._state.isClosed();
365 }
366
367 private boolean willCancel() {
368 return this._state.isCanceled() || this._state.isCanceling();
369 }
370
371 private boolean willClose() {
372 return this._state.isClosed() || this._state.isClosing();
373 }
374
375
376
377
378 @Override
379 public boolean waitForAnnounced(long timeout) {
380 if (!this.isAnnounced() && !this.willCancel()) {
381 _announcing.waitForEvent(timeout);
382 }
383 if (!this.isAnnounced()) {
384 if (this.willCancel() || this.willClose()) {
385 logger.fine("Wait for announced cancelled: " + this);
386 } else {
387 logger.warning("Wait for announced timed out: " + this);
388 }
389 }
390 return this.isAnnounced();
391 }
392
393
394
395
396 @Override
397 public boolean waitForCanceled(long timeout) {
398 if (!this.isCanceled()) {
399 _canceling.waitForEvent(timeout);
400 }
401 if (!this.isCanceled() && !this.willClose()) {
402 logger.warning("Wait for canceled timed out: " + this);
403 }
404 return this.isCanceled();
405 }
406
407
408
409
410 @Override
411 public String toString() {
412 return (_dns != null ? "DNS: " + _dns.getName() : "NO DNS") + " state: " + _state + " task: " + _task;
413 }
414
415 }
416
417
418
419
420
421
422 public JmDNSImpl getDns();
423
424
425
426
427
428
429
430
431
432 public void associateWithTask(DNSTask task, DNSState state);
433
434
435
436
437
438
439
440 public void removeAssociationWithTask(DNSTask task);
441
442
443
444
445
446
447
448
449
450
451 public boolean isAssociatedWithTask(DNSTask task, DNSState state);
452
453
454
455
456
457
458
459
460
461 public boolean advanceState(DNSTask task);
462
463
464
465
466
467
468
469 public boolean revertState();
470
471
472
473
474
475
476 public boolean cancelState();
477
478
479
480
481
482
483 public boolean closeState();
484
485
486
487
488
489
490 public boolean recoverState();
491
492
493
494
495
496
497 public boolean isProbing();
498
499
500
501
502
503
504 public boolean isAnnouncing();
505
506
507
508
509
510
511 public boolean isAnnounced();
512
513
514
515
516
517
518 public boolean isCanceling();
519
520
521
522
523
524
525 public boolean isCanceled();
526
527
528
529
530
531
532 public boolean isClosing();
533
534
535
536
537
538
539 public boolean isClosed();
540
541
542
543
544
545
546
547
548 public boolean waitForAnnounced(long timeout);
549
550
551
552
553
554
555
556
557 public boolean waitForCanceled(long timeout);
558
559 }