All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.jmdns.impl.JmmDNSImpl Maven / Gradle / Ivy

Go to download

JmDNS is a Java implementation of multi-cast DNS and can be used for service registration and discovery in local area networks. JmDNS is fully compatible with Apple's Bonjour. The project was originally started in December 2002 by Arthur van Hoff at Strangeberry.

There is a newer version: 3.6.0
Show newest version
/**
 *
 */
package javax.jmdns.impl;

import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jmdns.JmDNS;
import javax.jmdns.JmmDNS;
import javax.jmdns.NetworkTopologyDiscovery;
import javax.jmdns.NetworkTopologyEvent;
import javax.jmdns.NetworkTopologyListener;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import javax.jmdns.ServiceTypeListener;
import javax.jmdns.impl.constants.DNSConstants;
import javax.jmdns.impl.util.NamedThreadFactory;

/**
 * This class enable multihoming mDNS. It will open a mDNS per IP address of the machine.
 *
 * @author Cédrik Lime, Pierre Frisch
 */
public class JmmDNSImpl implements JmmDNS, NetworkTopologyListener, ServiceInfoImpl.Delegate {
    private static Logger                                      logger = LoggerFactory.getLogger(JmmDNSImpl.class);

    private final Set                 _networkListeners;

    /**
     * Every JmDNS created.
     */
    private final ConcurrentMap            _knownMDNS;

    /**
     * This enable the service info text update.
     */
    private final ConcurrentMap           _services;

    /**
     * List of registered services
     */
    private final Set                                  _serviceTypes;

    /**
     * Holds instances of ServiceListener's. Keys are Strings holding a fully qualified service type. Values are LinkedList's of ServiceListener's.
     */
    private final ConcurrentMap> _serviceListeners;

    /**
     * Holds instances of ServiceTypeListener's.
     */
    private final Set                     _typeListeners;

    private final ExecutorService                              _listenerExecutor;

    private final ExecutorService                              _jmDNSExecutor;

    private final Timer                                        _timer;

    private final AtomicBoolean                                _isClosing;

    private final AtomicBoolean                                _closed;

    /**
     *
     */
    public JmmDNSImpl() {
        super();
        _networkListeners = Collections.synchronizedSet(new HashSet());
        _knownMDNS = new ConcurrentHashMap();
        _services = new ConcurrentHashMap(20);
        _listenerExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory("JmmDNS Listeners"));
        _jmDNSExecutor = Executors.newCachedThreadPool(new NamedThreadFactory("JmmDNS"));
        _timer = new Timer("Multihomed mDNS.Timer", true);
        _serviceListeners = new ConcurrentHashMap>();
        _typeListeners = Collections.synchronizedSet(new HashSet());
        _serviceTypes = Collections.synchronizedSet(new HashSet());
        (new NetworkChecker(this, NetworkTopologyDiscovery.Factory.getInstance())).start(_timer);
        _isClosing = new AtomicBoolean(false);
        _closed = new AtomicBoolean(false);
    }

    /*
     * (non-Javadoc)
     * @see java.io.Closeable#close()
     */
    @Override
    public void close() throws IOException {
        if (_isClosing.compareAndSet(false, true)) {
            logger.debug("Cancelling JmmDNS: {}", this);
            _timer.cancel();
            _listenerExecutor.shutdown();
            _jmDNSExecutor.shutdown();
            // We need to cancel all the DNS
            ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("JmmDNS.close"));
            try {
                for (final JmDNS mDNS : this.getDNS()) {
                    executor.submit(new Runnable() {
                        /**
                         * {@inheritDoc}
                         */
                        @Override
                        public void run() {
                            try {
                                mDNS.close();
                            } catch (IOException exception) {
                                // JmDNS never throws this is only because of the closeable interface
                            }
                        }
                    });
                }
            } finally {
                executor.shutdown();
            }
            try {
                executor.awaitTermination(DNSConstants.CLOSE_TIMEOUT, TimeUnit.MILLISECONDS);
            } catch (InterruptedException exception) {
                logger.warn("Exception ", exception);
            }
            _knownMDNS.clear();
            _services.clear();
            _serviceListeners.clear();
            _typeListeners.clear();
            _serviceTypes.clear();
            _closed.set(true);
            JmmDNS.Factory.close();
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#getNames()
     */
    @Override
    public String[] getNames() {
        Set result = new HashSet();
        for (JmDNS mDNS : this.getDNS()) {
            result.add(mDNS.getName());
        }
        return result.toArray(new String[result.size()]);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#getHostNames()
     */
    @Override
    public String[] getHostNames() {
        Set result = new HashSet();
        for (JmDNS mDNS : this.getDNS()) {
            result.add(mDNS.getHostName());
        }
        return result.toArray(new String[result.size()]);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#getInetAddresses()
     */
    @Override
    public InetAddress[] getInetAddresses() throws IOException {
        Set result = new HashSet();
        for (JmDNS mDNS : this.getDNS()) {
            result.add(mDNS.getInetAddress());
        }
        return result.toArray(new InetAddress[result.size()]);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#getDNS()
     */
    @Override
    public JmDNS[] getDNS() {
        synchronized (_knownMDNS) {
            return _knownMDNS.values().toArray(new JmDNS[_knownMDNS.size()]);
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#getInterfaces()
     */
    @Override
    @Deprecated
    public InetAddress[] getInterfaces() throws IOException {
        Set result = new HashSet();
        for (JmDNS mDNS : this.getDNS()) {
            result.add(mDNS.getInterface());
        }
        return result.toArray(new InetAddress[result.size()]);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#getServiceInfos(java.lang.String, java.lang.String)
     */
    @Override
    public ServiceInfo[] getServiceInfos(String type, String name) {
        return this.getServiceInfos(type, name, false, DNSConstants.SERVICE_INFO_TIMEOUT);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#getServiceInfos(java.lang.String, java.lang.String, long)
     */
    @Override
    public ServiceInfo[] getServiceInfos(String type, String name, long timeout) {
        return this.getServiceInfos(type, name, false, timeout);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#getServiceInfos(java.lang.String, java.lang.String, boolean)
     */
    @Override
    public ServiceInfo[] getServiceInfos(String type, String name, boolean persistent) {
        return this.getServiceInfos(type, name, persistent, DNSConstants.SERVICE_INFO_TIMEOUT);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#getServiceInfos(java.lang.String, java.lang.String, boolean, long)
     */
    @Override
    public ServiceInfo[] getServiceInfos(final String type, final String name, final boolean persistent, final long timeout) {
        // We need to run this in parallel to respect the timeout.
        final JmDNS[] dnsArray = this.getDNS();
        final Set result = new HashSet(dnsArray.length);
        if (dnsArray.length > 0) {
            List> tasks = new ArrayList>(dnsArray.length);
            for (final JmDNS mDNS : dnsArray) {
                tasks.add(new Callable() {

                    @Override
                    public ServiceInfo call() throws Exception {
                        return mDNS.getServiceInfo(type, name, persistent, timeout);
                    }

                });
            }

            ExecutorService executor = Executors.newFixedThreadPool(tasks.size(), new NamedThreadFactory("JmmDNS.getServiceInfos"));
            try {
                List> results = Collections.emptyList();
                try {
                    results = executor.invokeAll(tasks, timeout + 100, TimeUnit.MILLISECONDS);
                } catch (InterruptedException exception) {
                    logger.debug("Interrupted ", exception);
                    Thread.currentThread().interrupt();
                    // Will terminate next loop early.
                }

                for (Future future : results) {
                    if (future.isCancelled()) {
                        continue;
                    }
                    try {
                        ServiceInfo info = future.get();
                        if (info != null) {
                            result.add(info);
                        }
                    } catch (InterruptedException exception) {
                        logger.debug("Interrupted ", exception);
                        Thread.currentThread().interrupt();
                    } catch (ExecutionException exception) {
                        logger.warn("Exception ", exception);
                    }
                }
            } finally {
                executor.shutdown();
            }
        }
        return result.toArray(new ServiceInfo[result.size()]);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#requestServiceInfo(java.lang.String, java.lang.String)
     */
    @Override
    public void requestServiceInfo(String type, String name) {
        this.requestServiceInfo(type, name, false, DNSConstants.SERVICE_INFO_TIMEOUT);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#requestServiceInfo(java.lang.String, java.lang.String, boolean)
     */
    @Override
    public void requestServiceInfo(String type, String name, boolean persistent) {
        this.requestServiceInfo(type, name, persistent, DNSConstants.SERVICE_INFO_TIMEOUT);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#requestServiceInfo(java.lang.String, java.lang.String, long)
     */
    @Override
    public void requestServiceInfo(String type, String name, long timeout) {
        this.requestServiceInfo(type, name, false, timeout);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#requestServiceInfo(java.lang.String, java.lang.String, boolean, long)
     */
    @Override
    public void requestServiceInfo(final String type, final String name, final boolean persistent, final long timeout) {
        // We need to run this in parallel to respect the timeout.
        for (final JmDNS mDNS : this.getDNS()) {
            _jmDNSExecutor.submit(new Runnable() {
                /**
                 * {@inheritDoc}
                 */
                @Override
                public void run() {
                    mDNS.requestServiceInfo(type, name, persistent, timeout);
                }
            });
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#addServiceTypeListener(javax.jmdns.ServiceTypeListener)
     */
    @Override
    public void addServiceTypeListener(ServiceTypeListener listener) throws IOException {
        _typeListeners.add(listener);
        for (JmDNS mDNS : this.getDNS()) {
            mDNS.addServiceTypeListener(listener);
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#removeServiceTypeListener(javax.jmdns.ServiceTypeListener)
     */
    @Override
    public void removeServiceTypeListener(ServiceTypeListener listener) {
        _typeListeners.remove(listener);
        for (JmDNS mDNS : this.getDNS()) {
            mDNS.removeServiceTypeListener(listener);
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#addServiceListener(java.lang.String, javax.jmdns.ServiceListener)
     */
    @Override
    public void addServiceListener(String type, ServiceListener listener) {
        final String loType = type.toLowerCase();
        List list = _serviceListeners.get(loType);
        if (list == null) {
            _serviceListeners.putIfAbsent(loType, new LinkedList());
            list = _serviceListeners.get(loType);
        }
        if (list != null) {
            synchronized (list) {
                if (!list.contains(listener)) {
                    list.add(listener);
                }
            }
        }
        for (JmDNS mDNS : this.getDNS()) {
            mDNS.addServiceListener(type, listener);
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#removeServiceListener(java.lang.String, javax.jmdns.ServiceListener)
     */
    @Override
    public void removeServiceListener(String type, ServiceListener listener) {
        String loType = type.toLowerCase();
        List list = _serviceListeners.get(loType);
        if (list != null) {
            synchronized (list) {
                list.remove(listener);
                if (list.isEmpty()) {
                    _serviceListeners.remove(loType, list);
                }
            }
        }
        for (JmDNS mDNS : this.getDNS()) {
            mDNS.removeServiceListener(type, listener);
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.impl.ServiceInfoImpl.Delegate#textValueUpdated(javax.jmdns.ServiceInfo, byte[])
     */
    @Override
    public void textValueUpdated(ServiceInfo target, byte[] value) {
        // We need to get the list out of the synchronized block to prevent dead locks
        final JmDNS[] dnsArray = this.getDNS();
        synchronized (_services) {
            for (JmDNS mDNS : dnsArray) {
                ServiceInfo info = ((JmDNSImpl) mDNS).getServices().get(target.getQualifiedName());
                if (info != null) {
                    info.setText(value);
                } else {
                    logger.warn("We have a mDNS that does not know about the service info being updated.");
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#registerService(javax.jmdns.ServiceInfo)
     */
    @Override
    public void registerService(ServiceInfo info) throws IOException {
        // We need to get the list out of the synchronized block to prevent dead locks
        final JmDNS[] dnsArray = this.getDNS();
        // This is really complex. We need to clone the service info for each DNS but then we loose the ability to update it.
        synchronized (_services) {
            for (JmDNS mDNS : dnsArray) {
                mDNS.registerService(info.clone());
            }
            ((ServiceInfoImpl) info).setDelegate(this);
            _services.put(info.getQualifiedName(), info);
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#unregisterService(javax.jmdns.ServiceInfo)
     */
    @Override
    public void unregisterService(ServiceInfo info) {
        // We need to get the list out of the synchronized block to prevent dead locks
        final JmDNS[] dnsArray = this.getDNS();
        synchronized (_services) {
            _services.remove(info.getQualifiedName());
            for (JmDNS mDNS : dnsArray) {
                mDNS.unregisterService(info);
            }
            ((ServiceInfoImpl) info).setDelegate(null);
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#unregisterAllServices()
     */
    @Override
    public void unregisterAllServices() {
        // We need to get the list out of the synchronized block to prevent dead locks
        final JmDNS[] dnsArray = this.getDNS();
        synchronized (_services) {
            _services.clear();
            for (JmDNS mDNS : dnsArray) {
                mDNS.unregisterAllServices();
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#registerServiceType(java.lang.String)
     */
    @Override
    public void registerServiceType(String type) {
        _serviceTypes.add(type);
        for (JmDNS mDNS : this.getDNS()) {
            mDNS.registerServiceType(type);
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#list(java.lang.String)
     */
    @Override
    public ServiceInfo[] list(String type) {
        return this.list(type, DNSConstants.SERVICE_INFO_TIMEOUT);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#list(java.lang.String, long)
     */
    @Override
    public ServiceInfo[] list(final String type, final long timeout) {
        final JmDNS[] dnsArray = this.getDNS();
        // We need to run this in parallel to respect the timeout.
        final Set result = new HashSet(dnsArray.length * 5);
        if (dnsArray.length > 0) {
            List>> tasks = new ArrayList>>(dnsArray.length);
            for (final JmDNS mDNS : dnsArray) {
                tasks.add(new Callable>() {
                    @Override
                    public List call() throws Exception {
                        return Arrays.asList(mDNS.list(type, timeout));
                    }
                });
            }

            ExecutorService executor = Executors.newFixedThreadPool(tasks.size(), new NamedThreadFactory("JmmDNS.list"));
            try {
                List>> results = Collections.emptyList();
                try {
                    results = executor.invokeAll(tasks, timeout + 100, TimeUnit.MILLISECONDS);
                } catch (InterruptedException exception) {
                    logger.debug("Interrupted ", exception);
                    Thread.currentThread().interrupt();
                    // Will terminate next loop early.
                }

                for (Future> future : results) {
                    if (future.isCancelled()) {
                        continue;
                    }
                    try {
                        result.addAll(future.get());
                    } catch (InterruptedException exception) {
                        logger.debug("Interrupted ", exception);
                        Thread.currentThread().interrupt();
                    } catch (ExecutionException exception) {
                        logger.warn("Exception ", exception);
                    }
                }
            } finally {
                executor.shutdown();
            }
        }
        return result.toArray(new ServiceInfo[result.size()]);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#listBySubtype(java.lang.String)
     */
    @Override
    public Map listBySubtype(String type) {
        return this.listBySubtype(type, DNSConstants.SERVICE_INFO_TIMEOUT);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#listBySubtype(java.lang.String, long)
     */
    @Override
    public Map listBySubtype(final String type, final long timeout) {
        Map> map = new HashMap>(5);
        for (ServiceInfo info : this.list(type, timeout)) {
            String subtype = info.getSubtype();
            if (!map.containsKey(subtype)) {
                map.put(subtype, new ArrayList(10));
            }
            map.get(subtype).add(info);
        }

        Map result = new HashMap(map.size());
        for (final Map.Entry> entry : map.entrySet()) {
            final String subtype = entry.getKey();
            final List infoForSubType = entry.getValue();
            result.put(subtype, infoForSubType.toArray(new ServiceInfo[infoForSubType.size()]));
        }

        return result;
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#addNetworkTopologyListener(javax.jmdns.NetworkTopologyListener)
     */
    @Override
    public void addNetworkTopologyListener(NetworkTopologyListener listener) {
        _networkListeners.add(listener);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#removeNetworkTopologyListener(javax.jmdns.NetworkTopologyListener)
     */
    @Override
    public void removeNetworkTopologyListener(NetworkTopologyListener listener) {
        _networkListeners.remove(listener);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.JmmDNS#networkListeners()
     */
    @Override
    public NetworkTopologyListener[] networkListeners() {
        return _networkListeners.toArray(new NetworkTopologyListener[_networkListeners.size()]);
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.NetworkTopologyListener#inetAddressAdded(javax.jmdns.NetworkTopologyEvent)
     */
    @Override
    public void inetAddressAdded(NetworkTopologyEvent event) {
        InetAddress address = event.getInetAddress();
        try {
            if (!_knownMDNS.containsKey(address)) {
                synchronized (_knownMDNS) {
                    if (!_knownMDNS.containsKey(address)) {
                        final JmDNS dns = createJmDnsInstance(address);
                        if (_knownMDNS.putIfAbsent(address, dns) == null) {
                            // We need to register the services and listeners with the new JmDNS
                            final Collection types = _serviceTypes;
                            final Collection infos = _services.values();
                            final Collection typeListeners = _typeListeners;
                            final Map> serviceListeners = _serviceListeners;
                            _jmDNSExecutor.submit(new Runnable() {
                                /**
                                 * {@inheritDoc}
                                 */
                                @Override
                                public void run() {
                                    // Register Types
                                    for (String type : types) {
                                        dns.registerServiceType(type);
                                    }
                                    // Register services
                                    for (ServiceInfo info : infos) {
                                        try {
                                            dns.registerService(info.clone());
                                        } catch (IOException exception) {
                                            // logger.warn("Unexpected unhandled exception: " + exception);
                                        }
                                    }
                                    // Add ServiceType Listeners
                                    for (ServiceTypeListener listener : typeListeners) {
                                        try {
                                            dns.addServiceTypeListener(listener);
                                        } catch (IOException exception) {
                                            // logger.warn("Unexpected unhandled exception: " + exception);
                                        }
                                    }
                                    // Add Service Listeners
                                    for (final Map.Entry> entry : serviceListeners.entrySet()) {
                                        final String type = entry.getKey();
                                        final List listeners = entry.getValue();
                                        synchronized (listeners) {
                                            for (ServiceListener listener : listeners) {
                                                dns.addServiceListener(type, listener);
                                            }
                                        }
                                    }
                                }
                            });
                            final NetworkTopologyEvent jmdnsEvent = new NetworkTopologyEventImpl(dns, address);
                            for (final NetworkTopologyListener listener : this.networkListeners()) {
                                _listenerExecutor.submit(new Runnable() {
                                    /**
                                     * {@inheritDoc}
                                     */
                                    @Override
                                    public void run() {
                                        listener.inetAddressAdded(jmdnsEvent);
                                    }
                                });
                            }
                        } else {
                            dns.close();
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.warn("Unexpected unhandled exception: ", e);
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.jmdns.NetworkTopologyListener#inetAddressRemoved(javax.jmdns.NetworkTopologyEvent)
     */
    @Override
    public void inetAddressRemoved(NetworkTopologyEvent event) {
        InetAddress address = event.getInetAddress();
        try {
            if (_knownMDNS.containsKey(address)) {
                synchronized (_knownMDNS) {
                    if (_knownMDNS.containsKey(address)) {
                        JmDNS mDNS = _knownMDNS.remove(address);
                        mDNS.close();
                        final NetworkTopologyEvent jmdnsEvent = new NetworkTopologyEventImpl(mDNS, address);
                        for (final NetworkTopologyListener listener : this.networkListeners()) {
                            _listenerExecutor.submit(new Runnable() {
                                /**
                                 * {@inheritDoc}
                                 */
                                @Override
                                public void run() {
                                    listener.inetAddressRemoved(jmdnsEvent);
                                }
                            });
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.warn("Unexpected unhandled exception: ", e);
        }
    }

    /**
     * Checks the network state.
* If the network change, this class will reconfigure the list of DNS do adapt to the new configuration. */ static class NetworkChecker extends TimerTask { private final NetworkTopologyListener _mmDNS; private final NetworkTopologyDiscovery _topology; private Set _knownAddresses; public NetworkChecker(NetworkTopologyListener mmDNS, NetworkTopologyDiscovery topology) { super(); this._mmDNS = mmDNS; this._topology = topology; _knownAddresses = Collections.synchronizedSet(new HashSet()); } public void start(Timer timer) { // Run once up-front otherwise the list of servers will only appear after a delay. timer.schedule(this, 0, DNSConstants.NETWORK_CHECK_INTERVAL); } /** * {@inheritDoc} */ @Override public void run() { try { InetAddress[] curentAddresses = _topology.getInetAddresses(); Set current = new HashSet(curentAddresses.length); for (InetAddress address : curentAddresses) { current.add(address); if (!_knownAddresses.contains(address)) { final NetworkTopologyEvent event = new NetworkTopologyEventImpl(_mmDNS, address); _mmDNS.inetAddressAdded(event); } } for (InetAddress address : _knownAddresses) { if (!current.contains(address)) { final NetworkTopologyEvent event = new NetworkTopologyEventImpl(_mmDNS, address); _mmDNS.inetAddressRemoved(event); } } _knownAddresses = current; } catch (Exception e) { logger.warn("Unexpected unhandled exception: ", e); } } } protected JmDNS createJmDnsInstance(InetAddress address) throws IOException { return JmDNS.create(address); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy