Fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=473558

Change-Id: I97587098ffe5917e3b4f8a6310af81aa13e9ec1b
diff --git a/providers/bundles/org.eclipse.ecf.provider.jmdns/META-INF/MANIFEST.MF b/providers/bundles/org.eclipse.ecf.provider.jmdns/META-INF/MANIFEST.MF
index 0a2653b..0b303bd 100644
--- a/providers/bundles/org.eclipse.ecf.provider.jmdns/META-INF/MANIFEST.MF
+++ b/providers/bundles/org.eclipse.ecf.provider.jmdns/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.ecf.provider.jmdns;singleton:=true
-Bundle-Version: 4.3.0.qualifier
+Bundle-Version: 4.3.100.qualifier
 Bundle-Activator: org.eclipse.ecf.internal.provider.jmdns.JMDNSPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/providers/bundles/org.eclipse.ecf.provider.jmdns/src/org/eclipse/ecf/provider/jmdns/container/JMDNSDiscoveryContainer.java b/providers/bundles/org.eclipse.ecf.provider.jmdns/src/org/eclipse/ecf/provider/jmdns/container/JMDNSDiscoveryContainer.java
index 2923877..80f06a0 100644
--- a/providers/bundles/org.eclipse.ecf.provider.jmdns/src/org/eclipse/ecf/provider/jmdns/container/JMDNSDiscoveryContainer.java
+++ b/providers/bundles/org.eclipse.ecf.provider.jmdns/src/org/eclipse/ecf/provider/jmdns/container/JMDNSDiscoveryContainer.java
@@ -51,7 +51,6 @@
 	 */
 	final Map services = Collections.synchronizedMap(new HashMap());
 
-	boolean disposed = false;
 	final Object lock = new Object();
 
 	SimpleFIFOQueue queue = null;
@@ -75,64 +74,62 @@
 	}
 
 	/* (non-Javadoc)
-	 * @see org.eclipse.ecf.discovery.AbstractDiscoveryContainerAdapter#dispose()
-	 */
-	public void dispose() {
-		synchronized (lock) {
-			super.dispose();
-			disposed = true;
-		}
-	}
-
-	/* (non-Javadoc)
 	 * @see org.eclipse.ecf.core.IContainer#connect(org.eclipse.ecf.core.identity.ID, org.eclipse.ecf.core.security.IConnectContext)
 	 */
 	public void connect(final ID targetID1, final IConnectContext joinContext) throws ContainerConnectException {
 		synchronized (lock) {
-			if (disposed)
-				throw new ContainerConnectException("Container has been disposed"); //$NON-NLS-1$
 			if (this.targetID != null)
 				throw new ContainerConnectException("Already connected"); //$NON-NLS-1$
 			this.targetID = (targetID1 == null) ? getConfig().getID() : targetID1;
 			fireContainerEvent(new ContainerConnectingEvent(this.getID(), this.targetID, joinContext));
-			initializeQueue();
+			// initialize queue and JMDNS discovery thread
+			queue = new SimpleFIFOQueue();
+			notificationThread = new Thread(new Runnable() {
+				public void run() {
+					while (!queue.isStopped()) {
+						if (Thread.currentThread().isInterrupted())
+							break;
+						final Runnable runnable = (Runnable) queue.dequeue();
+						if (Thread.currentThread().isInterrupted() || runnable == null)
+							break;
+						try {
+							runnable.run();
+						} catch (final Throwable t) {
+							JMDNSPlugin plugin = JMDNSPlugin.getDefault();
+							if (plugin != null)
+								plugin.logException("JMDNS.handleNotificationThreadException", t); //$NON-NLS-1$
+						}
+					}
+				}
+			}, "JMDNS Discovery Thread"); //$NON-NLS-1$
+			notificationThread.start();
+			// Create JmDNS and add type listener
 			try {
 				this.jmdns = JmDNS.create();
 				jmdns.addServiceTypeListener(this);
 			} catch (final IOException e) {
 				Trace.catching(JMDNSPlugin.PLUGIN_ID, JMDNSDebugOptions.EXCEPTIONS_CATCHING, this.getClass(), "connect", e); //$NON-NLS-1$
-				if (this.jmdns != null) {
-					jmdns.close();
-					jmdns = null;
-				}
+				doCleanup();
 				throw new ContainerConnectException("Cannot create JmDNS instance", e); //$NON-NLS-1$
 			}
 			fireContainerEvent(new ContainerConnectedEvent(this.getID(), this.targetID));
 		}
 	}
 
-	private void initializeQueue() {
-		queue = new SimpleFIFOQueue();
-		notificationThread = new Thread(new Runnable() {
-			public void run() {
-				while (!disposed || queue.isStopped()) {
-					if (Thread.currentThread().isInterrupted())
-						break;
-					final Runnable runnable = (Runnable) queue.dequeue();
-					if (Thread.currentThread().isInterrupted() || runnable == null)
-						break;
-					try {
-						runnable.run();
-					} catch (final Throwable t) {
-						JMDNSPlugin plugin = JMDNSPlugin.getDefault();
-						if (plugin != null) {
-							plugin.logException("handleRuntimeException", t); //$NON-NLS-1$
-						}
-					}
-				}
-			}
-		}, "JMDNS Discovery Thread"); //$NON-NLS-1$
-		notificationThread.start();
+	private void doCleanup() {
+		if (queue != null)
+			queue.close();
+		if (notificationThread != null) {
+			notificationThread.interrupt();
+			notificationThread = null;
+		}
+		this.targetID = null;
+		serviceTypes.clear();
+		// @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=385395
+		if (jmdns != null) {
+			jmdns.close();
+			jmdns = null;
+		}
 	}
 
 	/* (non-Javadoc)
@@ -140,21 +137,11 @@
 	 */
 	public void disconnect() {
 		synchronized (lock) {
-			if (getConnectedID() == null || disposed) {
-				return;
-			}
 			final ID connectedID = getConnectedID();
+			if (connectedID == null)
+				return;
 			fireContainerEvent(new ContainerDisconnectingEvent(this.getID(), connectedID));
-			queue.close();
-			notificationThread.interrupt();
-			notificationThread = null;
-			this.targetID = null;
-			serviceTypes.clear();
-			// @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=385395
-			if (jmdns != null) {
-				jmdns.close();
-				jmdns = null;
-			}
+			doCleanup();
 			fireContainerEvent(new ContainerDisconnectedEvent(this.getID(), connectedID));
 		}
 	}
@@ -168,6 +155,8 @@
 		Assert.isNotNull(service);
 		synchronized (lock) {
 			try {
+				if (jmdns == null)
+					return null;
 				// ECF discovery API defines identity to be the service type and the URI (location)
 				// see https://bugs.eclipse.org/266723
 				final ServiceInfo[] serviceInfos = jmdns.list(service.getServiceTypeID().getInternal());
@@ -215,7 +204,7 @@
 			for (final Iterator itr = serviceTypes.iterator(); itr.hasNext();) {
 				final IServiceTypeID serviceType = (IServiceTypeID) itr.next();
 				if (Arrays.equals(serviceType.getServices(), type.getServices()) && Arrays.equals(serviceType.getProtocols(), type.getProtocols()) && Arrays.equals(serviceType.getScopes(), type.getScopes())) {
-					final ServiceInfo[] infos = jmdns.list(type.getInternal());
+					final ServiceInfo[] infos = (jmdns == null) ? new ServiceInfo[0] : jmdns.list(type.getInternal());
 					for (int i = 0; i < infos.length; i++) {
 						try {
 							if (infos[i] != null) {
@@ -229,7 +218,7 @@
 					}
 				}
 			}
-			return (IServiceInfo[]) serviceInfos.toArray(new IServiceInfo[] {});
+			return (IServiceInfo[]) serviceInfos.toArray(new IServiceInfo[serviceInfos.size()]);
 		}
 	}
 
@@ -238,7 +227,7 @@
 	 */
 	public IServiceTypeID[] getServiceTypes() {
 		synchronized (lock) {
-			return (IServiceTypeID[]) serviceTypes.toArray(new IServiceTypeID[] {});
+			return (IServiceTypeID[]) serviceTypes.toArray(new IServiceTypeID[serviceTypes.size()]);
 		}
 	}
 
@@ -249,10 +238,13 @@
 		Assert.isNotNull(serviceInfo);
 		final ServiceInfo svcInfo = createServiceInfoFromIServiceInfo(serviceInfo);
 		checkServiceInfo(svcInfo);
-		try {
-			jmdns.registerService(svcInfo);
-		} catch (final IOException e) {
-			throw new ECFRuntimeException("Exception registering service", e); //$NON-NLS-1$
+		synchronized (lock) {
+			try {
+				if (jmdns != null)
+					jmdns.registerService(svcInfo);
+			} catch (final IOException e) {
+				throw new ECFRuntimeException("Exception registering service", e); //$NON-NLS-1$
+			}
 		}
 	}
 
@@ -262,14 +254,20 @@
 	public void unregisterService(final IServiceInfo serviceInfo) {
 		Assert.isNotNull(serviceInfo);
 		final ServiceInfo si = createServiceInfoFromIServiceInfo(serviceInfo);
-		jmdns.unregisterService(si);
+		synchronized (lock) {
+			if (jmdns != null)
+				jmdns.unregisterService(si);
+		}
 	}
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.ecf.discovery.AbstractDiscoveryContainerAdapter#unregisterAllServices()
 	 */
 	public void unregisterAllServices() {
-		jmdns.unregisterAllServices();
+		synchronized (lock) {
+			if (jmdns != null)
+				jmdns.unregisterAllServices();
+		}
 	}
 
 	/* (non-Javadoc)
@@ -311,9 +309,8 @@
 				final String serviceName = arg0.getName();
 				IServiceInfo aServiceInfo = null;
 				synchronized (lock) {
-					if (getConnectedID() == null || disposed) {
+					if (getConnectedID() == null)
 						return;
-					}
 
 					// explicitly get the service to determine the naming authority (part of the service properties)
 					try {
@@ -339,9 +336,8 @@
 		Trace.trace(JMDNSPlugin.PLUGIN_ID, "serviceRemoved(" + arg0.getName() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
 		runInThread(new Runnable() {
 			public void run() {
-				if (getConnectedID() == null || disposed) {
+				if (getConnectedID() == null)
 					return;
-				}
 				final String serviceType = arg0.getType();
 				final String serviceName = arg0.getName();
 				IServiceInfo aServiceInfo = (IServiceInfo) services.remove(serviceType + serviceName);