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 */
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 }