00001
00004 package javax.jmdns.impl;
00005
00006 import java.io.IOException;
00007 import java.net.InetAddress;
00008 import java.util.ArrayList;
00009 import java.util.Arrays;
00010 import java.util.Collections;
00011 import java.util.HashMap;
00012 import java.util.HashSet;
00013 import java.util.List;
00014 import java.util.Map;
00015 import java.util.Set;
00016 import java.util.Timer;
00017 import java.util.TimerTask;
00018 import java.util.concurrent.ConcurrentHashMap;
00019 import java.util.concurrent.ConcurrentMap;
00020 import java.util.concurrent.ExecutorService;
00021 import java.util.concurrent.Executors;
00022 import java.util.concurrent.TimeUnit;
00023 import java.util.logging.Level;
00024 import java.util.logging.Logger;
00025
00026 import javax.jmdns.JmDNS;
00027 import javax.jmdns.JmmDNS;
00028 import javax.jmdns.NetworkTopologyDiscovery;
00029 import javax.jmdns.NetworkTopologyEvent;
00030 import javax.jmdns.NetworkTopologyListener;
00031 import javax.jmdns.ServiceInfo;
00032 import javax.jmdns.ServiceListener;
00033 import javax.jmdns.ServiceTypeListener;
00034 import javax.jmdns.impl.constants.DNSConstants;
00035
00041 public class JmmDNSImpl implements JmmDNS, NetworkTopologyListener, ServiceInfoImpl.Delegate {
00042 private static Logger logger = Logger.getLogger(JmmDNSImpl.class.getName());
00043
00044 private final Set<NetworkTopologyListener> _networkListeners;
00045
00049 private final ConcurrentMap<InetAddress, JmDNS> _knownMDNS;
00050
00054 private final ConcurrentMap<String, ServiceInfo> _services;
00055
00056 private final ExecutorService _ListenerExecutor;
00057
00058 private final ExecutorService _jmDNSExecutor;
00059
00060 private final Timer _timer;
00061
00062 private boolean is_closed;
00063
00067 public JmmDNSImpl() {
00068 super();
00069 _networkListeners = Collections.synchronizedSet(new HashSet<NetworkTopologyListener>());
00070 _knownMDNS = new ConcurrentHashMap<InetAddress, JmDNS>();
00071 _services = new ConcurrentHashMap<String, ServiceInfo>(20);
00072 _ListenerExecutor = Executors.newSingleThreadExecutor();
00073 _jmDNSExecutor = Executors.newCachedThreadPool();
00074 _timer = new Timer("Multihommed mDNS.Timer", true);
00075 boolean is_closed = false;
00076 (new NetworkChecker(this, NetworkTopologyDiscovery.Factory.getInstance())).start(_timer);
00077 }
00078
00079 public boolean isClosed() {
00080 return is_closed;
00081 }
00082
00083
00084
00085
00086
00087 @Override
00088 public void close() throws IOException {
00089 is_closed = true;
00090 if (logger.isLoggable(Level.FINER)) {
00091 logger.finer("Cancelling JmmDNS: " + this);
00092 }
00093 _timer.cancel();
00094 _ListenerExecutor.shutdown();
00095
00096 ExecutorService executor = Executors.newCachedThreadPool();
00097 for (final JmDNS mDNS : _knownMDNS.values()) {
00098 executor.submit(new Runnable() {
00102 @Override
00103 public void run() {
00104 try {
00105 mDNS.close();
00106 } catch (IOException exception) {
00107
00108 }
00109 }
00110 });
00111 }
00112 executor.shutdown();
00113 try {
00114 executor.awaitTermination(DNSConstants.CLOSE_TIMEOUT, TimeUnit.MILLISECONDS);
00115 } catch (InterruptedException exception) {
00116 logger.log(Level.WARNING, "Exception ", exception);
00117 }
00118 _knownMDNS.clear();
00119 }
00120
00121
00122
00123
00124
00125
00126 @Override
00127 public String[] getNames() {
00128 Set<String> result = new HashSet<String>();
00129 for (JmDNS mDNS : _knownMDNS.values()) {
00130 result.add(mDNS.getName());
00131 }
00132 return result.toArray(new String[result.size()]);
00133 }
00134
00135
00136
00137
00138
00139 @Override
00140 public String[] getHostNames() {
00141 Set<String> result = new HashSet<String>();
00142 for (JmDNS mDNS : _knownMDNS.values()) {
00143 result.add(mDNS.getHostName());
00144 }
00145 return result.toArray(new String[result.size()]);
00146 }
00147
00148
00149
00150
00151
00152 @Override
00153 public InetAddress[] getInetAddresses() throws IOException {
00154 Set<InetAddress> result = new HashSet<InetAddress>();
00155 for (JmDNS mDNS : _knownMDNS.values()) {
00156 result.add(mDNS.getInetAddress());
00157 }
00158 return result.toArray(new InetAddress[result.size()]);
00159 }
00160
00161
00162
00163
00164
00165 @Override
00166 @Deprecated
00167 public InetAddress[] getInterfaces() throws IOException {
00168 Set<InetAddress> result = new HashSet<InetAddress>();
00169 for (JmDNS mDNS : _knownMDNS.values()) {
00170 result.add(mDNS.getInterface());
00171 }
00172 return result.toArray(new InetAddress[result.size()]);
00173 }
00174
00175
00176
00177
00178
00179 @Override
00180 public ServiceInfo[] getServiceInfos(String type, String name) {
00181 return this.getServiceInfos(type, name, false, DNSConstants.SERVICE_INFO_TIMEOUT);
00182 }
00183
00184
00185
00186
00187
00188 @Override
00189 public ServiceInfo[] getServiceInfos(String type, String name, long timeout) {
00190 return this.getServiceInfos(type, name, false, timeout);
00191 }
00192
00193
00194
00195
00196
00197 @Override
00198 public ServiceInfo[] getServiceInfos(String type, String name, boolean persistent) {
00199 return this.getServiceInfos(type, name, persistent, DNSConstants.SERVICE_INFO_TIMEOUT);
00200 }
00201
00202
00203
00204
00205
00206 @Override
00207 public ServiceInfo[] getServiceInfos(final String type, final String name, final boolean persistent, final long timeout) {
00208
00209 final Set<ServiceInfo> result = Collections.synchronizedSet(new HashSet<ServiceInfo>(_knownMDNS.size()));
00210 ExecutorService executor = Executors.newCachedThreadPool();
00211 for (final JmDNS mDNS : _knownMDNS.values()) {
00212 executor.submit(new Runnable() {
00216 @Override
00217 public void run() {
00218 result.add(mDNS.getServiceInfo(type, name, persistent, timeout));
00219 }
00220 });
00221 }
00222 executor.shutdown();
00223 try {
00224 executor.awaitTermination(timeout, TimeUnit.MILLISECONDS);
00225 } catch (InterruptedException exception) {
00226 logger.log(Level.WARNING, "Exception ", exception);
00227 }
00228 return result.toArray(new ServiceInfo[result.size()]);
00229 }
00230
00231
00232
00233
00234
00235 @Override
00236 public void requestServiceInfo(String type, String name) {
00237 this.requestServiceInfo(type, name, false, DNSConstants.SERVICE_INFO_TIMEOUT);
00238 }
00239
00240
00241
00242
00243
00244 @Override
00245 public void requestServiceInfo(String type, String name, boolean persistent) {
00246 this.requestServiceInfo(type, name, persistent, DNSConstants.SERVICE_INFO_TIMEOUT);
00247 }
00248
00249
00250
00251
00252
00253 @Override
00254 public void requestServiceInfo(String type, String name, long timeout) {
00255 this.requestServiceInfo(type, name, false, timeout);
00256 }
00257
00258
00259
00260
00261
00262 @Override
00263 public void requestServiceInfo(final String type, final String name, final boolean persistent, final long timeout) {
00264
00265 for (final JmDNS mDNS : _knownMDNS.values()) {
00266 _jmDNSExecutor.submit(new Runnable() {
00270 @Override
00271 public void run() {
00272 mDNS.requestServiceInfo(type, name, persistent, timeout);
00273 }
00274 });
00275 }
00276 }
00277
00278
00279
00280
00281
00282 @Override
00283 public void addServiceTypeListener(ServiceTypeListener listener) throws IOException {
00284 for (JmDNS mDNS : _knownMDNS.values()) {
00285 mDNS.addServiceTypeListener(listener);
00286 }
00287 }
00288
00289
00290
00291
00292
00293 @Override
00294 public void removeServiceTypeListener(ServiceTypeListener listener) {
00295 for (JmDNS mDNS : _knownMDNS.values()) {
00296 mDNS.removeServiceTypeListener(listener);
00297 }
00298 }
00299
00300
00301
00302
00303
00304 @Override
00305 public void addServiceListener(String type, ServiceListener listener) {
00306 for (JmDNS mDNS : _knownMDNS.values()) {
00307 try {
00308 System.out.println("Adding listener:");
00309 System.out.printf(" Service type : %s\n", type);
00310 System.out.printf(" mDNS Name : %s\n", mDNS.getName());
00311 System.out.printf(" mDNS Localhost: %s\n", mDNS.getHostName());
00312 System.out.printf(" mDNS Address : %s\n", mDNS.getInetAddress().getHostAddress());
00313 } catch (IOException e) {
00314 e.printStackTrace();
00315 }
00316 mDNS.addServiceListener(type, listener);
00317 }
00318 }
00319
00320
00321
00322
00323
00324 @Override
00325 public void removeServiceListener(String type, ServiceListener listener) {
00326 for (JmDNS mDNS : _knownMDNS.values()) {
00327 mDNS.removeServiceListener(type, listener);
00328 }
00329 }
00330
00331
00332
00333
00334
00335 @Override
00336 public void textValueUpdated(ServiceInfo target, byte[] value) {
00337 synchronized (_services) {
00338 for (JmDNS mDNS : _knownMDNS.values()) {
00339 ServiceInfo info = ((JmDNSImpl) mDNS).getServices().get(target.getQualifiedName());
00340 if (info != null) {
00341 info.setText(value);
00342 } else {
00343 logger.warning("We have a mDNS that does not know about the service info being updated.");
00344 }
00345 }
00346 }
00347 }
00348
00349
00350
00351
00352
00353 @Override
00354 public void registerService(ServiceInfo info) throws IOException {
00355
00356 synchronized (_services) {
00357 for (JmDNS mDNS : _knownMDNS.values()) {
00358 mDNS.registerService(info.clone());
00359 }
00360 ((ServiceInfoImpl) info).setDelegate(this);
00361 _services.put(info.getQualifiedName(), info);
00362 }
00363 }
00364
00365
00366
00367
00368
00369 @Override
00370 public void unregisterService(ServiceInfo info) {
00371 synchronized (_services) {
00372 for (JmDNS mDNS : _knownMDNS.values()) {
00373 mDNS.unregisterService(info);
00374 }
00375 ((ServiceInfoImpl) info).setDelegate(null);
00376 _services.remove(info.getQualifiedName());
00377 }
00378 }
00379
00380
00381
00382
00383
00384 @Override
00385 public void unregisterAllServices() {
00386 synchronized (_services) {
00387 for (JmDNS mDNS : _knownMDNS.values()) {
00388 mDNS.unregisterAllServices();
00389 }
00390 _services.clear();
00391 }
00392 }
00393
00394
00395
00396
00397
00398 @Override
00399 public void registerServiceType(String type) {
00400 for (JmDNS mDNS : _knownMDNS.values()) {
00401 mDNS.registerServiceType(type);
00402 }
00403 }
00404
00405
00406
00407
00408
00409 @Override
00410 public ServiceInfo[] list(String type) {
00411 return this.list(type, DNSConstants.SERVICE_INFO_TIMEOUT);
00412 }
00413
00414
00415
00416
00417
00418 @Override
00419 public ServiceInfo[] list(final String type, final long timeout) {
00420
00421
00422
00423
00424
00425 final List<ServiceInfo> result = new ArrayList<ServiceInfo>(_knownMDNS.size() * 5);
00426
00427 ExecutorService executor = Executors.newCachedThreadPool();
00428 for (final JmDNS mDNS : _knownMDNS.values()) {
00429 List<ServiceInfo> single_mdns_list = new ArrayList<ServiceInfo>();
00430
00431
00432 for (ServiceInfo service_info : Arrays.asList(mDNS.list(type, timeout)) ) {
00433 boolean duplicate = false;
00434 for ( ServiceInfo existing_service_info : single_mdns_list ) {
00435 if ( ( existing_service_info.getQualifiedName().equals(service_info.getQualifiedName() ) ) &&
00436 ( existing_service_info.getPort() == service_info.getPort() ) &&
00437 ( Arrays.equals(existing_service_info.getInetAddresses(),service_info.getInetAddresses()) )
00438 ) {
00439
00440 duplicate = true;
00441 }
00442 }
00443 if ( !duplicate ) {
00444
00445
00446
00447
00448 single_mdns_list.add(service_info);
00449 }
00450 }
00451
00452 final List<ServiceInfo> service_list = new ArrayList<ServiceInfo>(single_mdns_list);
00453 executor.submit(new Runnable() {
00457 @Override
00458 public void run() {
00459
00460 result.addAll(service_list);
00461 }
00462 });
00463 }
00464 executor.shutdown();
00465 try {
00466 executor.awaitTermination(timeout, TimeUnit.MILLISECONDS);
00467 } catch (InterruptedException exception) {
00468 logger.log(Level.WARNING, "Exception ", exception);
00469 }
00470 return result.toArray(new ServiceInfo[result.size()]);
00471 }
00472
00473
00474
00475
00476
00477 @Override
00478 public Map<String, ServiceInfo[]> listBySubtype(String type) {
00479 return this.listBySubtype(type, DNSConstants.SERVICE_INFO_TIMEOUT);
00480 }
00481
00482
00483
00484
00485
00486 @Override
00487 public Map<String, ServiceInfo[]> listBySubtype(final String type, final long timeout) {
00488 Map<String, List<ServiceInfo>> map = new HashMap<String, List<ServiceInfo>>(5);
00489 for (ServiceInfo info : this.list(type, timeout)) {
00490 String subtype = info.getSubtype();
00491 if (!map.containsKey(subtype)) {
00492 map.put(subtype, new ArrayList<ServiceInfo>(10));
00493 }
00494 map.get(subtype).add(info);
00495 }
00496
00497 Map<String, ServiceInfo[]> result = new HashMap<String, ServiceInfo[]>(map.size());
00498 for (String subtype : map.keySet()) {
00499 List<ServiceInfo> infoForSubType = map.get(subtype);
00500 result.put(subtype, infoForSubType.toArray(new ServiceInfo[infoForSubType.size()]));
00501 }
00502
00503 return result;
00504 }
00505
00506
00507
00508
00509
00510 @Override
00511 public void addNetworkTopologyListener(NetworkTopologyListener listener) {
00512 _networkListeners.add(listener);
00513 }
00514
00515
00516
00517
00518
00519 @Override
00520 public void removeNetworkTopologyListener(NetworkTopologyListener listener) {
00521 _networkListeners.remove(listener);
00522 }
00523
00524
00525
00526
00527
00528 @Override
00529 public NetworkTopologyListener[] networkListeners() {
00530 return _networkListeners.toArray(new NetworkTopologyListener[_networkListeners.size()]);
00531 }
00532
00533
00534
00535
00536
00537 @Override
00538 public void inetAddressAdded(NetworkTopologyEvent event) {
00539 InetAddress address = event.getInetAddress();
00540 try {
00541 synchronized (this) {
00542 if (!_knownMDNS.containsKey(address)) {
00543 _knownMDNS.put(address, JmDNS.create(address));
00544 final NetworkTopologyEvent jmdnsEvent = new NetworkTopologyEventImpl(_knownMDNS.get(address), address);
00545 for (final NetworkTopologyListener listener : this.networkListeners()) {
00546 _ListenerExecutor.submit(new Runnable() {
00550 @Override
00551 public void run() {
00552 listener.inetAddressAdded(jmdnsEvent);
00553 }
00554 });
00555 }
00556 }
00557 }
00558 } catch (Exception e) {
00559 logger.warning("Unexpected unhandled exception: " + e);
00560 }
00561 }
00562
00563
00564
00565
00566
00567 @Override
00568 public void inetAddressRemoved(NetworkTopologyEvent event) {
00569 InetAddress address = event.getInetAddress();
00570 try {
00571 synchronized (this) {
00572 if (_knownMDNS.containsKey(address)) {
00573 JmDNS mDNS = _knownMDNS.remove(address);
00574 mDNS.close();
00575 final NetworkTopologyEvent jmdnsEvent = new NetworkTopologyEventImpl(mDNS, address);
00576 for (final NetworkTopologyListener listener : this.networkListeners()) {
00577 _ListenerExecutor.submit(new Runnable() {
00581 @Override
00582 public void run() {
00583 listener.inetAddressRemoved(jmdnsEvent);
00584 }
00585 });
00586 }
00587 }
00588 }
00589 } catch (Exception e) {
00590 logger.warning("Unexpected unhandled exception: " + e);
00591 }
00592 }
00593
00598 static class NetworkChecker extends TimerTask {
00599 private static Logger logger1 = Logger.getLogger(NetworkChecker.class.getName());
00600
00601 private final NetworkTopologyListener _mmDNS;
00602
00603 private final NetworkTopologyDiscovery _topology;
00604
00605 private Set<InetAddress> _knownAddresses;
00606
00607 public NetworkChecker(NetworkTopologyListener mmDNS, NetworkTopologyDiscovery topology) {
00608 super();
00609 this._mmDNS = mmDNS;
00610 this._topology = topology;
00611 _knownAddresses = Collections.synchronizedSet(new HashSet<InetAddress>());
00612 }
00613
00614 public void start(Timer timer) {
00615 timer.schedule(this, 0, DNSConstants.NETWORK_CHECK_INTERVAL);
00616 }
00617
00621 @Override
00622 public void run() {
00623 try {
00624 InetAddress[] curentAddresses = _topology.getInetAddresses();
00625 Set<InetAddress> current = new HashSet<InetAddress>(curentAddresses.length);
00626 for (InetAddress address : curentAddresses) {
00627 current.add(address);
00628 if (!_knownAddresses.contains(address)) {
00629 final NetworkTopologyEvent event = new NetworkTopologyEventImpl(_mmDNS, address);
00630 _mmDNS.inetAddressAdded(event);
00631 }
00632 }
00633 for (InetAddress address : _knownAddresses) {
00634 if (!current.contains(address)) {
00635 final NetworkTopologyEvent event = new NetworkTopologyEventImpl(_mmDNS, address);
00636 _mmDNS.inetAddressRemoved(event);
00637 }
00638 }
00639 _knownAddresses = current;
00640 } catch (Exception e) {
00641 logger1.warning("Unexpected unhandled exception: " + e);
00642 }
00643 }
00644
00645 }
00646
00647 }