/** Stop advertising the service. */ public void stop() { log.debug("Stopping ZeroConfService {}", this.key()); if (ZeroConfService.services().containsKey(this.key())) { ZeroConfService.netServices() .values() .stream() .forEach( (netService) -> { try { try { log.debug("Unregistering {} from {}", this.key(), netService.getInetAddress()); netService.unregisterService( this.serviceInfos.get(netService.getInetAddress())); this.serviceInfos.remove(netService.getInetAddress()); this.listeners .stream() .forEach( (listener) -> { listener.serviceUnpublished( new ZeroConfServiceEvent(this, netService)); }); } catch (NullPointerException ex) { log.debug( "{} already unregistered from {}", this.key(), netService.getInetAddress()); } } catch (IOException ex) { log.error( "Unable to stop ZeroConfService {}. {}", this.key(), ex.getLocalizedMessage()); } }); ZeroConfService.services().remove(key()); } }
private static void stopAll(final boolean close) { log.debug("Stopping all ZeroConfServices"); ZeroConfService.netServices() .values() .stream() .forEach( (netService) -> { new Thread() { @Override public void run() { netService.unregisterAllServices(); if (close) { try { netService.close(); } catch (IOException ex) { log.debug("jmdns.close() returned IOException: {}", ex.getMessage()); } } } }.start(); }); ZeroConfService.services().clear(); }
@Override public void inetAddressAdded(NetworkTopologyEvent nte) { if (nte.getInetAddress() instanceof Inet6Address && !ProfileUtils.getPreferences( ProfileManager.getDefault().getActiveProfile(), ZeroConfService.class, false) .getBoolean(ZeroConfService.IPv6, true)) { log.debug("Ignoring IPv6 address {}", nte.getInetAddress().getHostAddress()); return; } if (nte.getInetAddress() instanceof Inet4Address && !ProfileUtils.getPreferences( ProfileManager.getDefault().getActiveProfile(), ZeroConfService.class, false) .getBoolean(ZeroConfService.IPv4, true)) { log.debug("Ignoring IPv4 address {}", nte.getInetAddress().getHostAddress()); return; } if (!ZeroConfService.netServices.containsKey(nte.getInetAddress())) { log.debug("Adding address {}", nte.getInetAddress().getHostAddress()); ZeroConfService.netServices.put(nte.getInetAddress(), nte.getDNS()); ZeroConfService.allServices() .stream() .forEach( (service) -> { try { if (!service.serviceInfos.containsKey(nte.getDNS().getInetAddress())) { log.debug( "Publishing zeroConf service for '{}' on {}", service.key(), nte.getInetAddress().getHostAddress()); nte.getDNS().registerService(service.addServiceInfo(nte.getDNS())); service .listeners .stream() .forEach( (listener) -> { listener.servicePublished( new ZeroConfServiceEvent(service, nte.getDNS())); }); } } catch (IOException ex) { log.error(ex.getLocalizedMessage(), ex); } }); } else { log.debug("Address {} already known.", nte.getInetAddress().getHostAddress()); } }
@Override public void inetAddressRemoved(NetworkTopologyEvent nte) { log.debug("Removing address {}", nte.getInetAddress().toString()); ZeroConfService.netServices.remove(nte.getInetAddress()); nte.getDNS().unregisterAllServices(); ZeroConfService.allServices() .stream() .map( (service) -> { service.serviceInfos.remove(nte.getInetAddress()); return service; }) .forEach( (service) -> { service .listeners .stream() .forEach( (listener) -> { listener.servicePublished( new ZeroConfServiceEvent(service, nte.getDNS())); }); }); }
/** * Create a ZeroConfService. The property <i>version</i> is added or replaced with the current * JMRI version as its value. The property <i>jmri</i> is added or replaced with the JMRI * major.minor.test version string as its value. * * <p>If a service with the same key as the new service is already published, the original service * is returned unmodified. * * @param type The service protocol * @param name The name of the JMRI server listed on client devices * @param port The port the service runs over * @param weight Default value is 0 * @param priority Default value is 0 * @param properties Additional information to be listed in service advertisement * @return An unpublished ZeroConfService */ public static ZeroConfService create( String type, String name, int port, int weight, int priority, HashMap<String, String> properties) { ZeroConfService s; if (ZeroConfService.services().containsKey(ZeroConfService.key(type, name))) { s = ZeroConfService.services().get(ZeroConfService.key(type, name)); log.debug("Using existing ZeroConfService {}", s.key()); } else { properties.put("version", jmri.Version.name()); // use the major.minor.test version string for jmri since we have potentially // tight space constraints in terms of the number of bytes that properties // can use, and there are some unconstrained properties that we would like to use. properties.put("jmri", jmri.Version.getCanonicalVersion()); properties.put("node", NodeIdentity.identity()); s = new ZeroConfService(ServiceInfo.create(type, name, port, weight, priority, properties)); log.debug("Creating new ZeroConfService {} with properties {}", s.key(), properties); } return s; }
@Override public boolean execute() { ZeroConfService.stopAll(true); JmmDNS.Factory.getInstance().removeNetworkTopologyListener(ZeroConfService.networkListener); return true; }
/** * Return the fully qualified domain name or "computer" if the system name cannot be determined. * This method uses the {@link javax.jmdns.JmDNS#getHostName()} method to get the name. * * @param address The {@link java.net.InetAddress} for the FQDN. * @return The fully qualified domain name. */ public static String FQDN(InetAddress address) { return ZeroConfService.netServices().get(address).getHostName(); }
/** * Return the system name or "computer" if the system name cannot be determined. This method * returns the first part of the fully qualified domain name from {@link #FQDN}. * * @param address The {@link java.net.InetAddress} for the host name. * @return The hostName associated with the first interface encountered. */ public static String hostName(InetAddress address) { String hostName = ZeroConfService.FQDN(address) + "."; // we would have to check for the existance of . if we did not add . // to the string above. return hostName.substring(0, hostName.indexOf('.')); }
/** * A list of published ZeroConfServices * * @return Collection of ZeroConfServices */ public static Collection<ZeroConfService> allServices() { return ZeroConfService.services().values(); }
/** Stop advertising all services. */ public static void stopAll() { ZeroConfService.stopAll(false); }
/** Start advertising the service. */ public void publish() { if (!isPublished()) { ZeroConfService.services.put(this.key(), this); this.listeners .stream() .forEach( (listener) -> { listener.serviceQueued(new ZeroConfServiceEvent(this, null)); }); boolean useIPv4 = ProfileUtils.getPreferences( ProfileManager.getDefault().getActiveProfile(), ZeroConfService.class, false) .getBoolean(ZeroConfService.IPv4, true); boolean useIPv6 = ProfileUtils.getPreferences( ProfileManager.getDefault().getActiveProfile(), ZeroConfService.class, false) .getBoolean(ZeroConfService.IPv6, true); for (JmDNS netService : ZeroConfService.netServices().values()) { ZeroConfServiceEvent event; ServiceInfo info; try { if (netService.getInetAddress() instanceof Inet6Address && !useIPv6) { // Skip if address is IPv6 and should not be advertised on log.debug("Ignoring IPv6 address {}", netService.getInetAddress().getHostAddress()); continue; } if (netService.getInetAddress() instanceof Inet4Address && !useIPv4) { // Skip if address is IPv4 and should not be advertised on log.debug("Ignoring IPv4 address {}", netService.getInetAddress().getHostAddress()); continue; } try { log.debug( "Publishing ZeroConfService for '{}' on {}", key(), netService.getInetAddress().getHostAddress()); } catch (IOException ex) { log.debug( "Publishing ZeroConfService for '{}' with IOException {}", key(), ex.getLocalizedMessage(), ex); } // JmDNS requires a 1-to-1 mapping of serviceInfo to InetAddress if (!this.serviceInfos.containsKey(netService.getInetAddress())) { try { info = this.serviceInfo(); netService.registerService(info); log.debug( "Register service '{}' on {} successful.", this.key(), netService.getInetAddress().getHostAddress()); } catch (IllegalStateException ex) { // thrown if the reference serviceInfo object is in use try { log.debug( "Initial attempt to register '{}' on {} failed.", this.key(), netService.getInetAddress().getHostAddress()); info = this.addServiceInfo(netService); log.debug( "Retrying register '{}' on {}.", this.key(), netService.getInetAddress().getHostAddress()); netService.registerService(info); } catch (IllegalStateException ex1) { // thrown if service gets registered on interface by // the networkListener before this loop on interfaces // completes, so we only ensure a later notification // is not posted continuing to next interface in list log.debug( "'{}' is already registered on {}.", this.key(), netService.getInetAddress().getHostAddress()); continue; } } } else { log.debug( "skipping '{}' on {}, already in serviceInfos.", this.key(), netService.getInetAddress().getHostAddress()); } event = new ZeroConfServiceEvent(this, netService); } catch (IOException ex) { log.error("Unable to publish service for '{}': {}", key(), ex.getMessage()); continue; } this.listeners .stream() .forEach( (listener) -> { listener.servicePublished(event); }); } } }
/** * Get the state of the service. * * @return True if the service is being advertised, and false otherwise. */ public Boolean isPublished() { return ZeroConfService.services().containsKey(key()); }