13742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman/**
23742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman *
33742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */
43742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpackage javax.jmdns.impl;
53742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
63742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.io.IOException;
73742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.InetAddress;
83742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.ArrayList;
93742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Arrays;
103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Collections;
113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.HashMap;
123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.HashSet;
133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.List;
143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Map;
153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Set;
163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Timer;
173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.TimerTask;
183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.concurrent.ConcurrentHashMap;
193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.concurrent.ConcurrentMap;
203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.concurrent.ExecutorService;
213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.concurrent.Executors;
223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.concurrent.TimeUnit;
233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Level;
243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Logger;
253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.JmDNS;
273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.JmmDNS;
283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.NetworkTopologyDiscovery;
293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.NetworkTopologyEvent;
303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.NetworkTopologyListener;
313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceInfo;
323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceListener;
333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceTypeListener;
343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSConstants;
353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman/**
373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * This class enable multihomming mDNS. It will open a mDNS per IP address of the machine.
383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman *
393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @author Cédrik Lime, Pierre Frisch
403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */
413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpublic class JmmDNSImpl implements JmmDNS, NetworkTopologyListener, ServiceInfoImpl.Delegate {
423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private static Logger                            logger = Logger.getLogger(JmmDNSImpl.class.getName());
433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final Set<NetworkTopologyListener>       _networkListeners;
453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Every JmDNS created.
483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final ConcurrentMap<InetAddress, JmDNS>  _knownMDNS;
503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * This enable the service info text update.
533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final ConcurrentMap<String, ServiceInfo> _services;
553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final ExecutorService                    _ListenerExecutor;
573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final ExecutorService                    _jmDNSExecutor;
593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final Timer                              _timer;
613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *
643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public JmmDNSImpl() {
663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        super();
673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _networkListeners = Collections.synchronizedSet(new HashSet<NetworkTopologyListener>());
683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _knownMDNS = new ConcurrentHashMap<InetAddress, JmDNS>();
693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _services = new ConcurrentHashMap<String, ServiceInfo>(20);
703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _ListenerExecutor = Executors.newSingleThreadExecutor();
713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _jmDNSExecutor = Executors.newCachedThreadPool();
723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _timer = new Timer("Multihommed mDNS.Timer", true);
733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        (new NetworkChecker(this, NetworkTopologyDiscovery.Factory.getInstance())).start(_timer);
743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see java.io.Closeable#close()
793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void close() throws IOException {
823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (logger.isLoggable(Level.FINER)) {
833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            logger.finer("Cancelling JmmDNS: " + this);
843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _timer.cancel();
863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _ListenerExecutor.shutdown();
873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // We need to cancel all the DNS
883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        ExecutorService executor = Executors.newCachedThreadPool();
893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (final JmDNS mDNS : _knownMDNS.values()) {
903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            executor.submit(new Runnable() {
913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                /**
923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                 * {@inheritDoc}
933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                 */
943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                @Override
953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                public void run() {
963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    try {
973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        mDNS.close();
983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    } catch (IOException exception) {
993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        // JmDNS never throws this is only because of the closeable interface
1003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
1013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
1023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            });
1033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        executor.shutdown();
1053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        try {
1063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            executor.awaitTermination(DNSConstants.CLOSE_TIMEOUT, TimeUnit.MILLISECONDS);
1073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } catch (InterruptedException exception) {
1083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            logger.log(Level.WARNING, "Exception ", exception);
1093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _knownMDNS.clear();
1113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#getNames()
1163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String[] getNames() {
1193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Set<String> result = new HashSet<String>();
1203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (JmDNS mDNS : _knownMDNS.values()) {
1213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            result.add(mDNS.getName());
1223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return result.toArray(new String[result.size()]);
1243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#getHostNames()
1293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String[] getHostNames() {
1323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Set<String> result = new HashSet<String>();
1333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (JmDNS mDNS : _knownMDNS.values()) {
1343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            result.add(mDNS.getHostName());
1353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return result.toArray(new String[result.size()]);
1373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#getInetAddresses()
1423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public InetAddress[] getInetAddresses() throws IOException {
1453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Set<InetAddress> result = new HashSet<InetAddress>();
1463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (JmDNS mDNS : _knownMDNS.values()) {
1473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            result.add(mDNS.getInetAddress());
1483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return result.toArray(new InetAddress[result.size()]);
1503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#getInterfaces()
1553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Deprecated
1583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public InetAddress[] getInterfaces() throws IOException {
1593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Set<InetAddress> result = new HashSet<InetAddress>();
1603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (JmDNS mDNS : _knownMDNS.values()) {
1613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            result.add(mDNS.getInterface());
1623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return result.toArray(new InetAddress[result.size()]);
1643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#getServiceInfos(java.lang.String, java.lang.String)
1693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public ServiceInfo[] getServiceInfos(String type, String name) {
1723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this.getServiceInfos(type, name, false, DNSConstants.SERVICE_INFO_TIMEOUT);
1733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#getServiceInfos(java.lang.String, java.lang.String, long)
1783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public ServiceInfo[] getServiceInfos(String type, String name, long timeout) {
1813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this.getServiceInfos(type, name, false, timeout);
1823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#getServiceInfos(java.lang.String, java.lang.String, boolean)
1873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public ServiceInfo[] getServiceInfos(String type, String name, boolean persistent) {
1903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this.getServiceInfos(type, name, persistent, DNSConstants.SERVICE_INFO_TIMEOUT);
1913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#getServiceInfos(java.lang.String, java.lang.String, boolean, long)
1963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public ServiceInfo[] getServiceInfos(final String type, final String name, final boolean persistent, final long timeout) {
1993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // We need to run this in parallel to respect the timeout.
2003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        final Set<ServiceInfo> result = Collections.synchronizedSet(new HashSet<ServiceInfo>(_knownMDNS.size()));
2013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        ExecutorService executor = Executors.newCachedThreadPool();
2023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (final JmDNS mDNS : _knownMDNS.values()) {
2033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            executor.submit(new Runnable() {
2043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                /**
2053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                 * {@inheritDoc}
2063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                 */
2073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                @Override
2083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                public void run() {
2093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    result.add(mDNS.getServiceInfo(type, name, persistent, timeout));
2103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
2113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            });
2123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        executor.shutdown();
2143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        try {
2153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            executor.awaitTermination(timeout, TimeUnit.MILLISECONDS);
2163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } catch (InterruptedException exception) {
2173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            logger.log(Level.WARNING, "Exception ", exception);
2183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return result.toArray(new ServiceInfo[result.size()]);
2203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
2233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
2243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#requestServiceInfo(java.lang.String, java.lang.String)
2253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
2273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void requestServiceInfo(String type, String name) {
2283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this.requestServiceInfo(type, name, false, DNSConstants.SERVICE_INFO_TIMEOUT);
2293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
2323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
2333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#requestServiceInfo(java.lang.String, java.lang.String, boolean)
2343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
2363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void requestServiceInfo(String type, String name, boolean persistent) {
2373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this.requestServiceInfo(type, name, persistent, DNSConstants.SERVICE_INFO_TIMEOUT);
2383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
2413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
2423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#requestServiceInfo(java.lang.String, java.lang.String, long)
2433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
2453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void requestServiceInfo(String type, String name, long timeout) {
2463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this.requestServiceInfo(type, name, false, timeout);
2473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
2503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
2513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#requestServiceInfo(java.lang.String, java.lang.String, boolean, long)
2523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
2543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void requestServiceInfo(final String type, final String name, final boolean persistent, final long timeout) {
2553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // We need to run this in parallel to respect the timeout.
2563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (final JmDNS mDNS : _knownMDNS.values()) {
2573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            _jmDNSExecutor.submit(new Runnable() {
2583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                /**
2593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                 * {@inheritDoc}
2603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                 */
2613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                @Override
2623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                public void run() {
2633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    mDNS.requestServiceInfo(type, name, persistent, timeout);
2643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
2653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            });
2663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
2703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
2713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#addServiceTypeListener(javax.jmdns.ServiceTypeListener)
2723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
2743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void addServiceTypeListener(ServiceTypeListener listener) throws IOException {
2753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (JmDNS mDNS : _knownMDNS.values()) {
2763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            mDNS.addServiceTypeListener(listener);
2773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
2813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
2823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#removeServiceTypeListener(javax.jmdns.ServiceTypeListener)
2833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
2853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void removeServiceTypeListener(ServiceTypeListener listener) {
2863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (JmDNS mDNS : _knownMDNS.values()) {
2873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            mDNS.removeServiceTypeListener(listener);
2883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
2923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
2933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#addServiceListener(java.lang.String, javax.jmdns.ServiceListener)
2943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
2963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void addServiceListener(String type, ServiceListener listener) {
2973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (JmDNS mDNS : _knownMDNS.values()) {
2983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            mDNS.addServiceListener(type, listener);
2993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
3033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
3043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#removeServiceListener(java.lang.String, javax.jmdns.ServiceListener)
3053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void removeServiceListener(String type, ServiceListener listener) {
3083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (JmDNS mDNS : _knownMDNS.values()) {
3093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            mDNS.removeServiceListener(type, listener);
3103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
3143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
3153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.impl.ServiceInfoImpl.Delegate#textValueUpdated(javax.jmdns.ServiceInfo, byte[])
3163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void textValueUpdated(ServiceInfo target, byte[] value) {
3193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        synchronized (_services) {
3203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            for (JmDNS mDNS : _knownMDNS.values()) {
3213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                ServiceInfo info = ((JmDNSImpl) mDNS).getServices().get(target.getQualifiedName());
3223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (info != null) {
3233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    info.setText(value);
3243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                } else {
3253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    logger.warning("We have a mDNS that does not know about the service info being updated.");
3263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
3273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
3283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
3323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
3333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#registerService(javax.jmdns.ServiceInfo)
3343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void registerService(ServiceInfo info) throws IOException {
3373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // This is really complex. We need to clone the service info for each DNS but then we loose the ability to update it.
3383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        synchronized (_services) {
3393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            for (JmDNS mDNS : _knownMDNS.values()) {
3403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                mDNS.registerService(info.clone());
3413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
3423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ((ServiceInfoImpl) info).setDelegate(this);
3433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            _services.put(info.getQualifiedName(), info);
3443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
3483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
3493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#unregisterService(javax.jmdns.ServiceInfo)
3503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void unregisterService(ServiceInfo info) {
3533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        synchronized (_services) {
3543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            for (JmDNS mDNS : _knownMDNS.values()) {
3553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                mDNS.unregisterService(info);
3563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
3573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ((ServiceInfoImpl) info).setDelegate(null);
3583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            _services.remove(info.getQualifiedName());
3593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
3633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
3643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#unregisterAllServices()
3653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void unregisterAllServices() {
3683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        synchronized (_services) {
3693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            for (JmDNS mDNS : _knownMDNS.values()) {
3703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                mDNS.unregisterAllServices();
3713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
3723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            _services.clear();
3733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
3773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
3783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#registerServiceType(java.lang.String)
3793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void registerServiceType(String type) {
3823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (JmDNS mDNS : _knownMDNS.values()) {
3833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            mDNS.registerServiceType(type);
3843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
3883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
3893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#list(java.lang.String)
3903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public ServiceInfo[] list(String type) {
3933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this.list(type, DNSConstants.SERVICE_INFO_TIMEOUT);
3943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
3973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
3983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#list(java.lang.String, long)
3993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public ServiceInfo[] list(final String type, final long timeout) {
4023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // We need to run this in parallel to respect the timeout.
4033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        final Set<ServiceInfo> result = Collections.synchronizedSet(new HashSet<ServiceInfo>(_knownMDNS.size() * 5));
4043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        ExecutorService executor = Executors.newCachedThreadPool();
4053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (final JmDNS mDNS : _knownMDNS.values()) {
4063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            executor.submit(new Runnable() {
4073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                /**
4083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                 * {@inheritDoc}
4093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                 */
4103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                @Override
4113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                public void run() {
4123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    result.addAll(Arrays.asList(mDNS.list(type, timeout)));
4133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
4143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            });
4153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        executor.shutdown();
4173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        try {
4183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            executor.awaitTermination(timeout, TimeUnit.MILLISECONDS);
4193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } catch (InterruptedException exception) {
4203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            logger.log(Level.WARNING, "Exception ", exception);
4213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return result.toArray(new ServiceInfo[result.size()]);
4233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
4263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
4273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#listBySubtype(java.lang.String)
4283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public Map<String, ServiceInfo[]> listBySubtype(String type) {
4313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this.listBySubtype(type, DNSConstants.SERVICE_INFO_TIMEOUT);
4323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
4353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
4363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#listBySubtype(java.lang.String, long)
4373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public Map<String, ServiceInfo[]> listBySubtype(final String type, final long timeout) {
4403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Map<String, List<ServiceInfo>> map = new HashMap<String, List<ServiceInfo>>(5);
4413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (ServiceInfo info : this.list(type, timeout)) {
4423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            String subtype = info.getSubtype();
4433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (!map.containsKey(subtype)) {
4443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                map.put(subtype, new ArrayList<ServiceInfo>(10));
4453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
4463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            map.get(subtype).add(info);
4473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Map<String, ServiceInfo[]> result = new HashMap<String, ServiceInfo[]>(map.size());
4503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (String subtype : map.keySet()) {
4513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            List<ServiceInfo> infoForSubType = map.get(subtype);
4523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            result.put(subtype, infoForSubType.toArray(new ServiceInfo[infoForSubType.size()]));
4533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return result;
4563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
4593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
4603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#addNetworkTopologyListener(javax.jmdns.NetworkTopologyListener)
4613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void addNetworkTopologyListener(NetworkTopologyListener listener) {
4643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _networkListeners.add(listener);
4653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
4683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
4693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#removeNetworkTopologyListener(javax.jmdns.NetworkTopologyListener)
4703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void removeNetworkTopologyListener(NetworkTopologyListener listener) {
4733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _networkListeners.remove(listener);
4743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
4773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
4783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.JmmDNS#networkListeners()
4793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public NetworkTopologyListener[] networkListeners() {
4823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _networkListeners.toArray(new NetworkTopologyListener[_networkListeners.size()]);
4833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
4863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
4873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.NetworkTopologyListener#inetAddressAdded(javax.jmdns.NetworkTopologyEvent)
4883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void inetAddressAdded(NetworkTopologyEvent event) {
4913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        InetAddress address = event.getInetAddress();
4923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        try {
4933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            synchronized (this) {
4943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (!_knownMDNS.containsKey(address)) {
4953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    _knownMDNS.put(address, JmDNS.create(address));
4963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    final NetworkTopologyEvent jmdnsEvent = new NetworkTopologyEventImpl(_knownMDNS.get(address), address);
4973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    for (final NetworkTopologyListener listener : this.networkListeners()) {
4983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _ListenerExecutor.submit(new Runnable() {
4993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            /**
5003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                             * {@inheritDoc}
5013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                             */
5023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            @Override
5033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            public void run() {
5043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                                listener.inetAddressAdded(jmdnsEvent);
5053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            }
5063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        });
5073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
5083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
5093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
5103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } catch (Exception e) {
5113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            logger.warning("Unexpected unhandled exception: " + e);
5123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
5163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
5173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.NetworkTopologyListener#inetAddressRemoved(javax.jmdns.NetworkTopologyEvent)
5183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
5193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
5203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void inetAddressRemoved(NetworkTopologyEvent event) {
5213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        InetAddress address = event.getInetAddress();
5223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        try {
5233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            synchronized (this) {
5243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (_knownMDNS.containsKey(address)) {
5253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    JmDNS mDNS = _knownMDNS.remove(address);
5263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    mDNS.close();
5273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    final NetworkTopologyEvent jmdnsEvent = new NetworkTopologyEventImpl(mDNS, address);
5283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    for (final NetworkTopologyListener listener : this.networkListeners()) {
5293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _ListenerExecutor.submit(new Runnable() {
5303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            /**
5313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                             * {@inheritDoc}
5323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                             */
5333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            @Override
5343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            public void run() {
5353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                                listener.inetAddressRemoved(jmdnsEvent);
5363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            }
5373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        });
5383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
5393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
5403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
5413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } catch (Exception e) {
5423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            logger.warning("Unexpected unhandled exception: " + e);
5433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
5473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Checks the network state.<br/>
5483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * If the network change, this class will reconfigure the list of DNS do adapt to the new configuration.
5493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
5503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    static class NetworkChecker extends TimerTask {
5513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private static Logger                  logger1 = Logger.getLogger(NetworkChecker.class.getName());
5523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private final NetworkTopologyListener  _mmDNS;
5543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private final NetworkTopologyDiscovery _topology;
5563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private Set<InetAddress>               _knownAddresses;
5583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public NetworkChecker(NetworkTopologyListener mmDNS, NetworkTopologyDiscovery topology) {
5603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super();
5613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._mmDNS = mmDNS;
5623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._topology = topology;
5633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            _knownAddresses = Collections.synchronizedSet(new HashSet<InetAddress>());
5643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public void start(Timer timer) {
5673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            timer.schedule(this, 0, DNSConstants.NETWORK_CHECK_INTERVAL);
5683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
5713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * {@inheritDoc}
5723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
5733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
5743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public void run() {
5753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            try {
5763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                InetAddress[] curentAddresses = _topology.getInetAddresses();
5773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                Set<InetAddress> current = new HashSet<InetAddress>(curentAddresses.length);
5783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                for (InetAddress address : curentAddresses) {
5793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    current.add(address);
5803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (!_knownAddresses.contains(address)) {
5813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        final NetworkTopologyEvent event = new NetworkTopologyEventImpl(_mmDNS, address);
5823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _mmDNS.inetAddressAdded(event);
5833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
5843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
5853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                for (InetAddress address : _knownAddresses) {
5863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (!current.contains(address)) {
5873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        final NetworkTopologyEvent event = new NetworkTopologyEventImpl(_mmDNS, address);
5883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _mmDNS.inetAddressRemoved(event);
5893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
5903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
5913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                _knownAddresses = current;
5923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } catch (Exception e) {
5933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                logger1.warning("Unexpected unhandled exception: " + e);
5943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
5953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman}
600