/**
*
*/
package javax.jmdns.impl;
import java.net.InetAddress;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;
import javax.jmdns.impl.tasks.RecordReaper;
import javax.jmdns.impl.tasks.Responder;
import javax.jmdns.impl.tasks.resolver.ServiceInfoResolver;
import javax.jmdns.impl.tasks.resolver.ServiceResolver;
import javax.jmdns.impl.tasks.resolver.TypeResolver;
import javax.jmdns.impl.tasks.state.Announcer;
import javax.jmdns.impl.tasks.state.Canceler;
import javax.jmdns.impl.tasks.state.Prober;
import javax.jmdns.impl.tasks.state.Renewer;
/**
* 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.
* <p>
* <b>Note: </b> This is not considered as part of the general public API of
* JmDNS.
* </p>
*
* @author Pierre Frisch
*/
public interface DNSTaskStarter
{
/**
* Purge the general task timer
*/
public void purgeTimer();
/**
* Purge the state task timer
*/
public void purgeStateTimer();
/**
* Cancel the generals task timer
*/
public void cancelTimer();
/**
* Cancel the state task timer
*/
public void cancelStateTimer();
/**
* Start a new prober task
*/
public void startProber();
/**
* Start a new announcer task
*/
public void startAnnouncer();
/**
* Start a new renewer task
*/
public void startRenewer();
/**
* Start a new canceler task
*/
public void startCanceler();
/**
* Start a new reaper task. There is only supposed to be one reaper running
* at a time.
*/
public void startReaper();
/**
* Start a new service info resolver task
*
* @param info service info to resolve
*/
public void startServiceInfoResolver(ServiceInfoImpl info);
/**
* Start a new service type resolver task
*/
public void startTypeResolver();
/**
* Start a new service resolver task
*
* @param type service type to resolve
*/
public void startServiceResolver(String type);
/**
* Start a new responder task
*
* @param in incoming message
* @param addr incoming address
* @param port incoming port
*/
public void startResponder(DNSIncoming in, InetAddress addr, int port);
/**
* DNSTaskStarter.Factory enable the creation of new instance of
* DNSTaskStarter.
*/
public static final class Factory
{
private static final AtomicReference<ClassDelegate> _databaseClassDelegate = new AtomicReference<ClassDelegate>();
private static volatile Factory _instance;
private final ConcurrentMap<JmDNSImpl, DNSTaskStarter> _instances;
private Factory()
{
super();
_instances = new ConcurrentHashMap<JmDNSImpl, DNSTaskStarter>(20);
}
/**
* Assigns <code>delegate</code> as DNSTaskStarter's class delegate. The
* class delegate is optional.
*
* @param delegate The object to set as DNSTaskStarter's class delegate.
* @see #classDelegate()
* @see ClassDelegate
*/
public static void setClassDelegate(ClassDelegate delegate)
{
_databaseClassDelegate.set(delegate);
}
/**
* Returns DNSTaskStarter's class delegate.
*
* @return DNSTaskStarter's class delegate.
* @see #setClassDelegate(ClassDelegate anObject)
* @see ClassDelegate
*/
public static ClassDelegate classDelegate()
{
return _databaseClassDelegate.get();
}
/**
* Returns a new instance of DNSTaskStarter using the class delegate if
* it exists.
*
* @param jmDNSImpl jmDNS instance
* @return new instance of DNSTaskStarter
*/
protected static DNSTaskStarter newDNSTaskStarter(JmDNSImpl jmDNSImpl)
{
DNSTaskStarter instance = null;
ClassDelegate delegate = _databaseClassDelegate.get();
if (delegate != null)
{
instance = delegate.newDNSTaskStarter(jmDNSImpl);
}
return (instance != null ? instance : new DNSTaskStarterImpl(jmDNSImpl));
}
/**
* Return the instance of the DNSTaskStarter Factory.
*
* @return DNSTaskStarter Factory
*/
public static Factory getInstance()
{
if (_instance == null)
{
synchronized (Factory.class)
{
if (_instance == null)
{
_instance = new Factory();
}
}
}
return _instance;
}
/**
* Return the instance of the DNSTaskStarter for the JmDNS.
*
* @param jmDNSImpl jmDNS instance
* @return the DNSTaskStarter
*/
public DNSTaskStarter getStarter(JmDNSImpl jmDNSImpl)
{
DNSTaskStarter starter = _instances.get(jmDNSImpl);
if (starter == null)
{
_instances.putIfAbsent(jmDNSImpl, newDNSTaskStarter(jmDNSImpl));
starter = _instances.get(jmDNSImpl);
}
return starter;
}
/**
* Dispose of the DNSTaskStarter instance associated with this JmDNS.
*
* @param jmDNSImpl jmDNS instance
*/
public void disposeStarter(JmDNSImpl jmDNSImpl)
{
_instances.remove(jmDNSImpl);
}
/**
* This interface defines a delegate to the DNSTaskStarter class to
* enable subclassing.
*/
public static interface ClassDelegate
{
/**
* Allows the delegate the opportunity to construct and return a
* different DNSTaskStarter.
*
* @param jmDNSImpl jmDNS instance
* @return Should return a new DNSTaskStarter Object.
* @see #classDelegate()
* @see #setClassDelegate(ClassDelegate anObject)
*/
public DNSTaskStarter newDNSTaskStarter(JmDNSImpl jmDNSImpl);
}
}
public static final class DNSTaskStarterImpl implements DNSTaskStarter
{
private final JmDNSImpl _jmDNSImpl;
/**
* The timer is used to dispatch all outgoing messages of JmDNS. It is
* also used to dispatch maintenance tasks for the DNS cache.
*/
private final Timer _timer;
/**
* The timer is used to dispatch maintenance tasks for the DNS cache.
*/
private final Timer _stateTimer;
public DNSTaskStarterImpl(JmDNSImpl jmDNSImpl)
{
super();
_jmDNSImpl = jmDNSImpl;
_timer = new StarterTimer("JmDNS(" + _jmDNSImpl.getName() + ").Timer", true);
_stateTimer = new StarterTimer("JmDNS(" + _jmDNSImpl.getName()
+ ").State.Timer", true);
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.DNSTaskStarter#purgeTimer()
*/
@Override
public void purgeTimer()
{
_timer.purge();
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.DNSTaskStarter#purgeStateTimer()
*/
@Override
public void purgeStateTimer()
{
_stateTimer.purge();
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.DNSTaskStarter#cancelTimer()
*/
@Override
public void cancelTimer()
{
_timer.cancel();
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.DNSTaskStarter#cancelStateTimer()
*/
@Override
public void cancelStateTimer()
{
_stateTimer.cancel();
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.DNSTaskStarter#startProber()
*/
@Override
public void startProber()
{
new Prober(_jmDNSImpl).start(_stateTimer);
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.DNSTaskStarter#startAnnouncer()
*/
@Override
public void startAnnouncer()
{
new Announcer(_jmDNSImpl).start(_stateTimer);
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.DNSTaskStarter#startRenewer()
*/
@Override
public void startRenewer()
{
new Renewer(_jmDNSImpl).start(_stateTimer);
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.DNSTaskStarter#startCanceler()
*/
@Override
public void startCanceler()
{
new Canceler(_jmDNSImpl).start(_stateTimer);
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.DNSTaskStarter#startReaper()
*/
@Override
public void startReaper()
{
new RecordReaper(_jmDNSImpl).start(_timer);
}
/*
* (non-Javadoc)
*
* @see
* javax.jmdns.impl.DNSTaskStarter#startServiceInfoResolver(javax.jmdns
* .impl.ServiceInfoImpl)
*/
@Override
public void startServiceInfoResolver(ServiceInfoImpl info)
{
new ServiceInfoResolver(_jmDNSImpl, info).start(_timer);
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.DNSTaskStarter#startTypeResolver()
*/
@Override
public void startTypeResolver()
{
new TypeResolver(_jmDNSImpl).start(_timer);
}
/*
* (non-Javadoc)
*
* @see
* javax.jmdns.impl.DNSTaskStarter#startServiceResolver(java.lang.String
* )
*/
@Override
public void startServiceResolver(String type)
{
new ServiceResolver(_jmDNSImpl, type).start(_timer);
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.DNSTaskStarter#startResponder(javax.jmdns.impl.
* DNSIncoming, int)
*/
@Override
public void startResponder(DNSIncoming in, InetAddress addr, int port)
{
new Responder(_jmDNSImpl, in, addr, port).start(_timer);
}
public static class StarterTimer extends Timer
{
// 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
private volatile boolean _cancelled;
/**
*
*/
public StarterTimer()
{
super();
_cancelled = false;
}
/**
* @param isDaemon
*/
public StarterTimer(boolean isDaemon)
{
super(isDaemon);
_cancelled = false;
}
/**
* @param name
* @param isDaemon
*/
public StarterTimer(String name, boolean isDaemon)
{
super(name, isDaemon);
_cancelled = false;
}
/**
* @param name
*/
public StarterTimer(String name)
{
super(name);
_cancelled = false;
}
/*
* (non-Javadoc)
*
* @see java.util.Timer#cancel()
*/
@Override
public synchronized void cancel()
{
if (_cancelled)
return;
_cancelled = true;
super.cancel();
}
/*
* (non-Javadoc)
*
* @see java.util.Timer#schedule(java.util.TimerTask, long)
*/
@Override
public synchronized void schedule(TimerTask task, long delay)
{
if (_cancelled)
return;
super.schedule(task, delay);
}
/*
* (non-Javadoc)
*
* @see java.util.Timer#schedule(java.util.TimerTask,
* java.util.Date)
*/
@Override
public synchronized void schedule(TimerTask task, Date time)
{
if (_cancelled)
return;
super.schedule(task, time);
}
/*
* (non-Javadoc)
*
* @see java.util.Timer#schedule(java.util.TimerTask, long, long)
*/
@Override
public synchronized void schedule(TimerTask task, long delay, long period)
{
if (_cancelled)
return;
super.schedule(task, delay, period);
}
/*
* (non-Javadoc)
*
* @see java.util.Timer#schedule(java.util.TimerTask,
* java.util.Date, long)
*/
@Override
public synchronized void schedule(TimerTask task, Date firstTime, long period)
{
if (_cancelled)
return;
super.schedule(task, firstTime, period);
}
/*
* (non-Javadoc)
*
* @see java.util.Timer#scheduleAtFixedRate(java.util.TimerTask,
* long, long)
*/
@Override
public synchronized void scheduleAtFixedRate(TimerTask task, long delay,
long period)
{
if (_cancelled)
return;
super.scheduleAtFixedRate(task, delay, period);
}
/*
* (non-Javadoc)
*
* @see java.util.Timer#scheduleAtFixedRate(java.util.TimerTask,
* java.util.Date, long)
*/
@Override
public synchronized void scheduleAtFixedRate(TimerTask task, Date firstTime,
long period)
{
if (_cancelled)
return;
super.scheduleAtFixedRate(task, firstTime, period);
}
}
}
}