From 8af7e729439591ab3f9a9080a342d47fc203897a Mon Sep 17 00:00:00 2001
From: akwizgran <akwizgran@users.sourceforge.net>
Date: Fri, 9 Dec 2011 21:13:53 +0000
Subject: [PATCH] Cancel outstanding tasks and shut down the executor.

---
 api/net/sf/briar/api/plugins/PluginManager.java     |  4 ++--
 .../net/sf/briar/plugins/PluginManagerImpl.java     | 10 +++++++---
 components/net/sf/briar/plugins/Poller.java         |  4 ++--
 components/net/sf/briar/plugins/PollerImpl.java     |  4 ++--
 .../sf/briar/plugins/bluetooth/BluetoothPlugin.java | 13 +++++++++++--
 .../net/sf/briar/plugins/PluginManagerImplTest.java |  9 +++++----
 6 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/api/net/sf/briar/api/plugins/PluginManager.java b/api/net/sf/briar/api/plugins/PluginManager.java
index 2fae4b17c8..b2dbd44ae0 100644
--- a/api/net/sf/briar/api/plugins/PluginManager.java
+++ b/api/net/sf/briar/api/plugins/PluginManager.java
@@ -6,10 +6,10 @@ public interface PluginManager {
 	 * Starts the plugins and returns the number of plugins successfully
 	 * started.
 	 */
-	int startPlugins();
+	int start();
 
 	/**
 	 * Stops the plugins and returns the number of plugins successfully stopped.
 	 */
-	int stopPlugins();
+	int stop();
 }
diff --git a/components/net/sf/briar/plugins/PluginManagerImpl.java b/components/net/sf/briar/plugins/PluginManagerImpl.java
index a88c8b563c..5d16299efb 100644
--- a/components/net/sf/briar/plugins/PluginManagerImpl.java
+++ b/components/net/sf/briar/plugins/PluginManagerImpl.java
@@ -76,7 +76,7 @@ class PluginManagerImpl implements PluginManager {
 		return batchPlugins.size() + streamPlugins.size();
 	}
 
-	public synchronized int startPlugins() {
+	public synchronized int start() {
 		Set<TransportId> ids = new HashSet<TransportId>();
 		// Instantiate and start the batch plugins
 		for(String s : BATCH_FACTORIES) {
@@ -162,12 +162,12 @@ class PluginManagerImpl implements PluginManager {
 		List<Plugin> plugins = new ArrayList<Plugin>();
 		plugins.addAll(batchPlugins);
 		plugins.addAll(streamPlugins);
-		poller.startPolling(Collections.unmodifiableList(plugins));
+		poller.start(Collections.unmodifiableList(plugins));
 		// Return the number of plugins successfully started
 		return batchPlugins.size() + streamPlugins.size();
 	}
 
-	public synchronized int stopPlugins() {
+	public synchronized int stop() {
 		int stopped = 0;
 		// Stop the batch plugins
 		for(BatchPlugin plugin : batchPlugins) {
@@ -189,6 +189,10 @@ class PluginManagerImpl implements PluginManager {
 			}
 		}
 		streamPlugins.clear();
+		// Stop the poller
+		poller.stop();
+		// Shut down the executor service
+		pluginExecutor.shutdown();
 		// Return the number of plugins successfully stopped
 		return stopped;
 	}
diff --git a/components/net/sf/briar/plugins/Poller.java b/components/net/sf/briar/plugins/Poller.java
index 0c349722aa..d5eb381ba6 100644
--- a/components/net/sf/briar/plugins/Poller.java
+++ b/components/net/sf/briar/plugins/Poller.java
@@ -7,8 +7,8 @@ import net.sf.briar.api.plugins.Plugin;
 interface Poller {
 
 	/** Starts a new thread to poll the given collection of plugins. */
-	void startPolling(Collection<Plugin> plugins);
+	void start(Collection<Plugin> plugins);
 
 	/** Tells the poller thread to exit. */
-	void stopPolling();
+	void stop();
 }
diff --git a/components/net/sf/briar/plugins/PollerImpl.java b/components/net/sf/briar/plugins/PollerImpl.java
index 3245c08a69..b1e3d6e68d 100644
--- a/components/net/sf/briar/plugins/PollerImpl.java
+++ b/components/net/sf/briar/plugins/PollerImpl.java
@@ -26,7 +26,7 @@ class PollerImpl implements Poller, Runnable {
 		pollTimes = new TreeSet<PollTime>();
 	}
 
-	public synchronized void startPolling(Collection<Plugin> plugins) {
+	public synchronized void start(Collection<Plugin> plugins) {
 		for(Plugin plugin : plugins) schedule(plugin);
 		new Thread(this).start();
 	}
@@ -39,7 +39,7 @@ class PollerImpl implements Poller, Runnable {
 		}
 	}
 
-	public synchronized void stopPolling() {
+	public synchronized void stop() {
 		pollTimes.clear();
 		notifyAll();
 	}
diff --git a/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java b/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
index 7884ead6c5..536de88124 100644
--- a/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
+++ b/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
@@ -1,6 +1,7 @@
 package net.sf.briar.plugins.bluetooth;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -8,6 +9,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Random;
 import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -43,6 +45,7 @@ class BluetoothPlugin implements StreamPlugin {
 	private final StreamPluginCallback callback;
 	private final long pollingInterval;
 	private final Object discoveryLock = new Object();
+	private final Collection<ScheduledFuture<?>> socketClosers; // Locking: this
 
 	private boolean running = false; // Locking: this
 	private LocalDevice localDevice = null; // Locking: this
@@ -53,6 +56,7 @@ class BluetoothPlugin implements StreamPlugin {
 		this.pluginExecutor = pluginExecutor;
 		this.callback = callback;
 		this.pollingInterval = pollingInterval;
+		socketClosers = new ArrayList<ScheduledFuture<?>>();
 	}
 
 	public TransportId getId() {
@@ -167,6 +171,7 @@ class BluetoothPlugin implements StreamPlugin {
 
 	public synchronized void stop() throws IOException {
 		running = false;
+		for(ScheduledFuture<?> close : socketClosers) close.cancel(false);
 		localDevice = null;
 		if(socket != null) {
 			socket.close();
@@ -377,11 +382,15 @@ class BluetoothPlugin implements StreamPlugin {
 			return;
 		}
 		// Close the socket when the invitation times out
-		pluginExecutor.schedule(new Runnable() {
+		Runnable close = new Runnable() {
 			public void run() {
 				tryToClose(scn);
 			}
-		}, c.getTimeout(), TimeUnit.MILLISECONDS);
+		};
+		synchronized(this) {
+			socketClosers.add(pluginExecutor.schedule(close, c.getTimeout(),
+					TimeUnit.MILLISECONDS));
+		}
 		try {
 			StreamConnection s = scn.acceptAndOpen();
 			c.addConnection(s);
diff --git a/test/net/sf/briar/plugins/PluginManagerImplTest.java b/test/net/sf/briar/plugins/PluginManagerImplTest.java
index 48f47eb256..37c50e3966 100644
--- a/test/net/sf/briar/plugins/PluginManagerImplTest.java
+++ b/test/net/sf/briar/plugins/PluginManagerImplTest.java
@@ -30,7 +30,7 @@ public class PluginManagerImplTest extends BriarTestCase {
 		final UiCallback uiCallback = context.mock(UiCallback.class);
 		final AtomicInteger index = new AtomicInteger(0);
 		context.checking(new Expectations() {{
-			oneOf(poller).startPolling(with(any(Collection.class)));
+			oneOf(poller).start(with(any(Collection.class)));
 			allowing(db).getLocalIndex(with(any(TransportId.class)));
 			will(returnValue(null));
 			allowing(db).addTransport(with(any(TransportId.class)));
@@ -41,17 +41,18 @@ public class PluginManagerImplTest extends BriarTestCase {
 			will(returnValue(new TransportProperties()));
 			allowing(db).setLocalProperties(with(any(TransportId.class)),
 					with(any(TransportProperties.class)));
-			oneOf(poller).stopPolling();
+			oneOf(poller).stop();
 		}});
 		ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
 		PluginManagerImpl p = new PluginManagerImpl(executor, db, poller,
 				dispatcher, uiCallback);
 		// We expect either 2 or 3 plugins to be started, depending on whether
 		// the test machine has a Bluetooth device
-		int started = p.startPlugins();
-		int stopped = p.stopPlugins();
+		int started = p.start();
+		int stopped = p.stop();
 		assertEquals(started, stopped);
 		assertTrue(started >= 2);
 		assertTrue(started <= 3);
+		context.assertIsSatisfied();
 	}
 }
-- 
GitLab