1 /**
2  *
3  */
4 package javax.jmdns.impl;
5 
6 import java.util.Date;
7 import java.util.Timer;
8 import java.util.TimerTask;
9 import java.util.concurrent.ConcurrentHashMap;
10 import java.util.concurrent.ConcurrentMap;
11 import java.util.concurrent.atomic.AtomicReference;
12 
13 import javax.jmdns.impl.tasks.RecordReaper;
14 import javax.jmdns.impl.tasks.Responder;
15 import javax.jmdns.impl.tasks.resolver.ServiceInfoResolver;
16 import javax.jmdns.impl.tasks.resolver.ServiceResolver;
17 import javax.jmdns.impl.tasks.resolver.TypeResolver;
18 import javax.jmdns.impl.tasks.state.Announcer;
19 import javax.jmdns.impl.tasks.state.Canceler;
20 import javax.jmdns.impl.tasks.state.Prober;
21 import javax.jmdns.impl.tasks.state.Renewer;
22 
23 /**
24  * This class is used by JmDNS to start the various task required to run the DNS discovery. This interface is only there in order to support MANET modifications.
25  * <p>
26  * <b>Note: </b> This is not considered as part of the general public API of JmDNS.
27  * </p>
28  *
29  * @author Pierre Frisch
30  */
31 public interface DNSTaskStarter {
32 
33     /**
34      * DNSTaskStarter.Factory enable the creation of new instance of DNSTaskStarter.
35      */
36     public static final class Factory {
37 
38         private static volatile Factory                        _instance;
39         private final ConcurrentMap<JmDNSImpl, DNSTaskStarter> _instances;
40 
41         /**
42          * This interface defines a delegate to the DNSTaskStarter class to enable subclassing.
43          */
44         public static interface ClassDelegate {
45 
46             /**
47              * Allows the delegate the opportunity to construct and return a different DNSTaskStarter.
48              *
49              * @param jmDNSImpl
50              *            jmDNS instance
51              * @return Should return a new DNSTaskStarter Object.
52              * @see #classDelegate()
53              * @see #setClassDelegate(ClassDelegate anObject)
54              */
newDNSTaskStarter(JmDNSImpl jmDNSImpl)55             public DNSTaskStarter newDNSTaskStarter(JmDNSImpl jmDNSImpl);
56         }
57 
58         private static final AtomicReference<Factory.ClassDelegate> _databaseClassDelegate = new AtomicReference<Factory.ClassDelegate>();
59 
Factory()60         private Factory() {
61             super();
62             _instances = new ConcurrentHashMap<JmDNSImpl, DNSTaskStarter>(20);
63         }
64 
65         /**
66          * Assigns <code>delegate</code> as DNSTaskStarter's class delegate. The class delegate is optional.
67          *
68          * @param delegate
69          *            The object to set as DNSTaskStarter's class delegate.
70          * @see #classDelegate()
71          * @see DNSTaskStarter.Factory.ClassDelegate
72          */
setClassDelegate(Factory.ClassDelegate delegate)73         public static void setClassDelegate(Factory.ClassDelegate delegate) {
74             _databaseClassDelegate.set(delegate);
75         }
76 
77         /**
78          * Returns DNSTaskStarter's class delegate.
79          *
80          * @return DNSTaskStarter's class delegate.
81          * @see #setClassDelegate(ClassDelegate anObject)
82          * @see DNSTaskStarter.Factory.ClassDelegate
83          */
classDelegate()84         public static Factory.ClassDelegate classDelegate() {
85             return _databaseClassDelegate.get();
86         }
87 
88         /**
89          * Returns a new instance of DNSTaskStarter using the class delegate if it exists.
90          *
91          * @param jmDNSImpl
92          *            jmDNS instance
93          * @return new instance of DNSTaskStarter
94          */
newDNSTaskStarter(JmDNSImpl jmDNSImpl)95         protected static DNSTaskStarter newDNSTaskStarter(JmDNSImpl jmDNSImpl) {
96             DNSTaskStarter instance = null;
97             Factory.ClassDelegate delegate = _databaseClassDelegate.get();
98             if (delegate != null) {
99                 instance = delegate.newDNSTaskStarter(jmDNSImpl);
100             }
101             return (instance != null ? instance : new DNSTaskStarterImpl(jmDNSImpl));
102         }
103 
104         /**
105          * Return the instance of the DNSTaskStarter Factory.
106          *
107          * @return DNSTaskStarter Factory
108          */
getInstance()109         public static Factory getInstance() {
110             if (_instance == null) {
111                 synchronized (DNSTaskStarter.Factory.class) {
112                     if (_instance == null) {
113                         _instance = new Factory();
114                     }
115                 }
116             }
117             return _instance;
118         }
119 
120         /**
121          * Return the instance of the DNSTaskStarter for the JmDNS.
122          *
123          * @param jmDNSImpl
124          *            jmDNS instance
125          * @return the DNSTaskStarter
126          */
getStarter(JmDNSImpl jmDNSImpl)127         public DNSTaskStarter getStarter(JmDNSImpl jmDNSImpl) {
128             DNSTaskStarter starter = _instances.get(jmDNSImpl);
129             if (starter == null) {
130                 _instances.putIfAbsent(jmDNSImpl, newDNSTaskStarter(jmDNSImpl));
131                 starter = _instances.get(jmDNSImpl);
132             }
133             return starter;
134         }
135 
136     }
137 
138     public static final class DNSTaskStarterImpl implements DNSTaskStarter {
139 
140         private final JmDNSImpl _jmDNSImpl;
141 
142         /**
143          * The timer is used to dispatch all outgoing messages of JmDNS. It is also used to dispatch maintenance tasks for the DNS cache.
144          */
145         private final Timer     _timer;
146 
147         /**
148          * The timer is used to dispatch maintenance tasks for the DNS cache.
149          */
150         private final Timer     _stateTimer;
151 
152         public static class StarterTimer extends Timer {
153 
154             // This is needed because in some case we cancel the timers before all the task have finished running and in some case they will try to reschedule
155             private volatile boolean _cancelled;
156 
157             /**
158              *
159              */
StarterTimer()160             public StarterTimer() {
161                 super();
162                 _cancelled = false;
163             }
164 
165             /**
166              * @param isDaemon
167              */
StarterTimer(boolean isDaemon)168             public StarterTimer(boolean isDaemon) {
169                 super(isDaemon);
170                 _cancelled = false;
171             }
172 
173             /**
174              * @param name
175              * @param isDaemon
176              */
StarterTimer(String name, boolean isDaemon)177             public StarterTimer(String name, boolean isDaemon) {
178                 super(name, isDaemon);
179                 _cancelled = false;
180             }
181 
182             /**
183              * @param name
184              */
StarterTimer(String name)185             public StarterTimer(String name) {
186                 super(name);
187                 _cancelled = false;
188             }
189 
190             /*
191              * (non-Javadoc)
192              * @see java.util.Timer#cancel()
193              */
194             @Override
cancel()195             public synchronized void cancel() {
196                 if (_cancelled) return;
197                 _cancelled = true;
198                 super.cancel();
199             }
200 
201             /*
202              * (non-Javadoc)
203              * @see java.util.Timer#schedule(java.util.TimerTask, long)
204              */
205             @Override
schedule(TimerTask task, long delay)206             public synchronized void schedule(TimerTask task, long delay) {
207                 if (_cancelled) return;
208                 super.schedule(task, delay);
209             }
210 
211             /*
212              * (non-Javadoc)
213              * @see java.util.Timer#schedule(java.util.TimerTask, java.util.Date)
214              */
215             @Override
schedule(TimerTask task, Date time)216             public synchronized void schedule(TimerTask task, Date time) {
217                 if (_cancelled) return;
218                 super.schedule(task, time);
219             }
220 
221             /*
222              * (non-Javadoc)
223              * @see java.util.Timer#schedule(java.util.TimerTask, long, long)
224              */
225             @Override
schedule(TimerTask task, long delay, long period)226             public synchronized void schedule(TimerTask task, long delay, long period) {
227                 if (_cancelled) return;
228                 super.schedule(task, delay, period);
229             }
230 
231             /*
232              * (non-Javadoc)
233              * @see java.util.Timer#schedule(java.util.TimerTask, java.util.Date, long)
234              */
235             @Override
schedule(TimerTask task, Date firstTime, long period)236             public synchronized void schedule(TimerTask task, Date firstTime, long period) {
237                 if (_cancelled) return;
238                 super.schedule(task, firstTime, period);
239             }
240 
241             /*
242              * (non-Javadoc)
243              * @see java.util.Timer#scheduleAtFixedRate(java.util.TimerTask, long, long)
244              */
245             @Override
scheduleAtFixedRate(TimerTask task, long delay, long period)246             public synchronized void scheduleAtFixedRate(TimerTask task, long delay, long period) {
247                 if (_cancelled) return;
248                 super.scheduleAtFixedRate(task, delay, period);
249             }
250 
251             /*
252              * (non-Javadoc)
253              * @see java.util.Timer#scheduleAtFixedRate(java.util.TimerTask, java.util.Date, long)
254              */
255             @Override
scheduleAtFixedRate(TimerTask task, Date firstTime, long period)256             public synchronized void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) {
257                 if (_cancelled) return;
258                 super.scheduleAtFixedRate(task, firstTime, period);
259             }
260 
261         }
262 
DNSTaskStarterImpl(JmDNSImpl jmDNSImpl)263         public DNSTaskStarterImpl(JmDNSImpl jmDNSImpl) {
264             super();
265             _jmDNSImpl = jmDNSImpl;
266             _timer = new StarterTimer("JmDNS(" + _jmDNSImpl.getName() + ").Timer", true);
267             _stateTimer = new StarterTimer("JmDNS(" + _jmDNSImpl.getName() + ").State.Timer", false);
268         }
269 
270         /*
271          * (non-Javadoc)
272          * @see javax.jmdns.impl.DNSTaskStarter#purgeTimer()
273          */
274         @Override
purgeTimer()275         public void purgeTimer() {
276             _timer.purge();
277         }
278 
279         /*
280          * (non-Javadoc)
281          * @see javax.jmdns.impl.DNSTaskStarter#purgeStateTimer()
282          */
283         @Override
purgeStateTimer()284         public void purgeStateTimer() {
285             _stateTimer.purge();
286         }
287 
288         /*
289          * (non-Javadoc)
290          * @see javax.jmdns.impl.DNSTaskStarter#cancelTimer()
291          */
292         @Override
cancelTimer()293         public void cancelTimer() {
294             _timer.cancel();
295         }
296 
297         /*
298          * (non-Javadoc)
299          * @see javax.jmdns.impl.DNSTaskStarter#cancelStateTimer()
300          */
301         @Override
cancelStateTimer()302         public void cancelStateTimer() {
303             _stateTimer.cancel();
304         }
305 
306         /*
307          * (non-Javadoc)
308          * @see javax.jmdns.impl.DNSTaskStarter#startProber()
309          */
310         @Override
startProber()311         public void startProber() {
312             new Prober(_jmDNSImpl).start(_stateTimer);
313         }
314 
315         /*
316          * (non-Javadoc)
317          * @see javax.jmdns.impl.DNSTaskStarter#startAnnouncer()
318          */
319         @Override
startAnnouncer()320         public void startAnnouncer() {
321             new Announcer(_jmDNSImpl).start(_stateTimer);
322         }
323 
324         /*
325          * (non-Javadoc)
326          * @see javax.jmdns.impl.DNSTaskStarter#startRenewer()
327          */
328         @Override
startRenewer()329         public void startRenewer() {
330             new Renewer(_jmDNSImpl).start(_stateTimer);
331         }
332 
333         /*
334          * (non-Javadoc)
335          * @see javax.jmdns.impl.DNSTaskStarter#startCanceler()
336          */
337         @Override
startCanceler()338         public void startCanceler() {
339             new Canceler(_jmDNSImpl).start(_stateTimer);
340         }
341 
342         /*
343          * (non-Javadoc)
344          * @see javax.jmdns.impl.DNSTaskStarter#startReaper()
345          */
346         @Override
startReaper()347         public void startReaper() {
348             new RecordReaper(_jmDNSImpl).start(_timer);
349         }
350 
351         /*
352          * (non-Javadoc)
353          * @see javax.jmdns.impl.DNSTaskStarter#startServiceInfoResolver(javax.jmdns.impl.ServiceInfoImpl)
354          */
355         @Override
startServiceInfoResolver(ServiceInfoImpl info)356         public void startServiceInfoResolver(ServiceInfoImpl info) {
357             new ServiceInfoResolver(_jmDNSImpl, info).start(_timer);
358         }
359 
360         /*
361          * (non-Javadoc)
362          * @see javax.jmdns.impl.DNSTaskStarter#startTypeResolver()
363          */
364         @Override
startTypeResolver()365         public void startTypeResolver() {
366             new TypeResolver(_jmDNSImpl).start(_timer);
367         }
368 
369         /*
370          * (non-Javadoc)
371          * @see javax.jmdns.impl.DNSTaskStarter#startServiceResolver(java.lang.String)
372          */
373         @Override
startServiceResolver(String type)374         public void startServiceResolver(String type) {
375             new ServiceResolver(_jmDNSImpl, type).start(_timer);
376         }
377 
378         /*
379          * (non-Javadoc)
380          * @see javax.jmdns.impl.DNSTaskStarter#startResponder(javax.jmdns.impl.DNSIncoming, int)
381          */
382         @Override
startResponder(DNSIncoming in, int port)383         public void startResponder(DNSIncoming in, int port) {
384             new Responder(_jmDNSImpl, in, port).start(_timer);
385         }
386     }
387 
388     /**
389      * Purge the general task timer
390      */
purgeTimer()391     public void purgeTimer();
392 
393     /**
394      * Purge the state task timer
395      */
purgeStateTimer()396     public void purgeStateTimer();
397 
398     /**
399      * Cancel the generals task timer
400      */
cancelTimer()401     public void cancelTimer();
402 
403     /**
404      * Cancel the state task timer
405      */
cancelStateTimer()406     public void cancelStateTimer();
407 
408     /**
409      * Start a new prober task
410      */
startProber()411     public void startProber();
412 
413     /**
414      * Start a new announcer task
415      */
startAnnouncer()416     public void startAnnouncer();
417 
418     /**
419      * Start a new renewer task
420      */
startRenewer()421     public void startRenewer();
422 
423     /**
424      * Start a new canceler task
425      */
startCanceler()426     public void startCanceler();
427 
428     /**
429      * Start a new reaper task. There is only supposed to be one reaper running at a time.
430      */
startReaper()431     public void startReaper();
432 
433     /**
434      * Start a new service info resolver task
435      *
436      * @param info
437      *            service info to resolve
438      */
startServiceInfoResolver(ServiceInfoImpl info)439     public void startServiceInfoResolver(ServiceInfoImpl info);
440 
441     /**
442      * Start a new service type resolver task
443      */
startTypeResolver()444     public void startTypeResolver();
445 
446     /**
447      * Start a new service resolver task
448      *
449      * @param type
450      *            service type to resolve
451      */
startServiceResolver(String type)452     public void startServiceResolver(String type);
453 
454     /**
455      * Start a new responder task
456      *
457      * @param in
458      *            incoming message
459      * @param port
460      *            incoming port
461      */
startResponder(DNSIncoming in, int port)462     public void startResponder(DNSIncoming in, int port);
463 
464 }
465