From 267a1055390c34c8d4993f68982533fe727db2cd Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Thu, 15 Nov 2012 01:31:08 +0000
Subject: [PATCH] Moved some work off the UI thread and fixed a potential
 memory leak.

---
 .../api/invitation/InvitationManager.java     |  7 +-
 .../sf/briar/invitation/ConnectorGroup.java   | 95 +++++++++++++------
 .../invitation/InvitationManagerImpl.java     | 25 ++---
 3 files changed, 76 insertions(+), 51 deletions(-)

diff --git a/src/net/sf/briar/api/invitation/InvitationManager.java b/src/net/sf/briar/api/invitation/InvitationManager.java
index 4cb6304e42..46b712adcd 100644
--- a/src/net/sf/briar/api/invitation/InvitationManager.java
+++ b/src/net/sf/briar/api/invitation/InvitationManager.java
@@ -12,6 +12,11 @@ public interface InvitationManager {
 	 */
 	InvitationTask getTask(int handle);
 
-	/** Called by tasks to remove themselves when they terminate. */
+	/** Called by tasks to add themselves to the manager when they start. */
+	void putTask(int handle, InvitationTask task);
+
+	/**
+	 * Called by tasks to remove themselves from the managet when they finish.
+	 */
 	void removeTask(int handle);
 }
diff --git a/src/net/sf/briar/invitation/ConnectorGroup.java b/src/net/sf/briar/invitation/ConnectorGroup.java
index d6d6c0045b..5c800411c7 100644
--- a/src/net/sf/briar/invitation/ConnectorGroup.java
+++ b/src/net/sf/briar/invitation/ConnectorGroup.java
@@ -4,32 +4,41 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.logging.Level.WARNING;
 import static net.sf.briar.api.plugins.InvitationConstants.CONFIRMATION_TIMEOUT;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Logger;
 
+import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.invitation.InvitationListener;
 import net.sf.briar.api.invitation.InvitationManager;
 import net.sf.briar.api.invitation.InvitationState;
 import net.sf.briar.api.invitation.InvitationTask;
+import net.sf.briar.api.plugins.PluginManager;
+import net.sf.briar.api.plugins.duplex.DuplexPlugin;
+import net.sf.briar.api.serial.ReaderFactory;
+import net.sf.briar.api.serial.WriterFactory;
 
 /** A task consisting of one or more parallel connection attempts. */
-class ConnectorGroup implements InvitationTask {
+class ConnectorGroup extends Thread implements InvitationTask {
 
 	private static final Logger LOG =
 			Logger.getLogger(ConnectorGroup.class.getName());
 
-	private final InvitationManager manager;
+	private final InvitationManager invitationManager;
+	private final CryptoComponent crypto;
+	private final ReaderFactory readerFactory;
+	private final WriterFactory writerFactory;
+	private final PluginManager pluginManager;
 	private final int handle, localInvitationCode, remoteInvitationCode;
-	private final Collection<Connector> connectors;
 	private final Collection<InvitationListener> listeners;
 	private final AtomicBoolean connected;
 	private final CountDownLatch localConfirmationLatch;
 
 	/*
-	 * All of the following are locking: this. We don't want to call the
+	 * All of the following require locking: this. We don't want to call the
 	 * listeners with a lock held, but we need to avoid a race condition in
 	 * addListener(), so the state that's accessed there after calling
 	 * listeners.add() must be guarded by a lock.
@@ -39,13 +48,18 @@ class ConnectorGroup implements InvitationTask {
 	private boolean localCompared = false, remoteCompared = false;
 	private boolean localMatched = false, remoteMatched = false;
 
-	ConnectorGroup(InvitationManager manager, int handle,
-			int localInvitationCode, int remoteInvitationCode) {
-		this.manager = manager;
+	ConnectorGroup(InvitationManager invitationManager, CryptoComponent crypto,
+			ReaderFactory readerFactory, WriterFactory writerFactory,
+			PluginManager pluginManager, int handle, int localInvitationCode,
+			int remoteInvitationCode) {
+		this.invitationManager = invitationManager;
+		this.crypto = crypto;
+		this.readerFactory = readerFactory;
+		this.writerFactory = writerFactory;
+		this.pluginManager = pluginManager;
 		this.handle = handle;
 		this.localInvitationCode = localInvitationCode;
 		this.remoteInvitationCode = remoteInvitationCode;
-		connectors = new CopyOnWriteArrayList<Connector>();
 		listeners = new CopyOnWriteArrayList<InvitationListener>();
 		connected = new AtomicBoolean(false);
 		localConfirmationLatch = new CountDownLatch(1);
@@ -66,27 +80,50 @@ class ConnectorGroup implements InvitationTask {
 		listeners.remove(l);
 	}
 
-	// FIXME: The task isn't removed from the manager unless this is called
 	public void connect() {
-		for(Connector c : connectors) c.start();
-		new Thread() {
-			@Override
-			public void run() {
-				try {
-					for(Connector c : connectors) c.join();
-				} catch(InterruptedException e) {
-					if(LOG.isLoggable(WARNING))
-						LOG.warning("Interrupted while waiting for connectors");
-				}
-				if(!connected.get()) {
-					synchronized(ConnectorGroup.this) {
-						connectionFailed = true;
-					}
-					for(InvitationListener l : listeners) l.connectionFailed();
-				}
-				manager.removeTask(handle);
+		start();
+	}
+
+	@Override
+	public void run() {
+		// Add this task to the manager
+		invitationManager.putTask(handle, this);
+		// Start the connection threads
+		final Collection<Connector> connectors = new ArrayList<Connector>();
+		// Alice is the party with the smaller invitation code
+		if(localInvitationCode < remoteInvitationCode) {
+			for(DuplexPlugin plugin : pluginManager.getInvitationPlugins()) {
+				Connector c = new AliceConnector(crypto, readerFactory,
+						writerFactory, this, plugin, localInvitationCode,
+						remoteInvitationCode);
+				connectors.add(c);
+				c.start();
+			}
+		} else {
+			for(DuplexPlugin plugin: pluginManager.getInvitationPlugins()) {
+				Connector c = (new BobConnector(crypto, readerFactory,
+						writerFactory, this, plugin, localInvitationCode,
+						remoteInvitationCode));
+				connectors.add(c);
+				c.start();
 			}
-		}.start();
+		}
+		// Wait for the connection threads to finish
+		try {
+			for(Connector c : connectors) c.join();
+		} catch(InterruptedException e) {
+			if(LOG.isLoggable(WARNING))
+				LOG.warning("Interrupted while waiting for connectors");
+		}
+		// If none of the threads connected, inform the listeners
+		if(!connected.get()) {
+			synchronized(this) {
+				connectionFailed = true;
+			}
+			for(InvitationListener l : listeners) l.connectionFailed();
+		}
+		// Remove this task from the manager
+		invitationManager.removeTask(handle);
 	}
 
 	public void localConfirmationSucceeded() {
@@ -104,10 +141,6 @@ class ConnectorGroup implements InvitationTask {
 		localConfirmationLatch.countDown();
 	}
 
-	void addConnector(Connector c) {
-		connectors.add(c);
-	}
-
 	boolean getAndSetConnected() {
 		return connected.getAndSet(true);
 	}
diff --git a/src/net/sf/briar/invitation/InvitationManagerImpl.java b/src/net/sf/briar/invitation/InvitationManagerImpl.java
index 33c06fa2cd..be47b398ab 100644
--- a/src/net/sf/briar/invitation/InvitationManagerImpl.java
+++ b/src/net/sf/briar/invitation/InvitationManagerImpl.java
@@ -1,6 +1,5 @@
 package net.sf.briar.invitation;
 
-import java.util.Collection;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -9,7 +8,6 @@ import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.invitation.InvitationManager;
 import net.sf.briar.api.invitation.InvitationTask;
 import net.sf.briar.api.plugins.PluginManager;
-import net.sf.briar.api.plugins.duplex.DuplexPlugin;
 import net.sf.briar.api.serial.ReaderFactory;
 import net.sf.briar.api.serial.WriterFactory;
 
@@ -37,30 +35,19 @@ class InvitationManagerImpl implements InvitationManager {
 	}
 
 	public InvitationTask createTask(int localCode, int remoteCode) {
-		Collection<DuplexPlugin> plugins = pluginManager.getInvitationPlugins();
 		int handle = nextHandle.incrementAndGet();
-		ConnectorGroup group =
-				new ConnectorGroup(this, handle, localCode, remoteCode);
-		// Alice is the peer with the lesser invitation code
-		if(localCode < remoteCode) {
-			for(DuplexPlugin plugin : plugins) {
-				group.addConnector(new AliceConnector(crypto, readerFactory,
-						writerFactory, group, plugin, localCode, remoteCode));
-			}
-		} else {
-			for(DuplexPlugin plugin : plugins) {
-				group.addConnector(new BobConnector(crypto, readerFactory,
-						writerFactory, group, plugin, localCode, remoteCode));
-			}
-		}
-		tasks.put(handle, group);
-		return group;
+		return new ConnectorGroup(this, crypto, readerFactory, writerFactory,
+				pluginManager, handle, localCode, remoteCode);
 	}
 
 	public InvitationTask getTask(int handle) {
 		return tasks.get(handle);
 	}
 
+	public void putTask(int handle, InvitationTask task) {
+		tasks.put(handle, task);
+	}
+
 	public void removeTask(int handle) {
 		tasks.remove(handle);
 	}
-- 
GitLab