/external/jmdns/src/javax/jmdns/impl/JmmDNSImpl.java
https://gitlab.com/brian0218/rk3066_r-box_android4.2.2_sdk · Java · 599 lines · 375 code · 52 blank · 172 comment · 32 complexity · f4b2fc8e0018a3879502f4eff6aab845 MD5 · raw file
- /**
- *
- */
- package javax.jmdns.impl;
- import java.io.IOException;
- import java.net.InetAddress;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.Timer;
- import java.util.TimerTask;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.ConcurrentMap;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.TimeUnit;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- 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;
- /**
- * This class enable multihomming 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 = Logger.getLogger(JmmDNSImpl.class.getName());
- private final Set<NetworkTopologyListener> _networkListeners;
- /**
- * Every JmDNS created.
- */
- private final ConcurrentMap<InetAddress, JmDNS> _knownMDNS;
- /**
- * This enable the service info text update.
- */
- private final ConcurrentMap<String, ServiceInfo> _services;
- private final ExecutorService _ListenerExecutor;
- private final ExecutorService _jmDNSExecutor;
- private final Timer _timer;
- /**
- *
- */
- public JmmDNSImpl() {
- super();
- _networkListeners = Collections.synchronizedSet(new HashSet<NetworkTopologyListener>());
- _knownMDNS = new ConcurrentHashMap<InetAddress, JmDNS>();
- _services = new ConcurrentHashMap<String, ServiceInfo>(20);
- _ListenerExecutor = Executors.newSingleThreadExecutor();
- _jmDNSExecutor = Executors.newCachedThreadPool();
- _timer = new Timer("Multihommed mDNS.Timer", true);
- (new NetworkChecker(this, NetworkTopologyDiscovery.Factory.getInstance())).start(_timer);
- }
- /*
- * (non-Javadoc)
- * @see java.io.Closeable#close()
- */
- @Override
- public void close() throws IOException {
- if (logger.isLoggable(Level.FINER)) {
- logger.finer("Cancelling JmmDNS: " + this);
- }
- _timer.cancel();
- _ListenerExecutor.shutdown();
- // We need to cancel all the DNS
- ExecutorService executor = Executors.newCachedThreadPool();
- for (final JmDNS mDNS : _knownMDNS.values()) {
- 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
- }
- }
- });
- }
- executor.shutdown();
- try {
- executor.awaitTermination(DNSConstants.CLOSE_TIMEOUT, TimeUnit.MILLISECONDS);
- } catch (InterruptedException exception) {
- logger.log(Level.WARNING, "Exception ", exception);
- }
- _knownMDNS.clear();
- }
- /*
- * (non-Javadoc)
- * @see javax.jmdns.JmmDNS#getNames()
- */
- @Override
- public String[] getNames() {
- Set<String> result = new HashSet<String>();
- for (JmDNS mDNS : _knownMDNS.values()) {
- result.add(mDNS.getName());
- }
- return result.toArray(new String[result.size()]);
- }
- /*
- * (non-Javadoc)
- * @see javax.jmdns.JmmDNS#getHostNames()
- */
- @Override
- public String[] getHostNames() {
- Set<String> result = new HashSet<String>();
- for (JmDNS mDNS : _knownMDNS.values()) {
- 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<InetAddress> result = new HashSet<InetAddress>();
- for (JmDNS mDNS : _knownMDNS.values()) {
- result.add(mDNS.getInetAddress());
- }
- return result.toArray(new InetAddress[result.size()]);
- }
- /*
- * (non-Javadoc)
- * @see javax.jmdns.JmmDNS#getInterfaces()
- */
- @Override
- @Deprecated
- public InetAddress[] getInterfaces() throws IOException {
- Set<InetAddress> result = new HashSet<InetAddress>();
- for (JmDNS mDNS : _knownMDNS.values()) {
- 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 Set<ServiceInfo> result = Collections.synchronizedSet(new HashSet<ServiceInfo>(_knownMDNS.size()));
- ExecutorService executor = Executors.newCachedThreadPool();
- for (final JmDNS mDNS : _knownMDNS.values()) {
- executor.submit(new Runnable() {
- /**
- * {@inheritDoc}
- */
- @Override
- public void run() {
- result.add(mDNS.getServiceInfo(type, name, persistent, timeout));
- }
- });
- }
- executor.shutdown();
- try {
- executor.awaitTermination(timeout, TimeUnit.MILLISECONDS);
- } catch (InterruptedException exception) {
- logger.log(Level.WARNING, "Exception ", exception);
- }
- 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 : _knownMDNS.values()) {
- _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 {
- for (JmDNS mDNS : _knownMDNS.values()) {
- mDNS.addServiceTypeListener(listener);
- }
- }
- /*
- * (non-Javadoc)
- * @see javax.jmdns.JmmDNS#removeServiceTypeListener(javax.jmdns.ServiceTypeListener)
- */
- @Override
- public void removeServiceTypeListener(ServiceTypeListener listener) {
- for (JmDNS mDNS : _knownMDNS.values()) {
- mDNS.removeServiceTypeListener(listener);
- }
- }
- /*
- * (non-Javadoc)
- * @see javax.jmdns.JmmDNS#addServiceListener(java.lang.String, javax.jmdns.ServiceListener)
- */
- @Override
- public void addServiceListener(String type, ServiceListener listener) {
- for (JmDNS mDNS : _knownMDNS.values()) {
- 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) {
- for (JmDNS mDNS : _knownMDNS.values()) {
- 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) {
- synchronized (_services) {
- for (JmDNS mDNS : _knownMDNS.values()) {
- ServiceInfo info = ((JmDNSImpl) mDNS).getServices().get(target.getQualifiedName());
- if (info != null) {
- info.setText(value);
- } else {
- logger.warning("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 {
- // 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 : _knownMDNS.values()) {
- 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) {
- synchronized (_services) {
- for (JmDNS mDNS : _knownMDNS.values()) {
- mDNS.unregisterService(info);
- }
- ((ServiceInfoImpl) info).setDelegate(null);
- _services.remove(info.getQualifiedName());
- }
- }
- /*
- * (non-Javadoc)
- * @see javax.jmdns.JmmDNS#unregisterAllServices()
- */
- @Override
- public void unregisterAllServices() {
- synchronized (_services) {
- for (JmDNS mDNS : _knownMDNS.values()) {
- mDNS.unregisterAllServices();
- }
- _services.clear();
- }
- }
- /*
- * (non-Javadoc)
- * @see javax.jmdns.JmmDNS#registerServiceType(java.lang.String)
- */
- @Override
- public void registerServiceType(String type) {
- for (JmDNS mDNS : _knownMDNS.values()) {
- 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) {
- // We need to run this in parallel to respect the timeout.
- final Set<ServiceInfo> result = Collections.synchronizedSet(new HashSet<ServiceInfo>(_knownMDNS.size() * 5));
- ExecutorService executor = Executors.newCachedThreadPool();
- for (final JmDNS mDNS : _knownMDNS.values()) {
- executor.submit(new Runnable() {
- /**
- * {@inheritDoc}
- */
- @Override
- public void run() {
- result.addAll(Arrays.asList(mDNS.list(type, timeout)));
- }
- });
- }
- executor.shutdown();
- try {
- executor.awaitTermination(timeout, TimeUnit.MILLISECONDS);
- } catch (InterruptedException exception) {
- logger.log(Level.WARNING, "Exception ", exception);
- }
- return result.toArray(new ServiceInfo[result.size()]);
- }
- /*
- * (non-Javadoc)
- * @see javax.jmdns.JmmDNS#listBySubtype(java.lang.String)
- */
- @Override
- public Map<String, ServiceInfo[]> 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<String, ServiceInfo[]> listBySubtype(final String type, final long timeout) {
- Map<String, List<ServiceInfo>> map = new HashMap<String, List<ServiceInfo>>(5);
- for (ServiceInfo info : this.list(type, timeout)) {
- String subtype = info.getSubtype();
- if (!map.containsKey(subtype)) {
- map.put(subtype, new ArrayList<ServiceInfo>(10));
- }
- map.get(subtype).add(info);
- }
- Map<String, ServiceInfo[]> result = new HashMap<String, ServiceInfo[]>(map.size());
- for (String subtype : map.keySet()) {
- List<ServiceInfo> infoForSubType = map.get(subtype);
- 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 {
- synchronized (this) {
- if (!_knownMDNS.containsKey(address)) {
- _knownMDNS.put(address, JmDNS.create(address));
- final NetworkTopologyEvent jmdnsEvent = new NetworkTopologyEventImpl(_knownMDNS.get(address), address);
- for (final NetworkTopologyListener listener : this.networkListeners()) {
- _ListenerExecutor.submit(new Runnable() {
- /**
- * {@inheritDoc}
- */
- @Override
- public void run() {
- listener.inetAddressAdded(jmdnsEvent);
- }
- });
- }
- }
- }
- } catch (Exception e) {
- logger.warning("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 {
- synchronized (this) {
- 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.warning("Unexpected unhandled exception: " + e);
- }
- }
- /**
- * Checks the network state.<br/>
- * If the network change, this class will reconfigure the list of DNS do adapt to the new configuration.
- */
- static class NetworkChecker extends TimerTask {
- private static Logger logger1 = Logger.getLogger(NetworkChecker.class.getName());
- private final NetworkTopologyListener _mmDNS;
- private final NetworkTopologyDiscovery _topology;
- private Set<InetAddress> _knownAddresses;
- public NetworkChecker(NetworkTopologyListener mmDNS, NetworkTopologyDiscovery topology) {
- super();
- this._mmDNS = mmDNS;
- this._topology = topology;
- _knownAddresses = Collections.synchronizedSet(new HashSet<InetAddress>());
- }
- public void start(Timer timer) {
- timer.schedule(this, 0, DNSConstants.NETWORK_CHECK_INTERVAL);
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void run() {
- try {
- InetAddress[] curentAddresses = _topology.getInetAddresses();
- Set<InetAddress> current = new HashSet<InetAddress>(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) {
- logger1.warning("Unexpected unhandled exception: " + e);
- }
- }
- }
- }