summaryrefslogtreecommitdiff
path: root/src/javax/jmdns/impl/JmmDNSImpl.java
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@google.com>2012-03-21 12:26:23 -0700
committerMike Lockwood <lockwood@google.com>2012-03-21 12:26:23 -0700
commitf4eb7466d5c09098f9dc54137ed3235e3c43fc9f (patch)
tree56e1bf5e433e60e3a18d5a9d08b7d55a64d8ae1d /src/javax/jmdns/impl/JmmDNSImpl.java
parent19376825c9e562c188aef9ccd09a7220bd3c0a20 (diff)
parent76f0067cea0428b683cba2f187d81e723658f964 (diff)
downloadjmdns-f4eb7466d5c09098f9dc54137ed3235e3c43fc9f.tar.gz
Merge remote-tracking branch 'goog/ics-aah-exp'android-wear-n-preview-3android-wear-n-preview-2android-wear-n-preview-1android-wear-7.1.1_r1android-wear-5.1.1_r1android-wear-5.1.0_r1android-wear-5.0.0_r1android-sdk-support_r11android-sdk-4.4.2_r1.0.1android-sdk-4.4.2_r1android-n-preview-5android-n-preview-4android-n-preview-3android-n-preview-2android-n-preview-1android-n-iot-preview-2android-m-preview-2android-m-preview-1android-m-previewandroid-l-preview_r2android-cts-6.0_r9android-cts-6.0_r8android-cts-6.0_r7android-cts-6.0_r6android-cts-6.0_r5android-cts-6.0_r4android-cts-6.0_r32android-cts-6.0_r31android-cts-6.0_r30android-cts-6.0_r3android-cts-6.0_r29android-cts-6.0_r28android-cts-6.0_r27android-cts-6.0_r26android-cts-6.0_r25android-cts-6.0_r24android-cts-6.0_r23android-cts-6.0_r22android-cts-6.0_r21android-cts-6.0_r20android-cts-6.0_r2android-cts-6.0_r19android-cts-6.0_r18android-cts-6.0_r17android-cts-6.0_r16android-cts-6.0_r15android-cts-6.0_r14android-cts-6.0_r13android-cts-6.0_r12android-cts-6.0_r1android-cts-5.1_r9android-cts-5.1_r8android-cts-5.1_r7android-cts-5.1_r6android-cts-5.1_r5android-cts-5.1_r4android-cts-5.1_r3android-cts-5.1_r28android-cts-5.1_r27android-cts-5.1_r26android-cts-5.1_r25android-cts-5.1_r24android-cts-5.1_r23android-cts-5.1_r22android-cts-5.1_r21android-cts-5.1_r20android-cts-5.1_r2android-cts-5.1_r19android-cts-5.1_r18android-cts-5.1_r17android-cts-5.1_r16android-cts-5.1_r15android-cts-5.1_r14android-cts-5.1_r13android-cts-5.1_r10android-cts-5.1_r1android-cts-5.0_r9android-cts-5.0_r8android-cts-5.0_r7android-cts-5.0_r6android-cts-5.0_r5android-cts-5.0_r4android-cts-5.0_r3android-cts-4.4_r4android-cts-4.4_r1android-cts-4.2_r2android-cts-4.2_r1android-cts-4.1_r4android-cts-4.1_r2android-cts-4.1_r1android-6.0.1_r9android-6.0.1_r81android-6.0.1_r80android-6.0.1_r8android-6.0.1_r79android-6.0.1_r78android-6.0.1_r77android-6.0.1_r74android-6.0.1_r73android-6.0.1_r72android-6.0.1_r70android-6.0.1_r7android-6.0.1_r69android-6.0.1_r68android-6.0.1_r67android-6.0.1_r66android-6.0.1_r65android-6.0.1_r63android-6.0.1_r62android-6.0.1_r61android-6.0.1_r60android-6.0.1_r59android-6.0.1_r58android-6.0.1_r57android-6.0.1_r56android-6.0.1_r55android-6.0.1_r54android-6.0.1_r53android-6.0.1_r52android-6.0.1_r51android-6.0.1_r50android-6.0.1_r5android-6.0.1_r49android-6.0.1_r48android-6.0.1_r47android-6.0.1_r46android-6.0.1_r45android-6.0.1_r43android-6.0.1_r42android-6.0.1_r41android-6.0.1_r40android-6.0.1_r4android-6.0.1_r33android-6.0.1_r32android-6.0.1_r31android-6.0.1_r30android-6.0.1_r3android-6.0.1_r28android-6.0.1_r27android-6.0.1_r26android-6.0.1_r25android-6.0.1_r24android-6.0.1_r22android-6.0.1_r21android-6.0.1_r20android-6.0.1_r18android-6.0.1_r17android-6.0.1_r16android-6.0.1_r13android-6.0.1_r12android-6.0.1_r11android-6.0.1_r10android-6.0.1_r1android-6.0.0_r7android-6.0.0_r6android-6.0.0_r5android-6.0.0_r41android-6.0.0_r4android-6.0.0_r3android-6.0.0_r26android-6.0.0_r25android-6.0.0_r24android-6.0.0_r23android-6.0.0_r2android-6.0.0_r13android-6.0.0_r12android-6.0.0_r11android-6.0.0_r1android-5.1.1_r9android-5.1.1_r8android-5.1.1_r7android-5.1.1_r6android-5.1.1_r5android-5.1.1_r4android-5.1.1_r38android-5.1.1_r37android-5.1.1_r36android-5.1.1_r35android-5.1.1_r34android-5.1.1_r33android-5.1.1_r30android-5.1.1_r3android-5.1.1_r29android-5.1.1_r28android-5.1.1_r26android-5.1.1_r25android-5.1.1_r24android-5.1.1_r23android-5.1.1_r22android-5.1.1_r20android-5.1.1_r2android-5.1.1_r19android-5.1.1_r18android-5.1.1_r17android-5.1.1_r16android-5.1.1_r15android-5.1.1_r14android-5.1.1_r13android-5.1.1_r12android-5.1.1_r10android-5.1.1_r1android-5.1.0_r5android-5.1.0_r4android-5.1.0_r3android-5.1.0_r1android-5.0.2_r3android-5.0.2_r1android-5.0.1_r1android-5.0.0_r7android-5.0.0_r6android-5.0.0_r5.1android-5.0.0_r5android-5.0.0_r4android-5.0.0_r3android-5.0.0_r2android-5.0.0_r1android-4.4w_r1android-4.4_r1.2.0.1android-4.4_r1.2android-4.4_r1.1.0.1android-4.4_r1.1android-4.4_r1.0.1android-4.4_r1android-4.4_r0.9android-4.4_r0.8android-4.4_r0.7android-4.4.4_r2.0.1android-4.4.4_r2android-4.4.4_r1.0.1android-4.4.4_r1android-4.4.3_r1.1.0.1android-4.4.3_r1.1android-4.4.3_r1.0.1android-4.4.3_r1android-4.4.2_r2.0.1android-4.4.2_r2android-4.4.2_r1.0.1android-4.4.2_r1android-4.4.1_r1.0.1android-4.4.1_r1android-4.3_r3.1android-4.3_r3android-4.3_r2.3android-4.3_r2.2android-4.3_r2.1android-4.3_r2android-4.3_r1.1android-4.3_r1android-4.3_r0.9.1android-4.3_r0.9android-4.3.1_r1android-4.2_r1android-4.2.2_r1.2android-4.2.2_r1.1android-4.2.2_r1android-4.2.1_r1.2android-4.2.1_r1.1android-4.2.1_r1android-4.1.2_r2.1android-4.1.2_r2android-4.1.2_r1android-4.1.1_r6.1android-4.1.1_r6android-4.1.1_r5android-4.1.1_r4android-4.1.1_r3android-4.1.1_r2android-4.1.1_r1.1android-4.1.1_r1tools_r22.2tools_r22tools_r21nougat-mr1-wear-releasen-iot-preview-2master-soongmarshmallow-releasemarshmallow-mr3-releasemarshmallow-mr2-releasemarshmallow-mr1-releasemarshmallow-mr1-devmarshmallow-dr1.6-releasemarshmallow-dr1.5-releasemarshmallow-dr1.5-devmarshmallow-dr-releasemarshmallow-dr-dragon-releasemarshmallow-dr-devmarshmallow-devmarshmallow-cts-releaselollipop-wear-releaselollipop-releaselollipop-mr1-wfc-releaselollipop-mr1-releaselollipop-mr1-fi-releaselollipop-mr1-devlollipop-mr1-cts-releaselollipop-devlollipop-cts-releasel-previewkitkat-wearkitkat-releasekitkat-mr2.2-releasekitkat-mr2.1-releasekitkat-mr2-releasekitkat-mr1.1-releasekitkat-mr1-releasekitkat-devkitkat-cts-releasekitkat-cts-devjb-releasejb-mr2.0.0-releasejb-mr2.0-releasejb-mr2-releasejb-mr2-devjb-mr1.1-releasejb-mr1.1-dev-plus-aospjb-mr1.1-devjb-mr1-releasejb-mr1-dev-plus-aospjb-mr1-devjb-mr0-releasejb-devidea133-weekly-releaseidea133
Diffstat (limited to 'src/javax/jmdns/impl/JmmDNSImpl.java')
-rw-r--r--src/javax/jmdns/impl/JmmDNSImpl.java599
1 files changed, 599 insertions, 0 deletions
diff --git a/src/javax/jmdns/impl/JmmDNSImpl.java b/src/javax/jmdns/impl/JmmDNSImpl.java
new file mode 100644
index 0000000..3eb78f1
--- /dev/null
+++ b/src/javax/jmdns/impl/JmmDNSImpl.java
@@ -0,0 +1,599 @@
+/**
+ *
+ */
+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&eacute;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);
+ }
+ }
+
+ }
+
+}