diff --git a/api/net/sf/briar/api/transport/batch/BatchTransportCallback.java b/api/net/sf/briar/api/transport/batch/BatchTransportCallback.java index 8ad8b4221060af085a876ec403e8ddb73ff7c90b..44387029f696fc461a8a6a9457c14460fc919fcf 100644 --- a/api/net/sf/briar/api/transport/batch/BatchTransportCallback.java +++ b/api/net/sf/briar/api/transport/batch/BatchTransportCallback.java @@ -1,5 +1,7 @@ package net.sf.briar.api.transport.batch; +import net.sf.briar.api.ContactId; +import net.sf.briar.api.TransportId; import net.sf.briar.api.transport.TransportCallback; /** @@ -8,7 +10,9 @@ import net.sf.briar.api.transport.TransportCallback; */ public interface BatchTransportCallback extends TransportCallback { - void readerCreated(BatchTransportReader r); + void readerCreated(ContactId contactId, byte[] encryptedIv, + BatchTransportReader r); - void writerCreated(BatchTransportWriter w); + void writerCreated(ContactId contactId, TransportId t, long connection, + BatchTransportWriter w); } diff --git a/api/net/sf/briar/api/transport/batch/BatchTransportPlugin.java b/api/net/sf/briar/api/transport/batch/BatchTransportPlugin.java index f217b4691b77745880fb8bca5c99dbf8f47c732f..09482f12bf468780631c87402eeaef3501e28ca7 100644 --- a/api/net/sf/briar/api/transport/batch/BatchTransportPlugin.java +++ b/api/net/sf/briar/api/transport/batch/BatchTransportPlugin.java @@ -1,5 +1,6 @@ package net.sf.briar.api.transport.batch; +import java.io.IOException; import java.util.Map; import net.sf.briar.api.ContactId; @@ -23,13 +24,13 @@ public interface BatchTransportPlugin { void start(Map<String, String> localProperties, Map<ContactId, Map<String, String>> remoteProperties, Map<String, String> config, BatchTransportCallback c) - throws InvalidTransportException, InvalidConfigException; + throws InvalidTransportException, InvalidConfigException, IOException; /** * Stops the plugin. No further connections will be passed to the callback * after this method has returned. */ - void stop(); + void stop() throws IOException; /** Updates the plugin's local transport properties. */ void setLocalProperties(Map<String, String> properties) diff --git a/api/net/sf/briar/api/transport/stream/StreamTransportCallback.java b/api/net/sf/briar/api/transport/stream/StreamTransportCallback.java index d58d0ecbc5cb9b577ae4197b4ec77fa4b4b6284f..fe741b8c2af8c4a5a0cb4db24070c6cb4da66b1a 100644 --- a/api/net/sf/briar/api/transport/stream/StreamTransportCallback.java +++ b/api/net/sf/briar/api/transport/stream/StreamTransportCallback.java @@ -1,5 +1,7 @@ package net.sf.briar.api.transport.stream; +import net.sf.briar.api.ContactId; +import net.sf.briar.api.TransportId; import net.sf.briar.api.transport.TransportCallback; /** @@ -8,5 +10,9 @@ import net.sf.briar.api.transport.TransportCallback; */ public interface StreamTransportCallback extends TransportCallback { - void connectionCreated(StreamTransportConnection c); + void incomingConnectionCreated(ContactId contactId, byte[] encryptedIv, + StreamTransportConnection c); + + void outgoingConnectionCreated(ContactId contactId, TransportId t, + long connection, StreamTransportConnection c); } diff --git a/components/net/sf/briar/plugins/file/FilePlugin.java b/components/net/sf/briar/plugins/file/FilePlugin.java index 93c745fb008cc5f2ca302bdb25781b65a29d8cdf..81c1a6a1284041efb5419b14fd156cb4fc5a4f73 100644 --- a/components/net/sf/briar/plugins/file/FilePlugin.java +++ b/components/net/sf/briar/plugins/file/FilePlugin.java @@ -1,12 +1,15 @@ package net.sf.briar.plugins.file; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Map; import net.sf.briar.api.ContactId; +import net.sf.briar.api.db.DbException; +import net.sf.briar.api.transport.ConnectionRecogniser; import net.sf.briar.api.transport.InvalidConfigException; import net.sf.briar.api.transport.InvalidTransportException; import net.sf.briar.api.transport.TransportConstants; @@ -19,6 +22,8 @@ import org.apache.commons.io.FileSystemUtils; abstract class FilePlugin implements BatchTransportPlugin { + private final ConnectionRecogniser recogniser; + protected Map<String, String> localProperties = null; protected Map<ContactId, Map<String, String>> remoteProperties = null; protected Map<String, String> config = null; @@ -28,10 +33,14 @@ abstract class FilePlugin implements BatchTransportPlugin { protected abstract File chooseOutputDirectory(); protected abstract void writerFinished(File f); + FilePlugin(ConnectionRecogniser recogniser) { + this.recogniser = recogniser; + } + public synchronized void start(Map<String, String> localProperties, Map<ContactId, Map<String, String>> remoteProperties, Map<String, String> config, BatchTransportCallback callback) - throws InvalidTransportException, InvalidConfigException { + throws InvalidTransportException, InvalidConfigException, IOException { if(started) throw new IllegalStateException(); started = true; this.localProperties = localProperties; @@ -40,7 +49,7 @@ abstract class FilePlugin implements BatchTransportPlugin { this.callback = callback; } - public synchronized void stop() { + public synchronized void stop() throws IOException { if(!started) throw new IllegalStateException(); started = false; } @@ -106,4 +115,37 @@ abstract class FilePlugin implements BatchTransportPlugin { protected long getCapacity(String path) throws IOException { return FileSystemUtils.freeSpaceKb(path) * 1024L; } + + protected void createReaderFromFile(File f) { + if(!isPossibleConnectionFilename(f.getName())) return; + if(f.length() < TransportConstants.MIN_CONNECTION_LENGTH) return; + try { + FileInputStream in = new FileInputStream(f); + byte[] iv = new byte[TransportConstants.IV_LENGTH]; + int offset = 0; + while(offset < iv.length) { + int read = in.read(iv, offset, iv.length - offset); + if(read == -1) break; + offset += read; + } + ContactId c = recogniser.acceptConnection(iv); + if(c == null) { + // Nobody there + in.close(); + return; + } + FileTransportReader reader = new FileTransportReader(f, in); + callback.readerCreated(c, iv, reader); + } catch(DbException e) { + // FIXME: At least log it + return; + } catch(IOException e) { + // FIXME: At least log it + return; + } + } + + protected boolean isPossibleConnectionFilename(String filename) { + return filename.toLowerCase().matches("[a-z]{8}\\.dat"); + } } diff --git a/components/net/sf/briar/plugins/file/FileTransportReader.java b/components/net/sf/briar/plugins/file/FileTransportReader.java new file mode 100644 index 0000000000000000000000000000000000000000..50f6b55574aacbeb5c370d629cf6187ad1326611 --- /dev/null +++ b/components/net/sf/briar/plugins/file/FileTransportReader.java @@ -0,0 +1,30 @@ +package net.sf.briar.plugins.file; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import net.sf.briar.api.transport.batch.BatchTransportReader; + +class FileTransportReader implements BatchTransportReader { + + private final File file; + private final InputStream in; + + private boolean streamInUse = false; + + FileTransportReader(File file, InputStream in) { + this.file = file; + this.in = in; + } + + public InputStream getInputStream() { + streamInUse = true; + return in; + } + + public void dispose() throws IOException { + if(streamInUse) in.close(); + file.delete(); + } +} diff --git a/components/net/sf/briar/plugins/file/PollingRemovableDriveMonitor.java b/components/net/sf/briar/plugins/file/PollingRemovableDriveMonitor.java index f693aa6a9985dfb1c1c5d220406d3bd4877709a7..853899befc1d5855ff29146878f21192840c5567 100644 --- a/components/net/sf/briar/plugins/file/PollingRemovableDriveMonitor.java +++ b/components/net/sf/briar/plugins/file/PollingRemovableDriveMonitor.java @@ -2,52 +2,39 @@ package net.sf.briar.plugins.file; import java.io.File; import java.io.IOException; -import java.util.LinkedList; import java.util.List; class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable { private final RemovableDriveFinder finder; private final long pollingInterval; - private final LinkedList<File> inserted; - private final LinkedList<IOException> exceptions; - private final Object pollingLock; + private final Object pollingLock = new Object(); - private boolean started = false, stopped = false; - private Thread pollingThread = null; + private volatile boolean running = false; + private volatile Callback callback = null; + private volatile IOException exception = null; public PollingRemovableDriveMonitor(RemovableDriveFinder finder, long pollingInterval) { this.finder = finder; this.pollingInterval = pollingInterval; - inserted = new LinkedList<File>(); - exceptions = new LinkedList<IOException>(); - pollingLock = new Object(); } - public synchronized void start() throws IOException { - if(started || stopped) throw new IllegalStateException(); - started = true; - pollingThread = new Thread(this); - pollingThread.start(); - } - - public synchronized File waitForInsertion() throws IOException { - if(!started || stopped) throw new IllegalStateException(); - if(!exceptions.isEmpty()) throw exceptions.poll(); - while(inserted.isEmpty()) { - try { - wait(); - } catch(InterruptedException ignored) {} - if(!exceptions.isEmpty()) throw exceptions.poll(); - } - return inserted.poll(); + public synchronized void start(Callback callback) throws IOException { + if(running) throw new IllegalStateException(); + running = true; + this.callback = callback; + new Thread(this).start(); } public synchronized void stop() throws IOException { - if(!started || stopped) throw new IllegalStateException(); - if(!exceptions.isEmpty()) throw exceptions.poll(); - stopped = true; + if(!running) throw new IllegalStateException(); + running = false; + if(exception != null) { + IOException e = exception; + exception = null; + throw e; + } synchronized(pollingLock) { pollingLock.notifyAll(); } @@ -56,34 +43,21 @@ class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable { public void run() { try { List<File> drives = finder.findRemovableDrives(); - while(true) { - synchronized(this) { - if(stopped) return; - } + while(running) { synchronized(pollingLock) { try { pollingLock.wait(pollingInterval); } catch(InterruptedException ignored) {} } - synchronized(this) { - if(stopped) return; - } + if(!running) return; List<File> newDrives = finder.findRemovableDrives(); for(File f : newDrives) { - if(!drives.contains(f)) { - synchronized(this) { - inserted.add(f); - notifyAll(); - } - } + if(!drives.contains(f)) callback.driveInserted(f); } drives = newDrives; } } catch(IOException e) { - synchronized(this) { - exceptions.add(e); - notifyAll(); - } + exception = e; } } } diff --git a/components/net/sf/briar/plugins/file/RemovableDriveMonitor.java b/components/net/sf/briar/plugins/file/RemovableDriveMonitor.java index 3ce0cc5f27b716edfb44e00ca206b28f9994fcd9..ce9aeeca1633018dd2922295e297712c6529a941 100644 --- a/components/net/sf/briar/plugins/file/RemovableDriveMonitor.java +++ b/components/net/sf/briar/plugins/file/RemovableDriveMonitor.java @@ -5,9 +5,12 @@ import java.io.IOException; interface RemovableDriveMonitor { - void start() throws IOException; - - File waitForInsertion() throws IOException; + void start(Callback c) throws IOException; void stop() throws IOException; + + interface Callback { + + void driveInserted(File f); + } } diff --git a/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java b/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java index 758c3e9e8e79561b092fae857a8819dd386b0cf5..bd959c219c598befbd268e110e3152c0b1440141 100644 --- a/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java +++ b/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java @@ -3,25 +3,51 @@ package net.sf.briar.plugins.file; import java.io.File; import java.io.IOException; import java.util.List; +import java.util.Map; +import net.sf.briar.api.ContactId; import net.sf.briar.api.TransportId; +import net.sf.briar.api.transport.ConnectionRecogniser; +import net.sf.briar.api.transport.InvalidConfigException; +import net.sf.briar.api.transport.InvalidTransportException; +import net.sf.briar.api.transport.batch.BatchTransportCallback; -class RemovableDrivePlugin extends FilePlugin { +class RemovableDrivePlugin extends FilePlugin +implements RemovableDriveMonitor.Callback { public static final int TRANSPORT_ID = 0; private static final TransportId id = new TransportId(TRANSPORT_ID); private final RemovableDriveFinder finder; + private final RemovableDriveMonitor monitor; - RemovableDrivePlugin(RemovableDriveFinder finder) { + RemovableDrivePlugin(ConnectionRecogniser recogniser, + RemovableDriveFinder finder, RemovableDriveMonitor monitor) { + super(recogniser); this.finder = finder; + this.monitor = monitor; } public TransportId getId() { return id; } + @Override + public void start(Map<String, String> localProperties, + Map<ContactId, Map<String, String>> remoteProperties, + Map<String, String> config, BatchTransportCallback callback) + throws InvalidTransportException, InvalidConfigException, IOException { + super.start(localProperties, remoteProperties, config, callback); + monitor.start(this); + } + + @Override + public void stop() throws IOException { + super.stop(); + monitor.stop(); + } + @Override protected File chooseOutputDirectory() { try { @@ -43,4 +69,9 @@ class RemovableDrivePlugin extends FilePlugin { protected void writerFinished(File f) { callback.showMessage("REMOVABLE_DRIVE_WRITE_FINISHED"); } + + public void driveInserted(File root) { + File[] files = root.listFiles(); + if(files != null) for(File f : files) createReaderFromFile(f); + } } diff --git a/components/net/sf/briar/plugins/file/UnixRemovableDriveMonitor.java b/components/net/sf/briar/plugins/file/UnixRemovableDriveMonitor.java index 3a211cc509063e41839fc1d5c73195a2eac4ed1b..c4daf247094c9c0d2fd3fe9fcdcdef41e537e080 100644 --- a/components/net/sf/briar/plugins/file/UnixRemovableDriveMonitor.java +++ b/components/net/sf/briar/plugins/file/UnixRemovableDriveMonitor.java @@ -3,7 +3,6 @@ package net.sf.briar.plugins.file; import java.io.File; import java.io.IOException; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; import net.contentobjects.jnotify.JNotify; @@ -13,15 +12,16 @@ abstract class UnixRemovableDriveMonitor implements RemovableDriveMonitor, JNotifyListener { private final List<Integer> watches = new ArrayList<Integer>(); - private final LinkedList<File> inserted = new LinkedList<File>(); - private boolean started = false, stopped = false; + private boolean started = false; + private Callback callback = null; protected abstract String[] getPathsToWatch(); - public synchronized void start() throws IOException { - if(started || stopped) throw new IllegalStateException(); + public synchronized void start(Callback callback) throws IOException { + if(started) throw new IllegalStateException(); started = true; + this.callback = callback; int mask = JNotify.FILE_CREATED; for(String path : getPathsToWatch()) { if(new File(path).exists()) @@ -29,26 +29,18 @@ JNotifyListener { } } - public synchronized File waitForInsertion() throws IOException { - if(!started || stopped) throw new IllegalStateException(); - while(inserted.isEmpty()) { - try { - wait(); - } catch(InterruptedException ignored) {} - } - return inserted.poll(); - } - public synchronized void stop() throws IOException { - if(!started || stopped) throw new IllegalStateException(); - stopped = true; + if(!started) throw new IllegalStateException(); + started = false; + callback = null; for(Integer w : watches) JNotify.removeWatch(w); + watches.clear(); } public void fileCreated(int wd, String rootPath, String name) { synchronized(this) { - inserted.add(new File(rootPath + "/" + name)); - notifyAll(); + if(!started) throw new IllegalStateException(); + callback.driveInserted(new File(rootPath + "/" + name)); } } diff --git a/test/net/sf/briar/plugins/file/PollingRemovableDriveMonitorTest.java b/test/net/sf/briar/plugins/file/PollingRemovableDriveMonitorTest.java index b559886e39b07fd6d32770dcb6b6a3a335a4602a..1d64cbc5c9eb2c0a1bf348122ccc8f6522c91ec0 100644 --- a/test/net/sf/briar/plugins/file/PollingRemovableDriveMonitorTest.java +++ b/test/net/sf/briar/plugins/file/PollingRemovableDriveMonitorTest.java @@ -10,6 +10,8 @@ import java.util.concurrent.TimeUnit; import junit.framework.TestCase; +import net.sf.briar.plugins.file.RemovableDriveMonitor.Callback; + import org.jmock.Expectations; import org.jmock.Mockery; import org.junit.Test; @@ -18,15 +20,13 @@ public class PollingRemovableDriveMonitorTest extends TestCase { @Test public void testOneCallbackPerFile() throws Exception { - final CountDownLatch latch = new CountDownLatch(1); - final List<File> detected = new ArrayList<File>(); final File file1 = new File("foo"); final File file2 = new File("bar"); + // Create a finder that returns no files the first time, then two files final List<File> noDrives = Collections.emptyList(); final List<File> twoDrives = new ArrayList<File>(); twoDrives.add(file1); twoDrives.add(file2); - // Create a finder that returns no files the first time, then two files Mockery context = new Mockery(); final RemovableDriveFinder finder = context.mock(RemovableDriveFinder.class); @@ -36,24 +36,21 @@ public class PollingRemovableDriveMonitorTest extends TestCase { oneOf(finder).findRemovableDrives(); will(returnValue(twoDrives)); }}); - // Create a monitor that will wait for two files before stopping + // Create a callback that will wait for two files before stopping + final List<File> detected = new ArrayList<File>(); + final CountDownLatch latch = new CountDownLatch(2); + final Callback callback = new Callback() { + public void driveInserted(File f) { + detected.add(f); + latch.countDown(); + } + }; + // Create the monitor and start it final RemovableDriveMonitor monitor = new PollingRemovableDriveMonitor(finder, 10); - monitor.start(); - new Thread() { - @Override - public void run() { - try { - detected.add(monitor.waitForInsertion()); - detected.add(monitor.waitForInsertion()); - latch.countDown(); - } catch(IOException e) { - fail(); - } - } - }.start(); + monitor.start(callback); // Wait for the monitor to detect the files - assertTrue(latch.await(2, TimeUnit.SECONDS)); + assertTrue(latch.await(1, TimeUnit.SECONDS)); monitor.stop(); // Check that both files were detected assertEquals(2, detected.size()); @@ -63,32 +60,6 @@ public class PollingRemovableDriveMonitorTest extends TestCase { context.assertIsSatisfied(); } - @Test - public void testExceptionRethrownWhenWaiting() throws Exception { - final List<File> noDrives = Collections.emptyList(); - // Create a finder that throws an exception the second time it's polled - Mockery context = new Mockery(); - final RemovableDriveFinder finder = - context.mock(RemovableDriveFinder.class); - context.checking(new Expectations() {{ - oneOf(finder).findRemovableDrives(); - will(returnValue(noDrives)); - oneOf(finder).findRemovableDrives(); - will(throwException(new IOException())); - }}); - // The monitor should rethrow the exception when it waits - final RemovableDriveMonitor monitor = - new PollingRemovableDriveMonitor(finder, 10); - monitor.start(); - try { - monitor.waitForInsertion(); - fail(); - } catch(IOException expected) {} - // The exception shouldn't be thrown again - monitor.stop(); - context.assertIsSatisfied(); - } - @Test public void testExceptionRethrownWhenStopping() throws Exception { final List<File> noDrives = Collections.emptyList(); @@ -102,11 +73,12 @@ public class PollingRemovableDriveMonitorTest extends TestCase { oneOf(finder).findRemovableDrives(); will(throwException(new IOException())); }}); - // The monitor should rethrow the exception when it stops + // Create the monitor, start it, and give it some time to run final RemovableDriveMonitor monitor = new PollingRemovableDriveMonitor(finder, 10); - monitor.start(); + monitor.start(null); Thread.sleep(50); + // The monitor should rethrow the exception when it stops try { monitor.stop(); fail(); diff --git a/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java b/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java index bf1a00077e283583c1f7fc4bd54f68336bdef9af..54a49c30d69094a1f9148ce28d515becb20d8973 100644 --- a/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java +++ b/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java @@ -9,8 +9,10 @@ import java.util.List; import junit.framework.TestCase; import net.sf.briar.TestUtils; import net.sf.briar.api.ContactId; +import net.sf.briar.api.transport.ConnectionRecogniser; import net.sf.briar.api.transport.batch.BatchTransportCallback; import net.sf.briar.api.transport.batch.BatchTransportWriter; +import net.sf.briar.plugins.file.RemovableDriveMonitor.Callback; import org.jmock.Expectations; import org.jmock.Mockery; @@ -31,9 +33,14 @@ public class RemovableDrivePluginTest extends TestCase { @Test public void testGetId() { Mockery context = new Mockery(); + final ConnectionRecogniser recogniser = + context.mock(ConnectionRecogniser.class); final RemovableDriveFinder finder = context.mock(RemovableDriveFinder.class); - RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder); + final RemovableDriveMonitor monitor = + context.mock(RemovableDriveMonitor.class); + RemovableDrivePlugin plugin = new RemovableDrivePlugin(recogniser, + finder, monitor); assertEquals(RemovableDrivePlugin.TRANSPORT_ID, plugin.getId().getInt()); @@ -46,15 +53,23 @@ public class RemovableDrivePluginTest extends TestCase { final List<File> drives = Collections.emptyList(); Mockery context = new Mockery(); + final ConnectionRecogniser recogniser = + context.mock(ConnectionRecogniser.class); final RemovableDriveFinder finder = context.mock(RemovableDriveFinder.class); + final RemovableDriveMonitor monitor = + context.mock(RemovableDriveMonitor.class); final BatchTransportCallback callback = context.mock(BatchTransportCallback.class); + context.checking(new Expectations() {{ + oneOf(monitor).start(with(any(Callback.class))); oneOf(finder).findRemovableDrives(); will(returnValue(drives)); }}); - RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder); + + RemovableDrivePlugin plugin = new RemovableDrivePlugin(recogniser, + finder, monitor); plugin.start(null, null, null, callback); assertNull(plugin.createWriter(contactId)); @@ -71,18 +86,26 @@ public class RemovableDrivePluginTest extends TestCase { drives.add(drive2); Mockery context = new Mockery(); + final ConnectionRecogniser recogniser = + context.mock(ConnectionRecogniser.class); final RemovableDriveFinder finder = context.mock(RemovableDriveFinder.class); + final RemovableDriveMonitor monitor = + context.mock(RemovableDriveMonitor.class); final BatchTransportCallback callback = context.mock(BatchTransportCallback.class); + context.checking(new Expectations() {{ + oneOf(monitor).start(with(any(Callback.class))); oneOf(finder).findRemovableDrives(); will(returnValue(drives)); oneOf(callback).showChoice(with(any(String.class)), with(any(String[].class))); will(returnValue(-1)); // The user cancelled the choice }}); - RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder); + + RemovableDrivePlugin plugin = new RemovableDrivePlugin(recogniser, + finder, monitor); plugin.start(null, null, null, callback); assertNull(plugin.createWriter(contactId)); @@ -101,18 +124,26 @@ public class RemovableDrivePluginTest extends TestCase { drives.add(drive2); Mockery context = new Mockery(); + final ConnectionRecogniser recogniser = + context.mock(ConnectionRecogniser.class); final RemovableDriveFinder finder = context.mock(RemovableDriveFinder.class); + final RemovableDriveMonitor monitor = + context.mock(RemovableDriveMonitor.class); final BatchTransportCallback callback = context.mock(BatchTransportCallback.class); + context.checking(new Expectations() {{ + oneOf(monitor).start(with(any(Callback.class))); oneOf(finder).findRemovableDrives(); will(returnValue(drives)); oneOf(callback).showChoice(with(any(String.class)), with(any(String[].class))); will(returnValue(0)); // The user chose drive1 but it doesn't exist }}); - RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder); + + RemovableDrivePlugin plugin = new RemovableDrivePlugin(recogniser, + finder, monitor); plugin.start(null, null, null, callback); assertNull(plugin.createWriter(contactId)); @@ -133,18 +164,26 @@ public class RemovableDrivePluginTest extends TestCase { assertTrue(drive1.createNewFile()); Mockery context = new Mockery(); + final ConnectionRecogniser recogniser = + context.mock(ConnectionRecogniser.class); final RemovableDriveFinder finder = context.mock(RemovableDriveFinder.class); + final RemovableDriveMonitor monitor = + context.mock(RemovableDriveMonitor.class); final BatchTransportCallback callback = context.mock(BatchTransportCallback.class); + context.checking(new Expectations() {{ + oneOf(monitor).start(with(any(Callback.class))); oneOf(finder).findRemovableDrives(); will(returnValue(drives)); oneOf(callback).showChoice(with(any(String.class)), with(any(String[].class))); will(returnValue(0)); // The user chose drive1 but it's not a dir }}); - RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder); + + RemovableDrivePlugin plugin = new RemovableDrivePlugin(recogniser, + finder, monitor); plugin.start(null, null, null, callback); assertNull(plugin.createWriter(contactId)); @@ -165,18 +204,26 @@ public class RemovableDrivePluginTest extends TestCase { assertTrue(drive1.mkdir()); Mockery context = new Mockery(); + final ConnectionRecogniser recogniser = + context.mock(ConnectionRecogniser.class); final RemovableDriveFinder finder = context.mock(RemovableDriveFinder.class); + final RemovableDriveMonitor monitor = + context.mock(RemovableDriveMonitor.class); final BatchTransportCallback callback = context.mock(BatchTransportCallback.class); + context.checking(new Expectations() {{ + oneOf(monitor).start(with(any(Callback.class))); oneOf(finder).findRemovableDrives(); will(returnValue(drives)); oneOf(callback).showChoice(with(any(String.class)), with(any(String[].class))); will(returnValue(0)); // The user chose drive1 }}); - RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder); + + RemovableDrivePlugin plugin = new RemovableDrivePlugin(recogniser, + finder, monitor); plugin.start(null, null, null, callback); assertNotNull(plugin.createWriter(contactId)); @@ -200,11 +247,17 @@ public class RemovableDrivePluginTest extends TestCase { assertTrue(drive1.mkdir()); Mockery context = new Mockery(); + final ConnectionRecogniser recogniser = + context.mock(ConnectionRecogniser.class); final RemovableDriveFinder finder = context.mock(RemovableDriveFinder.class); + final RemovableDriveMonitor monitor = + context.mock(RemovableDriveMonitor.class); final BatchTransportCallback callback = context.mock(BatchTransportCallback.class); + context.checking(new Expectations() {{ + oneOf(monitor).start(with(any(Callback.class))); oneOf(finder).findRemovableDrives(); will(returnValue(drives)); oneOf(callback).showChoice(with(any(String.class)), @@ -212,7 +265,9 @@ public class RemovableDrivePluginTest extends TestCase { will(returnValue(0)); // The user chose drive1 oneOf(callback).showMessage(with(any(String.class))); }}); - RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder); + + RemovableDrivePlugin plugin = new RemovableDrivePlugin(recogniser, + finder, monitor); plugin.start(null, null, null, callback); BatchTransportWriter writer = plugin.createWriter(contactId); diff --git a/test/net/sf/briar/plugins/file/UnixRemovableDriveMonitorTest.java b/test/net/sf/briar/plugins/file/UnixRemovableDriveMonitorTest.java index 2c2dd6047a17d30096dfab431831daa56507e7d2..1ed814d038dfb03eccebcb07ddac128616d96b44 100644 --- a/test/net/sf/briar/plugins/file/UnixRemovableDriveMonitorTest.java +++ b/test/net/sf/briar/plugins/file/UnixRemovableDriveMonitorTest.java @@ -1,7 +1,6 @@ package net.sf.briar.plugins.file; import java.io.File; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; @@ -9,6 +8,7 @@ import java.util.concurrent.TimeUnit; import junit.framework.TestCase; import net.sf.briar.TestUtils; +import net.sf.briar.plugins.file.RemovableDriveMonitor.Callback; import org.junit.After; import org.junit.Before; @@ -27,36 +27,31 @@ public class UnixRemovableDriveMonitorTest extends TestCase { public void testNonexistentDir() throws Exception { File doesNotExist = new File(testDir, "doesNotExist"); RemovableDriveMonitor monitor = createMonitor(doesNotExist); - monitor.start(); + monitor.start(null); monitor.stop(); } @Test public void testOneCallbackPerFile() throws Exception { - final CountDownLatch latch = new CountDownLatch(1); + // Create a callback that will wait for two files before stopping final List<File> detected = new ArrayList<File>(); - // Create a monitor that will wait for two files before stopping - final RemovableDriveMonitor monitor = createMonitor(testDir); - monitor.start(); - new Thread() { - @Override - public void run() { - try { - detected.add(monitor.waitForInsertion()); - detected.add(monitor.waitForInsertion()); - latch.countDown(); - } catch(IOException e) { - fail(); - } + final CountDownLatch latch = new CountDownLatch(2); + final Callback callback = new Callback() { + public void driveInserted(File f) { + detected.add(f); + latch.countDown(); } - }.start(); + }; + // Create the monitor and start it + RemovableDriveMonitor monitor = createMonitor(testDir); + monitor.start(callback); // Create two files in the test directory File file1 = new File(testDir, "1"); File file2 = new File(testDir, "2"); assertTrue(file1.createNewFile()); assertTrue(file2.createNewFile()); // Wait for the monitor to detect the files - assertTrue(latch.await(2, TimeUnit.SECONDS)); + assertTrue(latch.await(1, TimeUnit.SECONDS)); monitor.stop(); // Check that both files were detected assertEquals(2, detected.size());