1/**
2 *
3 */
4package javax.jmdns.impl;
5
6import java.util.Date;
7import java.util.Timer;
8import java.util.TimerTask;
9import java.util.concurrent.ConcurrentHashMap;
10import java.util.concurrent.ConcurrentMap;
11import java.util.concurrent.atomic.AtomicReference;
12
13import javax.jmdns.impl.tasks.RecordReaper;
14import javax.jmdns.impl.tasks.Responder;
15import javax.jmdns.impl.tasks.resolver.ServiceInfoResolver;
16import javax.jmdns.impl.tasks.resolver.ServiceResolver;
17import javax.jmdns.impl.tasks.resolver.TypeResolver;
18import javax.jmdns.impl.tasks.state.Announcer;
19import javax.jmdns.impl.tasks.state.Canceler;
20import javax.jmdns.impl.tasks.state.Prober;
21import 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 */
31public 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             */
55            public DNSTaskStarter newDNSTaskStarter(JmDNSImpl jmDNSImpl);
56        }
57
58        private static final AtomicReference<Factory.ClassDelegate> _databaseClassDelegate = new AtomicReference<Factory.ClassDelegate>();
59
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         */
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         */
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         */
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         */
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         */
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             */
160            public StarterTimer() {
161                super();
162                _cancelled = false;
163            }
164
165            /**
166             * @param isDaemon
167             */
168            public StarterTimer(boolean isDaemon) {
169                super(isDaemon);
170                _cancelled = false;
171            }
172
173            /**
174             * @param name
175             * @param isDaemon
176             */
177            public StarterTimer(String name, boolean isDaemon) {
178                super(name, isDaemon);
179                _cancelled = false;
180            }
181
182            /**
183             * @param name
184             */
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
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
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
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
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
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
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
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
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
275        public void purgeTimer() {
276            _timer.purge();
277        }
278
279        /*
280         * (non-Javadoc)
281         * @see javax.jmdns.impl.DNSTaskStarter#purgeStateTimer()
282         */
283        @Override
284        public void purgeStateTimer() {
285            _stateTimer.purge();
286        }
287
288        /*
289         * (non-Javadoc)
290         * @see javax.jmdns.impl.DNSTaskStarter#cancelTimer()
291         */
292        @Override
293        public void cancelTimer() {
294            _timer.cancel();
295        }
296
297        /*
298         * (non-Javadoc)
299         * @see javax.jmdns.impl.DNSTaskStarter#cancelStateTimer()
300         */
301        @Override
302        public void cancelStateTimer() {
303            _stateTimer.cancel();
304        }
305
306        /*
307         * (non-Javadoc)
308         * @see javax.jmdns.impl.DNSTaskStarter#startProber()
309         */
310        @Override
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
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
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
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
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
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
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
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
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     */
391    public void purgeTimer();
392
393    /**
394     * Purge the state task timer
395     */
396    public void purgeStateTimer();
397
398    /**
399     * Cancel the generals task timer
400     */
401    public void cancelTimer();
402
403    /**
404     * Cancel the state task timer
405     */
406    public void cancelStateTimer();
407
408    /**
409     * Start a new prober task
410     */
411    public void startProber();
412
413    /**
414     * Start a new announcer task
415     */
416    public void startAnnouncer();
417
418    /**
419     * Start a new renewer task
420     */
421    public void startRenewer();
422
423    /**
424     * Start a new canceler task
425     */
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     */
431    public void startReaper();
432
433    /**
434     * Start a new service info resolver task
435     *
436     * @param info
437     *            service info to resolve
438     */
439    public void startServiceInfoResolver(ServiceInfoImpl info);
440
441    /**
442     * Start a new service type resolver task
443     */
444    public void startTypeResolver();
445
446    /**
447     * Start a new service resolver task
448     *
449     * @param type
450     *            service type to resolve
451     */
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     */
462    public void startResponder(DNSIncoming in, int port);
463
464}
465