Clover Coverage Report - JmDNS 3.4.1
Coverage timestamp: Thu Aug 25 2011 13:06:33 CEST
../../../img/srcFileCovDistChart8.png 9% of files have more coverage
131   559   57   4.52
44   300   0.44   9.67
29     1.97  
3    
 
  DNSStatefulObject       Line # 22 0 - 0 0 - -1.0
  DNSStatefulObject.DNSStatefulObjectSemaphore       Line # 32 30 0% 7 18 52.6% 0.5263158
  DNSStatefulObject.DefaultImplementation       Line # 104 101 0% 50 34 79.5% 0.79518074
 
  (23)
 
1    // Licensed under Apache License version 2.0
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    * Sets of methods to manage the state machine.<br/>
18    * <b>Implementation note:</b> This interface is accessed from multiple threads. The implementation must be thread safe.
19    *
20    * @author Pierre Frisch
21    */
 
22    public interface DNSStatefulObject {
23   
24    /**
25    * This class define a semaphore. On this multiple threads can wait the arrival of one event. Thread wait for a maximum defined by the timeout.
26    * <p>
27    * Implementation note: this class is based on {@link java.util.concurrent.Semaphore} so that they can be released by the timeout timer.
28    * </p>
29    *
30    * @author Pierre Frisch
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    * @param name
41    * Semaphore name for debugging purposes.
42    */
 
43  939 toggle public DNSStatefulObjectSemaphore(String name) {
44  936 super();
45  940 _name = name;
46  936 _semaphores = new ConcurrentHashMap<Thread, Semaphore>(50);
47    }
48   
49    /**
50    * Blocks the current thread until the event arrives or the timeout expires.
51    *
52    * @param timeout
53    * wait period for the event
54    */
 
55  90 toggle public void waitForEvent(long timeout) {
56  90 Thread thread = Thread.currentThread();
57  90 Semaphore semaphore = _semaphores.get(thread);
58  90 if (semaphore == null) {
59  90 semaphore = new Semaphore(1, true);
60  90 semaphore.drainPermits();
61  90 _semaphores.putIfAbsent(thread, semaphore);
62    }
63  90 semaphore = _semaphores.get(thread);
64  90 try {
65  90 semaphore.tryAcquire(timeout, TimeUnit.MILLISECONDS);
66    } catch (InterruptedException exception) {
67  0 logger.log(Level.FINER, "Exception ", exception);
68    }
69    }
70   
71    /**
72    * Signals the semaphore when the event arrives.
73    */
 
74  92 toggle public void signalEvent() {
75  92 Collection<Semaphore> semaphores = _semaphores.values();
76  92 for (Semaphore semaphore : semaphores) {
77  60 semaphore.release();
78  60 semaphores.remove(semaphore);
79    }
80    }
81   
 
82  0 toggle @Override
83    public String toString() {
84  0 StringBuilder aLog = new StringBuilder(1000);
85  0 aLog.append("Semaphore: ");
86  0 aLog.append(this._name);
87  0 if (_semaphores.size() == 0) {
88  0 aLog.append(" no semaphores.");
89    } else {
90  0 aLog.append(" semaphores:\n");
91  0 for (Thread thread : _semaphores.keySet()) {
92  0 aLog.append("\tThread: ");
93  0 aLog.append(thread.getName());
94  0 aLog.append(' ');
95  0 aLog.append(_semaphores.get(thread));
96  0 aLog.append('\n');
97    }
98    }
99  0 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  467 toggle public DefaultImplementation() {
120  467 super();
121  468 _dns = null;
122  467 _task = null;
123  469 _state = DNSState.PROBING_1;
124  466 _announcing = new DNSStatefulObjectSemaphore("Announce");
125  468 _canceling = new DNSStatefulObjectSemaphore("Cancel");
126    }
127   
128    /**
129    * {@inheritDoc}
130    */
 
131  99 toggle @Override
132    public JmDNSImpl getDns() {
133  99 return this._dns;
134    }
135   
 
136  178 toggle protected void setDns(JmDNSImpl dns) {
137  179 this._dns = dns;
138    }
139   
140    /**
141    * {@inheritDoc}
142    */
 
143  273 toggle @Override
144    public void associateWithTask(DNSTask task, DNSState state) {
145  273 if (this._task == null && this._state == state) {
146  170 this.lock();
147  170 try {
148  170 if (this._task == null && this._state == state) {
149  170 this.setTask(task);
150    }
151    } finally {
152  170 this.unlock();
153    }
154    }
155    }
156   
157    /**
158    * {@inheritDoc}
159    */
 
160  197 toggle @Override
161    public void removeAssociationWithTask(DNSTask task) {
162  197 if (this._task == task) {
163  118 this.lock();
164  118 try {
165  118 if (this._task == task) {
166  117 this.setTask(null);
167    }
168    } finally {
169  118 this.unlock();
170    }
171    }
172    }
173   
174    /**
175    * {@inheritDoc}
176    */
 
177  486 toggle @Override
178    public boolean isAssociatedWithTask(DNSTask task, DNSState state) {
179  486 this.lock();
180  486 try {
181  485 return this._task == task && this._state == state;
182    } finally {
183  485 this.unlock();
184    }
185    }
186   
 
187  360 toggle protected void setTask(DNSTask task) {
188  360 this._task = task;
189    }
190   
191    /**
192    * @param state
193    * the state to set
194    */
 
195  405 toggle protected void setState(DNSState state) {
196  405 this.lock();
197  405 try {
198  405 this._state = state;
199  405 if (this.isAnnounced()) {
200  51 _announcing.signalEvent();
201    }
202  405 if (this.isCanceled()) {
203  20 _canceling.signalEvent();
204    // clear any waiting announcing
205  20 _announcing.signalEvent();
206    }
207    } finally {
208  405 this.unlock();
209    }
210    }
211   
212    /**
213    * {@inheritDoc}
214    */
 
215  332 toggle @Override
216    public boolean advanceState(DNSTask task) {
217  332 boolean result = true;
218  332 if (this._task == task) {
219  332 this.lock();
220  332 try {
221  332 if (this._task == task) {
222  332 this.setState(this._state.advance());
223    } else {
224  0 logger.warning("Trying to advance state whhen not the owner. owner: " + this._task + " perpetrator: " + task);
225    }
226    } finally {
227  332 this.unlock();
228    }
229    }
230  332 return result;
231    }
232   
233    /**
234    * {@inheritDoc}
235    */
 
236  0 toggle @Override
237    public boolean revertState() {
238  0 boolean result = true;
239  0 if (!this.willCancel()) {
240  0 this.lock();
241  0 try {
242  0 if (!this.willCancel()) {
243  0 this.setState(this._state.revert());
244  0 this.setTask(null);
245    }
246    } finally {
247  0 this.unlock();
248    }
249    }
250  0 return result;
251    }
252   
253    /**
254    * {@inheritDoc}
255    */
 
256  20 toggle @Override
257    public boolean cancelState() {
258  20 boolean result = false;
259  20 if (!this.willCancel()) {
260  20 this.lock();
261  20 try {
262  20 if (!this.willCancel()) {
263  20 this.setState(DNSState.CANCELING_1);
264  20 this.setTask(null);
265  20 result = true;
266    }
267    } finally {
268  20 this.unlock();
269    }
270    }
271  20 return result;
272    }
273   
274    /**
275    * {@inheritDoc}
276    */
 
277  29 toggle @Override
278    public boolean closeState() {
279  29 boolean result = false;
280  29 if (!this.willClose()) {
281  29 this.lock();
282  29 try {
283  29 if (!this.willClose()) {
284  29 this.setState(DNSState.CLOSING);
285  29 this.setTask(null);
286  29 result = true;
287    }
288    } finally {
289  29 this.unlock();
290    }
291    }
292  29 return result;
293    }
294   
295    /**
296    * {@inheritDoc}
297    */
 
298  20 toggle @Override
299    public boolean recoverState() {
300  20 boolean result = false;
301  20 this.lock();
302  20 try {
303  20 this.setState(DNSState.PROBING_1);
304  20 this.setTask(null);
305    } finally {
306  20 this.unlock();
307    }
308  20 return result;
309    }
310   
311    /**
312    * {@inheritDoc}
313    */
 
314  0 toggle @Override
315    public boolean isProbing() {
316  0 return this._state.isProbing();
317    }
318   
319    /**
320    * {@inheritDoc}
321    */
 
322  60 toggle @Override
323    public boolean isAnnouncing() {
324  60 return this._state.isAnnouncing();
325    }
326   
327    /**
328    * {@inheritDoc}
329    */
 
330  1187 toggle @Override
331    public boolean isAnnounced() {
332  1187 return this._state.isAnnounced();
333    }
334   
335    /**
336    * {@inheritDoc}
337    */
 
338  2378 toggle @Override
339    public boolean isCanceling() {
340  2409 return this._state.isCanceling();
341    }
342   
343    /**
344    * {@inheritDoc}
345    */
 
346  2946 toggle @Override
347    public boolean isCanceled() {
348  2968 return this._state.isCanceled();
349    }
350   
351    /**
352    * {@inheritDoc}
353    */
 
354  707 toggle @Override
355    public boolean isClosing() {
356  732 return this._state.isClosing();
357    }
358   
359    /**
360    * {@inheritDoc}
361    */
 
362  646 toggle @Override
363    public boolean isClosed() {
364  672 return this._state.isClosed();
365    }
366   
 
367  79 toggle private boolean willCancel() {
368  79 return this._state.isCanceled() || this._state.isCanceling();
369    }
370   
 
371  87 toggle private boolean willClose() {
372  87 return this._state.isClosed() || this._state.isClosing();
373    }
374   
375    /**
376    * {@inheritDoc}
377    */
 
378  40 toggle @Override
379    public boolean waitForAnnounced(long timeout) {
380  40 if (!this.isAnnounced() && !this.willCancel()) {
381  39 _announcing.waitForEvent(timeout);
382    }
383  40 if (!this.isAnnounced()) {
384  0 if (this.willCancel() || this.willClose()) {
385  0 logger.fine("Wait for announced cancelled: " + this);
386    } else {
387  0 logger.warning("Wait for announced timed out: " + this);
388    }
389    }
390  40 return this.isAnnounced();
391    }
392   
393    /**
394    * {@inheritDoc}
395    */
 
396  49 toggle @Override
397    public boolean waitForCanceled(long timeout) {
398  49 if (!this.isCanceled()) {
399  49 _canceling.waitForEvent(timeout);
400    }
401  49 if (!this.isCanceled() && !this.willClose()) {
402  0 logger.warning("Wait for canceled timed out: " + this);
403    }
404  49 return this.isCanceled();
405    }
406   
407    /**
408    * {@inheritDoc}
409    */
 
410  7 toggle @Override
411    public String toString() {
412  7 return (_dns != null ? "DNS: " + _dns.getName() : "NO DNS") + " state: " + _state + " task: " + _task;
413    }
414   
415    }
416   
417    /**
418    * Returns the DNS associated with this object.
419    *
420    * @return DNS resolver
421    */
422    public JmDNSImpl getDns();
423   
424    /**
425    * Sets the task associated with this Object.
426    *
427    * @param task
428    * associated task
429    * @param state
430    * state of the task
431    */
432    public void associateWithTask(DNSTask task, DNSState state);
433   
434    /**
435    * Remove the association of the task with this Object.
436    *
437    * @param task
438    * associated task
439    */
440    public void removeAssociationWithTask(DNSTask task);
441   
442    /**
443    * Checks if this object is associated with the task and in the same state.
444    *
445    * @param task
446    * associated task
447    * @param state
448    * state of the task
449    * @return <code>true</code> is the task is associated with this object, <code>false</code> otherwise.
450    */
451    public boolean isAssociatedWithTask(DNSTask task, DNSState state);
452   
453    /**
454    * Sets the state and notifies all objects that wait on the ServiceInfo.
455    *
456    * @param task
457    * associated task
458    * @return <code>true</code if the state was changed by this thread, <code>false</code> otherwise.
459    * @see DNSState#advance()
460    */
461    public boolean advanceState(DNSTask task);
462   
463    /**
464    * Sets the state and notifies all objects that wait on the ServiceInfo.
465    *
466    * @return <code>true</code if the state was changed by this thread, <code>false</code> otherwise.
467    * @see DNSState#revert()
468    */
469    public boolean revertState();
470   
471    /**
472    * Sets the state and notifies all objects that wait on the ServiceInfo.
473    *
474    * @return <code>true</code if the state was changed by this thread, <code>false</code> otherwise.
475    */
476    public boolean cancelState();
477   
478    /**
479    * Sets the state and notifies all objects that wait on the ServiceInfo.
480    *
481    * @return <code>true</code if the state was changed by this thread, <code>false</code> otherwise.
482    */
483    public boolean closeState();
484   
485    /**
486    * Sets the state and notifies all objects that wait on the ServiceInfo.
487    *
488    * @return <code>true</code if the state was changed by this thread, <code>false</code> otherwise.
489    */
490    public boolean recoverState();
491   
492    /**
493    * Returns true, if this is a probing state.
494    *
495    * @return <code>true</code> if probing state, <code>false</code> otherwise
496    */
497    public boolean isProbing();
498   
499    /**
500    * Returns true, if this is an announcing state.
501    *
502    * @return <code>true</code> if announcing state, <code>false</code> otherwise
503    */
504    public boolean isAnnouncing();
505   
506    /**
507    * Returns true, if this is an announced state.
508    *
509    * @return <code>true</code> if announced state, <code>false</code> otherwise
510    */
511    public boolean isAnnounced();
512   
513    /**
514    * Returns true, if this is a canceling state.
515    *
516    * @return <code>true</code> if canceling state, <code>false</code> otherwise
517    */
518    public boolean isCanceling();
519   
520    /**
521    * Returns true, if this is a canceled state.
522    *
523    * @return <code>true</code> if canceled state, <code>false</code> otherwise
524    */
525    public boolean isCanceled();
526   
527    /**
528    * Returns true, if this is a closing state.
529    *
530    * @return <code>true</code> if closing state, <code>false</code> otherwise
531    */
532    public boolean isClosing();
533   
534    /**
535    * Returns true, if this is a closed state.
536    *
537    * @return <code>true</code> if closed state, <code>false</code> otherwise
538    */
539    public boolean isClosed();
540   
541    /**
542    * Waits for the object to be announced.
543    *
544    * @param timeout
545    * the maximum time to wait in milliseconds.
546    * @return <code>true</code> if the object is announced, <code>false</code> otherwise
547    */
548    public boolean waitForAnnounced(long timeout);
549   
550    /**
551    * Waits for the object to be canceled.
552    *
553    * @param timeout
554    * the maximum time to wait in milliseconds.
555    * @return <code>true</code> if the object is canceled, <code>false</code> otherwise
556    */
557    public boolean waitForCanceled(long timeout);
558   
559    }