From 9abe920edb1b33ef5ab47173b0d2fb9558031e04 Mon Sep 17 00:00:00 2001
From: akwizgran <akwizgran@users.sourceforge.net>
Date: Fri, 9 Dec 2011 00:08:15 +0000
Subject: [PATCH] Plugin code cleanup.

---
 .../net/sf/briar/plugins/AbstractPlugin.java  |  28 -----
 .../plugins/bluetooth/BluetoothPlugin.java    | 110 +++++++-----------
 .../net/sf/briar/plugins/file/FilePlugin.java |  36 +++---
 .../plugins/file/RemovableDrivePlugin.java    |  10 +-
 .../briar/plugins/socket/LanSocketPlugin.java |  72 ++++++------
 .../plugins/socket/SimpleSocketPlugin.java    |   8 --
 .../sf/briar/plugins/socket/SocketPlugin.java | 106 ++++++++---------
 7 files changed, 154 insertions(+), 216 deletions(-)
 delete mode 100644 components/net/sf/briar/plugins/AbstractPlugin.java

diff --git a/components/net/sf/briar/plugins/AbstractPlugin.java b/components/net/sf/briar/plugins/AbstractPlugin.java
deleted file mode 100644
index 24b08006c8..0000000000
--- a/components/net/sf/briar/plugins/AbstractPlugin.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package net.sf.briar.plugins;
-
-import java.io.IOException;
-import java.util.concurrent.Executor;
-
-import net.sf.briar.api.plugins.Plugin;
-import net.sf.briar.api.plugins.PluginExecutor;
-
-public abstract class AbstractPlugin implements Plugin {
-
-	protected final Executor pluginExecutor;
-
-	protected boolean running = false; // Locking: this
-
-	protected AbstractPlugin(@PluginExecutor Executor pluginExecutor) {
-		this.pluginExecutor = pluginExecutor;
-	}
-
-	public synchronized void start() throws IOException {
-		if(running) throw new IllegalStateException();
-		running = true;
-	}
-
-	public synchronized void stop() throws IOException {
-		if(!running) throw new IllegalStateException();
-		running = false;
-	}
-}
diff --git a/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java b/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
index ea1faa626b..d715698010 100644
--- a/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
+++ b/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
@@ -24,11 +24,10 @@ import net.sf.briar.api.plugins.StreamPlugin;
 import net.sf.briar.api.plugins.StreamPluginCallback;
 import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.transport.StreamTransportConnection;
-import net.sf.briar.plugins.AbstractPlugin;
 import net.sf.briar.util.OsUtils;
 import net.sf.briar.util.StringUtils;
 
-class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
+class BluetoothPlugin implements StreamPlugin {
 
 	public static final byte[] TRANSPORT_ID =
 		StringUtils.fromHexString("d99c9313c04417dcf22fc60d12a187ea"
@@ -38,16 +37,18 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
 	private static final Logger LOG =
 		Logger.getLogger(BluetoothPlugin.class.getName());
 
-	private final Object discoveryLock = new Object();
+	private final Executor pluginExecutor;
 	private final StreamPluginCallback callback;
 	private final long pollingInterval;
+	private final Object discoveryLock = new Object();
 
+	private boolean running = false; // Locking: this
 	private LocalDevice localDevice = null; // Locking: this
 	private StreamConnectionNotifier socket = null; // Locking: this
 
 	BluetoothPlugin(@PluginExecutor Executor pluginExecutor,
 			StreamPluginCallback callback, long pollingInterval) {
-		super(pluginExecutor);
+		this.pluginExecutor = pluginExecutor;
 		this.callback = callback;
 		this.pollingInterval = pollingInterval;
 	}
@@ -56,43 +57,33 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
 		return id;
 	}
 
-	@Override
 	public void start() throws IOException {
 		// Initialise the Bluetooth stack
 		try {
 			synchronized(this) {
-				super.start();
+				running = true;
 				localDevice = LocalDevice.getLocalDevice();
-				if(LOG.isLoggable(Level.INFO))
-					LOG.info("Local address "
-							+ localDevice.getBluetoothAddress());
-			}
+			} 
 		} catch(UnsatisfiedLinkError e) {
 			// On Linux the user may need to install libbluetooth-dev
-			if(OsUtils.isLinux()) {
-				pluginExecutor.execute(new Runnable() {
-					public void run() {
-						callback.showMessage("BLUETOOTH_INSTALL_LIBS");
-					}
-				});
-			}
+			if(OsUtils.isLinux())
+				callback.showMessage("BLUETOOTH_INSTALL_LIBS");
 			throw new IOException(e.toString());
 		}
 		pluginExecutor.execute(new Runnable() {
 			public void run() {
-				bindContactSocket();
+				bind();
 			}
 		});
 	}
 
-	private void bindContactSocket() {
+	private void bind() {
 		String uuid;
 		synchronized(this) {
 			if(!running) return;
 			uuid = getUuid();
 			makeDeviceDiscoverable();
 		}
-		// Bind the socket
 		String url = "btspp://localhost:" + uuid + ";name=RFCOMM";
 		StreamConnectionNotifier scn;
 		try {
@@ -103,21 +94,12 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
 		}
 		synchronized(this) {
 			if(!running) {
-				try {
-					scn.close();
-				} catch(IOException e) {
-					if(LOG.isLoggable(Level.WARNING))
-						LOG.warning(e.toString());
-				}
+				tryToClose(scn);
 				return;
 			}
 			socket = scn;
 		}
-		pluginExecutor.execute(new Runnable() {
-			public void run() {
-				acceptContactConnections();
-			}
-		});
+		acceptContactConnections(scn);
 	}
 
 	private synchronized String getUuid() {
@@ -151,30 +133,37 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
 		}
 	}
 
-	private void acceptContactConnections() {
+	private void tryToClose(StreamConnectionNotifier scn) {
+		try {
+			scn.close();
+		} catch(IOException e) {
+			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
+		}
+	}
+
+	private void acceptContactConnections(StreamConnectionNotifier scn) {
 		while(true) {
-			StreamConnectionNotifier scn;
 			StreamConnection s;
-			synchronized(this) {
-				if(!running) return;
-				scn = socket;
-			}
 			try {
 				s = scn.acceptAndOpen();
 			} catch(IOException e) {
 				// This is expected when the socket is closed
 				if(LOG.isLoggable(Level.INFO)) LOG.info(e.toString());
+				tryToClose(scn);
 				return;
 			}
 			BluetoothTransportConnection conn =
 				new BluetoothTransportConnection(s);
 			callback.incomingConnectionCreated(conn);
+			synchronized(this) {
+				if(!running) return;
+			}
 		}
 	}
 
-	@Override
 	public synchronized void stop() throws IOException {
-		super.stop();
+		running = false;
+		localDevice = null;
 		if(socket != null) {
 			socket.close();
 			socket = null;
@@ -201,11 +190,11 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
 	}
 
 	private void connectAndCallBack() {
-		Map<ContactId, TransportProperties> remote;
 		synchronized(this) {
 			if(!running) return;
-			remote = callback.getRemoteProperties();
 		}
+		Map<ContactId, TransportProperties> remote =
+			callback.getRemoteProperties();
 		Map<ContactId, String> discovered = discoverContactUrls(remote);
 		for(Entry<ContactId, String> e : discovered.entrySet()) {
 			ContactId c = e.getKey();
@@ -268,11 +257,11 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
 	}
 
 	public StreamTransportConnection createConnection(ContactId c) {
-		Map<ContactId, TransportProperties> remote;
 		synchronized(this) {
 			if(!running) return null;
-			remote = callback.getRemoteProperties();
 		}
+		Map<ContactId, TransportProperties> remote =
+			callback.getRemoteProperties();
 		if(!remote.containsKey(c)) return null;
 		remote = Collections.singletonMap(c, remote.get(c));
 		String url = discoverContactUrls(remote).get(c);
@@ -293,6 +282,9 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
 
 	private StreamTransportConnection createInvitationConnection(int code,
 			long timeout) {
+		synchronized(this) {
+			if(!running) return null;
+		}
 		// The invitee's device may not be discoverable, so both parties must
 		// try to initiate connections
 		String uuid = convertInvitationCodeToUuid(code);
@@ -370,7 +362,6 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
 			if(!running) return;
 			makeDeviceDiscoverable();
 		}
-		// Bind the socket
 		String url = "btspp://localhost:" + c.getUuid() + ";name=RFCOMM";
 		final StreamConnectionNotifier scn;
 		try {
@@ -379,37 +370,26 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
 			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
 			return;
 		}
+		// Close the socket when the invitation times out
 		pluginExecutor.execute(new Runnable() {
 			public void run() {
-				acceptInvitationConnection(c, scn);
+				try {
+					Thread.sleep(c.getTimeout());
+				} catch(InterruptedException e) {
+					if(LOG.isLoggable(Level.INFO))
+						LOG.info("Interrupted while waiting for invitation");
+					Thread.currentThread().interrupt();
+				}
+				tryToClose(scn);
 			}
 		});
-		// Close the socket when the invitation times out
-		try {
-			Thread.sleep(c.getTimeout());
-		} catch(InterruptedException e) {
-			if(LOG.isLoggable(Level.INFO))
-				LOG.info("Interrupted while waiting for invitation timeout");
-			Thread.currentThread().interrupt();
-		}
-		try {
-			scn.close();
-		} catch(IOException e) {
-			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
-		}
-	}
-
-	private void acceptInvitationConnection(ConnectionCallback c,
-			StreamConnectionNotifier scn) {
-		synchronized(this) {
-			if(!running) return;
-		}
 		try {
 			StreamConnection s = scn.acceptAndOpen();
 			c.addConnection(s);
 		} catch(IOException e) {
 			// This is expected when the socket is closed
 			if(LOG.isLoggable(Level.INFO)) LOG.info(e.toString());
+			tryToClose(scn);
 		}
 	}
 }
diff --git a/components/net/sf/briar/plugins/file/FilePlugin.java b/components/net/sf/briar/plugins/file/FilePlugin.java
index 52e0998d39..23a6be7d82 100644
--- a/components/net/sf/briar/plugins/file/FilePlugin.java
+++ b/components/net/sf/briar/plugins/file/FilePlugin.java
@@ -17,18 +17,21 @@ import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.transport.BatchTransportReader;
 import net.sf.briar.api.transport.BatchTransportWriter;
 import net.sf.briar.api.transport.TransportConstants;
-import net.sf.briar.plugins.AbstractPlugin;
 
 import org.apache.commons.io.FileSystemUtils;
 
-abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
+abstract class FilePlugin implements BatchPlugin {
 
 	private static final Logger LOG =
 		Logger.getLogger(FilePlugin.class.getName());
 
+	protected final Executor pluginExecutor;
 	protected final BatchPluginCallback callback;
 
+	protected volatile boolean running = false;
+
 	private final Object listenerLock = new Object();
+
 	private FileListener listener = null; // Locking: listenerLock
 
 	protected abstract File chooseOutputDirectory();
@@ -38,7 +41,7 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
 
 	protected FilePlugin(@PluginExecutor Executor pluginExecutor,
 			BatchPluginCallback callback) {
-		super(pluginExecutor);
+		this.pluginExecutor = pluginExecutor;
 		this.callback = callback;
 	}
 
@@ -47,6 +50,7 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
 	}
 
 	public BatchTransportWriter createWriter(ContactId c) {
+		if(!running) return null;
 		return createWriter(createConnectionFilename());
 	}
 
@@ -63,9 +67,7 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
 	}
 
 	private BatchTransportWriter createWriter(String filename) {
-		synchronized(this) {
-			if(!running) return null;
-		}
+		if(!running) return null;
 		File dir = chooseOutputDirectory();
 		if(dir == null || !dir.exists() || !dir.isDirectory()) return null;
 		File f = new File(dir, filename);
@@ -85,26 +87,30 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
 		return FileSystemUtils.freeSpaceKb(path) * 1024L;
 	}
 
-	protected synchronized void createReaderFromFile(final File f) {
+	protected void createReaderFromFile(final File f) {
 		if(!running) return;
 		pluginExecutor.execute(new ReaderCreator(f));
 	}
 
 	public BatchTransportWriter sendInvitation(int code, long timeout) {
+		if(!running) return null;
 		return createWriter(createInvitationFilename(code, false));
 	}
 
 	public BatchTransportReader acceptInvitation(int code, long timeout) {
+		if(!running) return null;
 		String filename = createInvitationFilename(code, false);
 		return createInvitationReader(filename, timeout);
 	}
 
 	public BatchTransportWriter sendInvitationResponse(int code, long timeout) {
+		if(!running) return null;
 		return createWriter(createInvitationFilename(code, true));
 	}
 
 	public BatchTransportReader acceptInvitationResponse(int code,
 			long timeout) {
+		if(!running) return null;
 		String filename = createInvitationFilename(code, true);
 		return createInvitationReader(filename, timeout);
 	}
@@ -155,23 +161,23 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
 
 	private class ReaderCreator implements Runnable {
 
-		private final File f;
+		private final File file;
 
-		private ReaderCreator(File f) {
-			this.f = f;
+		private ReaderCreator(File file) {
+			this.file = file;
 		}
 
 		public void run() {
-			String filename = f.getName();
+			String filename = file.getName();
 			if(isPossibleInvitationFilename(filename)) {
 				synchronized(listenerLock) {
-					if(listener != null) listener.addFile(f);
+					if(listener != null) listener.addFile(file);
 				}
 			}
-			if(isPossibleConnectionFilename(f.getName())) {
+			if(isPossibleConnectionFilename(file.getName())) {
 				try {
-					FileInputStream in = new FileInputStream(f);
-					callback.readerCreated(new FileTransportReader(f, in,
+					FileInputStream in = new FileInputStream(file);
+					callback.readerCreated(new FileTransportReader(file, in,
 							FilePlugin.this));
 				} catch(IOException e) {
 					if(LOG.isLoggable(Level.WARNING))
diff --git a/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java b/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java
index 9bea390ea9..7609d25d0a 100644
--- a/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java
+++ b/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java
@@ -41,15 +41,13 @@ implements RemovableDriveMonitor.Callback {
 		return id;
 	}
 
-	@Override
-	public synchronized void start() throws IOException {
-		super.start();
+	public void start() throws IOException {
+		running = true;
 		monitor.start(this);
 	}
 
-	@Override
-	public synchronized void stop() throws IOException {
-		super.stop();
+	public void stop() throws IOException {
+		running = false;
 		monitor.stop();
 	}
 
diff --git a/components/net/sf/briar/plugins/socket/LanSocketPlugin.java b/components/net/sf/briar/plugins/socket/LanSocketPlugin.java
index d8016be741..9e5c3742c1 100644
--- a/components/net/sf/briar/plugins/socket/LanSocketPlugin.java
+++ b/components/net/sf/briar/plugins/socket/LanSocketPlugin.java
@@ -37,6 +37,9 @@ class LanSocketPlugin extends SimpleSocketPlugin {
 
 	@Override
 	public StreamTransportConnection sendInvitation(int code, long timeout) {
+		synchronized(this) {
+			if(!running) return null;
+		}
 		// Calculate the group address and port from the invitation code
 		InetSocketAddress mcast = convertInvitationCodeToMulticastGroup(code);
 		// Bind a multicast socket for receiving packets
@@ -48,15 +51,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
 			ms.joinGroup(mcast.getAddress());
 		} catch(IOException e) {
 			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
-			if(ms != null) {
-				try {
-					ms.leaveGroup(mcast.getAddress());
-				} catch(IOException e1) {
-					if(LOG.isLoggable(Level.WARNING))
-						LOG.warning(e1.toString());
-				}
-				ms.close();
-			}
+			if(ms != null) tryToClose(ms, mcast.getAddress());
 			return null;
 		}
 		// Listen until a valid packet is received or the timeout occurs
@@ -77,8 +72,6 @@ class LanSocketPlugin extends SimpleSocketPlugin {
 						try {
 							// Connect back on the advertised TCP port
 							Socket s = new Socket(packet.getAddress(), port);
-							ms.leaveGroup(mcast.getAddress());
-							ms.close();
 							return new SocketTransportConnection(s);
 						} catch(IOException e) {
 							if(LOG.isLoggable(Level.WARNING))
@@ -89,21 +82,29 @@ class LanSocketPlugin extends SimpleSocketPlugin {
 					break;
 				}
 				now = System.currentTimeMillis();
+				synchronized(this) {
+					if(!running) return null;
+				}
 			}
 			if(LOG.isLoggable(Level.INFO))
 				LOG.info("Timeout while sending invitation");
 		} catch(IOException e) {
 			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
-			try {
-				ms.leaveGroup(mcast.getAddress());
-			} catch(IOException e1) {
-				if(LOG.isLoggable(Level.WARNING)) LOG.warning(e1.toString());
-			}
-			ms.close();
+		} finally {
+			tryToClose(ms, mcast.getAddress());
 		}
 		return null;
 	}
 
+	private void tryToClose(MulticastSocket ms, InetAddress addr) {
+		try {
+			ms.leaveGroup(addr);
+		} catch(IOException e) {
+			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
+		}
+		ms.close();
+	}
+
 	private InetSocketAddress convertInvitationCodeToMulticastGroup(int code) {
 		Random r = new Random(code);
 		byte[] b = new byte[5];
@@ -139,6 +140,9 @@ class LanSocketPlugin extends SimpleSocketPlugin {
 
 	@Override
 	public StreamTransportConnection acceptInvitation(int code, long timeout) {
+		synchronized(this) {
+			if(!running) return null;
+		}
 		// Calculate the group address and port from the invitation code
 		InetSocketAddress mcast = convertInvitationCodeToMulticastGroup(code);
 		// Bind a TCP socket for receiving connections
@@ -149,14 +153,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
 			ss.bind(new InetSocketAddress(iface, 0));
 		} catch(IOException e) {
 			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
-			if(ss != null) {
-				try {
-					ss.close();
-				} catch(IOException e1) {
-					if(LOG.isLoggable(Level.WARNING))
-						LOG.warning(e1.toString());
-				}
-			}
+			if(ss != null) tryToClose(ss);
 			return null;
 		}
 		// Bind a multicast socket for sending packets
@@ -168,12 +165,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
 		} catch(IOException e) {
 			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
 			if(ms != null) ms.close();
-			try {
-				ss.close();
-			} catch(IOException e1) {
-				if(LOG.isLoggable(Level.WARNING))
-					LOG.warning(e1.toString());
-			}
+			tryToClose(ss);
 			return null;
 		}
 		// Send packets until a connection is received or the timeout expires
@@ -201,6 +193,9 @@ class LanSocketPlugin extends SimpleSocketPlugin {
 						interval += 1000;
 					}
 				}
+				synchronized(this) {
+					if(!running) return null;
+				}
 			}
 			if(LOG.isLoggable(Level.INFO))
 				LOG.info("Timeout while accepting invitation");
@@ -208,13 +203,16 @@ class LanSocketPlugin extends SimpleSocketPlugin {
 			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
 		} finally {
 			ms.close();
-			try {
-				ss.close();
-			} catch(IOException e1) {
-				if(LOG.isLoggable(Level.WARNING))
-					LOG.warning(e1.toString());
-			}
+			tryToClose(ss);
 		}
 		return null;
 	}
+
+	private void tryToClose(ServerSocket ss) {
+		try {
+			ss.close();
+		} catch(IOException e) {
+			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
+		}
+	}
 }
diff --git a/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java b/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java
index a38f982387..247a943a09 100644
--- a/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java
+++ b/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java
@@ -63,10 +63,8 @@ class SimpleSocketPlugin extends SocketPlugin {
 		return new ServerSocket();
 	}
 
-	// Locking: this
 	@Override
 	protected SocketAddress getLocalSocketAddress() {
-		assert running;
 		SocketAddress addr = createSocketAddress(callback.getLocalProperties());
 		if(addr == null) {
 			try {
@@ -112,17 +110,13 @@ class SimpleSocketPlugin extends SocketPlugin {
 		throw new IOException("No suitable interfaces");
 	}
 
-	// Locking: this
 	@Override
 	protected SocketAddress getRemoteSocketAddress(ContactId c) {
-		assert running;
 		TransportProperties p = callback.getRemoteProperties().get(c);
 		return p == null ? null : createSocketAddress(p);
 	}
 
-	// Locking: this
 	private SocketAddress createSocketAddress(TransportProperties p) {
-		assert running;
 		assert p != null;
 		String host = p.get("external");
 		if(host == null) host = p.get("internal");
@@ -137,10 +131,8 @@ class SimpleSocketPlugin extends SocketPlugin {
 		return new InetSocketAddress(host, port);
 	}
 
-	// Locking: this
 	@Override
 	protected void setLocalSocketAddress(SocketAddress s) {
-		assert running;
 		if(!(s instanceof InetSocketAddress))
 			throw new IllegalArgumentException();
 		InetSocketAddress i = (InetSocketAddress) s;
diff --git a/components/net/sf/briar/plugins/socket/SocketPlugin.java b/components/net/sf/briar/plugins/socket/SocketPlugin.java
index 505375dd59..77a2170bc4 100644
--- a/components/net/sf/briar/plugins/socket/SocketPlugin.java
+++ b/components/net/sf/briar/plugins/socket/SocketPlugin.java
@@ -15,21 +15,20 @@ import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.plugins.StreamPlugin;
 import net.sf.briar.api.plugins.StreamPluginCallback;
 import net.sf.briar.api.transport.StreamTransportConnection;
-import net.sf.briar.plugins.AbstractPlugin;
 
-abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
+abstract class SocketPlugin implements StreamPlugin {
 
 	private static final Logger LOG =
 		Logger.getLogger(SocketPlugin.class.getName());
 
+	protected final Executor pluginExecutor;
 	protected final StreamPluginCallback callback;
 
+	protected boolean running = false; // Locking: this
 	protected ServerSocket socket = null; // Locking: this
 
 	protected abstract void setLocalSocketAddress(SocketAddress s);
 
-	// These methods must only be called with this's lock held and
-	// started == true
 	protected abstract Socket createClientSocket() throws IOException;
 	protected abstract ServerSocket createServerSocket() throws IOException;
 	protected abstract SocketAddress getLocalSocketAddress();
@@ -37,13 +36,14 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
 
 	protected SocketPlugin(@PluginExecutor Executor pluginExecutor,
 			StreamPluginCallback callback) {
-		super(pluginExecutor);
+		this.pluginExecutor = pluginExecutor;
 		this.callback = callback;
 	}
 
-	@Override
-	public synchronized void start() throws IOException {
-		super.start();
+	public void start() throws IOException {
+		synchronized(this) {
+			running = true;
+		}
 		pluginExecutor.execute(new Runnable() {
 			public void run() {
 				bind();
@@ -55,78 +55,72 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
 		SocketAddress addr;
 		ServerSocket ss = null;
 		try {
-			synchronized(this) {
-				if(!running) return;
-				addr = getLocalSocketAddress();
-				ss = createServerSocket();
-				if(addr == null || ss == null) return;
-			}
+			addr = getLocalSocketAddress();
+			ss = createServerSocket();
+		} catch(IOException e) {
+			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
+			return;
+		}
+		if(addr == null || ss == null) return;
+		try {
 			ss.bind(addr);
-			if(LOG.isLoggable(Level.INFO)) {
-				LOG.info("Bound to " + ss.getInetAddress().getHostAddress()
-						+ ":" + ss.getLocalPort());
-			}
 		} catch(IOException e) {
 			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
-			if(ss != null) {
-				try {
-					ss.close();
-				} catch(IOException e1) {
-					if(LOG.isLoggable(Level.WARNING))
-						LOG.warning(e1.toString());
-				}
-			}
+			tryToClose(ss);
 			return;
 		}
 		synchronized(this) {
 			if(!running) {
-				try {
-					ss.close();
-				} catch(IOException e) {
-					if(LOG.isLoggable(Level.WARNING))
-						LOG.warning(e.toString());
-				}
+				tryToClose(ss);
 				return;
 			}
 			socket = ss;
-			setLocalSocketAddress(ss.getLocalSocketAddress());
 		}
-		// Accept connections until the socket is closed
+		setLocalSocketAddress(ss.getLocalSocketAddress());
+		acceptContactConnections(ss);
+	}
+
+	private void tryToClose(ServerSocket ss) {
+		try {
+			ss.close();
+		} catch(IOException e) {
+			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
+		}
+	}
+
+	private void acceptContactConnections(ServerSocket ss) {
 		while(true) {
 			Socket s;
-			synchronized(this) {
-				if(!running) return;
-			}
 			try {
 				s = ss.accept();
 			} catch(IOException e) {
 				// This is expected when the socket is closed
 				if(LOG.isLoggable(Level.INFO)) LOG.info(e.toString());
-				try {
-					ss.close();
-				} catch(IOException e1) {
-					if(LOG.isLoggable(Level.WARNING))
-						LOG.warning(e1.toString());
-				}
+				tryToClose(ss);
 				return;
 			}
 			SocketTransportConnection conn = new SocketTransportConnection(s);
 			callback.incomingConnectionCreated(conn);
+			synchronized(this) {
+				if(!running) return;
+			}
 		}
 	}
 
-	@Override
 	public synchronized void stop() throws IOException {
-		super.stop();
-		if(socket != null) socket.close();
+		running = false;
+		if(socket != null) {
+			socket.close();
+			socket = null;
+		}
 	}
 
 	public void poll() {
-		Map<ContactId, TransportProperties> remote;
 		synchronized(this) {
 			if(!running) return;
-			remote = callback.getRemoteProperties();
 		}
+		Map<ContactId, TransportProperties> remote =
+			callback.getRemoteProperties();
 		for(final ContactId c : remote.keySet()) {
 			pluginExecutor.execute(new Runnable() {
 				public void run() {
@@ -142,20 +136,18 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
 	}
 
 	public StreamTransportConnection createConnection(ContactId c) {
-		SocketAddress addr;
-		Socket s;
+		synchronized(this) {
+			if(!running) return null;
+		}
+		SocketAddress addr = getRemoteSocketAddress(c);
 		try {
-			synchronized(this) {
-				if(!running) return null;
-				addr = getRemoteSocketAddress(c);
-				s = createClientSocket();
-				if(addr == null || s == null) return null;
-			}
+			Socket s = createClientSocket();
+			if(addr == null || s == null) return null;
 			s.connect(addr);
+			return new SocketTransportConnection(s);
 		} catch(IOException e) {
 			if(LOG.isLoggable(Level.INFO)) LOG.info(e.toString());
 			return null;
 		}
-		return new SocketTransportConnection(s);
 	}
 }
-- 
GitLab