001package jmri.util.zeroconf; 002 003import java.util.ArrayList; 004import java.util.Arrays; 005import java.util.List; 006import javax.annotation.Nonnull; 007import javax.jmdns.JmDNS; 008import javax.jmdns.NetworkTopologyEvent; 009import javax.jmdns.NetworkTopologyListener; 010import javax.jmdns.ServiceEvent; 011import javax.jmdns.ServiceInfo; 012import javax.jmdns.ServiceListener; 013import jmri.InstanceManager; 014import org.slf4j.Logger; 015import org.slf4j.LoggerFactory; 016 017public class ZeroConfClient { 018 019 private ServiceListener mdnsServiceListener = null; 020 private final static Logger log = LoggerFactory.getLogger(ZeroConfClient.class); 021 022 // mdns related routines. 023 public void startServiceListener(@Nonnull String service) { 024 log.debug("StartServiceListener called for service: {}", service); 025 if (mdnsServiceListener == null) { 026 mdnsServiceListener = new NetworkServiceListener(service, this); 027 } 028 for (JmDNS server : InstanceManager.getDefault(ZeroConfServiceManager.class).getDNSes().values()) { 029 server.addServiceListener(service, mdnsServiceListener); 030 } 031 } 032 033 public void stopServiceListener(@Nonnull String service) { 034 for (JmDNS server : InstanceManager.getDefault(ZeroConfServiceManager.class).getDNSes().values()) { 035 server.removeServiceListener(service, mdnsServiceListener); 036 } 037 } 038 039 /** 040 * Request the first service of a particular service. 041 * 042 * @param service string service getName 043 * @return JmDNS service entry for the first service of a particular 044 * service. 045 */ 046 public ServiceInfo getService(@Nonnull String service) { 047 for (JmDNS server : InstanceManager.getDefault(ZeroConfServiceManager.class).getDNSes().values()) { 048 ServiceInfo[] infos = server.list(service); 049 if (infos != null) { 050 return infos[0]; 051 } 052 } 053 return null; 054 } 055 056 /** 057 * Get all servers providing the specified service. 058 * 059 * @param service the name of service as generated using 060 * {@link jmri.util.zeroconf.ZeroConfServiceManager#key(java.lang.String, java.lang.String) } 061 * @return A list of servers or an empty list. 062 */ 063 @Nonnull 064 public List<ServiceInfo> getServices(@Nonnull String service) { 065 ArrayList<ServiceInfo> services = new ArrayList<>(); 066 for (JmDNS server : InstanceManager.getDefault(ZeroConfServiceManager.class).getDNSes().values()) { 067 if (server.list(service) != null) { 068 services.addAll(Arrays.asList(server.list(service))); 069 } 070 } 071 return services; 072 } 073 074 /** 075 * Request the first service of a particular service on a specified host. 076 * 077 * @param service string service service 078 * @param hostname string host name 079 * @return JmDNS service entry for the first service of a particular service 080 * on the specified host.. 081 */ 082 public ServiceInfo getServiceOnHost(@Nonnull String service, @Nonnull String hostname) { 083 for (JmDNS server : InstanceManager.getDefault(ZeroConfServiceManager.class).getDNSes().values()) { 084 ServiceInfo[] infos = server.list(service); 085 for (ServiceInfo info : infos) { 086 if (info.getServer().equals(hostname)) { 087 return info; 088 } 089 } 090 } 091 return null; 092 } 093 094 /** 095 * Request the first service of a particular service with a particular 096 * service name. 097 * 098 * @param service string service service 099 * @param adName string qualified service advertisement name 100 * @return JmDNS service entry for the first service of a particular service 101 * on the specified host.. 102 */ 103 public ServiceInfo getServicebyAdName(@Nonnull String service, @Nonnull String adName) { 104 for (JmDNS server : InstanceManager.getDefault(ZeroConfServiceManager.class).getDNSes().values()) { 105 ServiceInfo[] infos = server.list(service); 106 for (ServiceInfo info : infos) { 107 log.debug("Found Name: {}", info.getQualifiedName()); 108 if (info.getQualifiedName().equals(adName)) { 109 return info; 110 } 111 } 112 } 113 return null; 114 } 115 116 @Nonnull 117 public String[] getHostList(@Nonnull String service) { 118 ArrayList<String> hostlist = new ArrayList<>(); 119 for (JmDNS server : InstanceManager.getDefault(ZeroConfServiceManager.class).getDNSes().values()) { 120 ServiceInfo[] infos = server.list(service); 121 for (ServiceInfo info : infos) { 122 hostlist.add(info.getServer()); 123 } 124 } 125 return hostlist.toArray(new String[hostlist.size()]); 126 } 127 128 public static class NetworkServiceListener implements ServiceListener, NetworkTopologyListener { 129 130 private final String service; 131 private final ZeroConfClient client; 132 133 protected NetworkServiceListener(String service, ZeroConfClient client) { 134 this.service = service; 135 this.client = client; 136 } 137 138 @Override 139 public void inetAddressAdded(NetworkTopologyEvent nte) { 140 nte.getDNS().addServiceListener(service, this); 141 } 142 143 @Override 144 public void inetAddressRemoved(NetworkTopologyEvent nte) { 145 nte.getDNS().removeServiceListener(service, this); 146 } 147 148 @Override 149 public void serviceAdded(ServiceEvent se) { 150 log.debug("Service added: {}", se.getInfo().toString()); 151 // notify the client when a service is added. 152 synchronized (client) { 153 client.notifyAll(); 154 } 155 } 156 157 @Override 158 public void serviceRemoved(ServiceEvent se) { 159 log.debug("Service removed: {}", se.getInfo().toString()); 160 } 161 162 @Override 163 public void serviceResolved(ServiceEvent se) { 164 log.debug("Service resolved: {}", se.getInfo().toString()); 165 } 166 167 } 168}