mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Moved all automatic connection logic into poller.
This commit is contained in:
@@ -2,24 +2,39 @@ package org.briarproject.api.plugins;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Responsible for starting transport plugins at startup, stopping them at
|
||||
* shutdown, and providing access to plugins for exchanging invitations.
|
||||
* Responsible for starting transport plugins at startup and stopping them at
|
||||
* shutdown.
|
||||
*/
|
||||
public interface PluginManager {
|
||||
|
||||
/**
|
||||
* Returns the plugin for the given transport, or null if no such plugin
|
||||
* is running.
|
||||
* has been created.
|
||||
*/
|
||||
Plugin getPlugin(TransportId t);
|
||||
|
||||
/** Returns any running duplex plugins that support invitations. */
|
||||
/**
|
||||
* Returns any simplex plugins that have been created.
|
||||
*/
|
||||
Collection<SimplexPlugin> getSimplexPlugins();
|
||||
|
||||
/**
|
||||
* Returns any duplex plugins that have been created.
|
||||
*/
|
||||
Collection<DuplexPlugin> getDuplexPlugins();
|
||||
|
||||
/**
|
||||
* Returns any duplex plugins that support invitations.
|
||||
*/
|
||||
Collection<DuplexPlugin> getInvitationPlugins();
|
||||
|
||||
/** Returns any running duplex plugins that support key agreement. */
|
||||
/**
|
||||
* Returns any duplex plugins that support key agreement.
|
||||
*/
|
||||
Collection<DuplexPlugin> getKeyAgreementPlugins();
|
||||
}
|
||||
|
||||
@@ -3,18 +3,13 @@ package org.briarproject.plugins;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.event.ConnectionClosedEvent;
|
||||
import org.briarproject.api.event.ContactStatusChangedEvent;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.TransportDisabledEvent;
|
||||
import org.briarproject.api.event.TransportEnabledEvent;
|
||||
import org.briarproject.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.api.lifecycle.Service;
|
||||
import org.briarproject.api.lifecycle.ServiceException;
|
||||
import org.briarproject.api.plugins.ConnectionManager;
|
||||
import org.briarproject.api.plugins.ConnectionRegistry;
|
||||
import org.briarproject.api.plugins.Plugin;
|
||||
import org.briarproject.api.plugins.PluginCallback;
|
||||
import org.briarproject.api.plugins.PluginConfig;
|
||||
@@ -51,7 +46,7 @@ import javax.inject.Inject;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
class PluginManagerImpl implements PluginManager, Service, EventListener {
|
||||
class PluginManagerImpl implements PluginManager, Service {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(PluginManagerImpl.class.getName());
|
||||
@@ -59,9 +54,7 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
|
||||
private final Executor ioExecutor;
|
||||
private final EventBus eventBus;
|
||||
private final PluginConfig pluginConfig;
|
||||
private final Poller poller;
|
||||
private final ConnectionManager connectionManager;
|
||||
private final ConnectionRegistry connectionRegistry;
|
||||
private final SettingsManager settingsManager;
|
||||
private final TransportPropertyManager transportPropertyManager;
|
||||
private final UiCallback uiCallback;
|
||||
@@ -71,18 +64,14 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
|
||||
|
||||
@Inject
|
||||
PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus,
|
||||
PluginConfig pluginConfig, Poller poller,
|
||||
ConnectionManager connectionManager,
|
||||
ConnectionRegistry connectionRegistry,
|
||||
PluginConfig pluginConfig, ConnectionManager connectionManager,
|
||||
SettingsManager settingsManager,
|
||||
TransportPropertyManager transportPropertyManager,
|
||||
UiCallback uiCallback) {
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.eventBus = eventBus;
|
||||
this.pluginConfig = pluginConfig;
|
||||
this.poller = poller;
|
||||
this.connectionManager = connectionManager;
|
||||
this.connectionRegistry = connectionRegistry;
|
||||
this.settingsManager = settingsManager;
|
||||
this.transportPropertyManager = transportPropertyManager;
|
||||
this.uiCallback = uiCallback;
|
||||
@@ -93,36 +82,55 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
|
||||
|
||||
@Override
|
||||
public void startService() throws ServiceException {
|
||||
Collection<SimplexPluginFactory> simplexFactories =
|
||||
pluginConfig.getSimplexFactories();
|
||||
Collection<DuplexPluginFactory> duplexFactories =
|
||||
pluginConfig.getDuplexFactories();
|
||||
int numPlugins = simplexFactories.size() + duplexFactories.size();
|
||||
CountDownLatch latch = new CountDownLatch(numPlugins);
|
||||
// Instantiate and start the simplex plugins
|
||||
LOG.info("Starting simplex plugins");
|
||||
Collection<SimplexPluginFactory> sFactories =
|
||||
pluginConfig.getSimplexFactories();
|
||||
final CountDownLatch sLatch = new CountDownLatch(sFactories.size());
|
||||
for (SimplexPluginFactory factory : sFactories)
|
||||
ioExecutor.execute(new SimplexPluginStarter(factory, sLatch));
|
||||
for (SimplexPluginFactory f : simplexFactories) {
|
||||
TransportId t = f.getId();
|
||||
SimplexPluginCallback c = new SimplexCallback(t);
|
||||
SimplexPlugin s = f.createPlugin(c);
|
||||
if (s == null) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.warning("Could not create plugin for " + t);
|
||||
latch.countDown();
|
||||
} else {
|
||||
plugins.put(t, s);
|
||||
simplexPlugins.add(s);
|
||||
ioExecutor.execute(new PluginStarter(s, latch));
|
||||
}
|
||||
}
|
||||
// Instantiate and start the duplex plugins
|
||||
LOG.info("Starting duplex plugins");
|
||||
Collection<DuplexPluginFactory> dFactories =
|
||||
pluginConfig.getDuplexFactories();
|
||||
final CountDownLatch dLatch = new CountDownLatch(dFactories.size());
|
||||
for (DuplexPluginFactory factory : dFactories)
|
||||
ioExecutor.execute(new DuplexPluginStarter(factory, dLatch));
|
||||
// Wait for the plugins to start
|
||||
for (DuplexPluginFactory f : duplexFactories) {
|
||||
TransportId t = f.getId();
|
||||
DuplexPluginCallback c = new DuplexCallback(t);
|
||||
DuplexPlugin d = f.createPlugin(c);
|
||||
if (d == null) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.warning("Could not create plugin for " + t);
|
||||
latch.countDown();
|
||||
} else {
|
||||
plugins.put(t, d);
|
||||
duplexPlugins.add(d);
|
||||
ioExecutor.execute(new PluginStarter(d, latch));
|
||||
}
|
||||
}
|
||||
// Wait for all the plugins to start
|
||||
try {
|
||||
sLatch.await();
|
||||
dLatch.await();
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
throw new ServiceException(e);
|
||||
}
|
||||
// Listen for events
|
||||
eventBus.addListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopService() throws ServiceException {
|
||||
// Stop listening for events
|
||||
eventBus.removeListener(this);
|
||||
final CountDownLatch latch = new CountDownLatch(plugins.size());
|
||||
CountDownLatch latch = new CountDownLatch(plugins.size());
|
||||
// Stop the simplex plugins
|
||||
LOG.info("Stopping simplex plugins");
|
||||
for (SimplexPlugin plugin : simplexPlugins)
|
||||
@@ -144,6 +152,18 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
|
||||
return plugins.get(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SimplexPlugin> getSimplexPlugins() {
|
||||
List<SimplexPlugin> copy = new ArrayList<SimplexPlugin>(simplexPlugins);
|
||||
return Collections.unmodifiableList(copy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<DuplexPlugin> getDuplexPlugins() {
|
||||
List<DuplexPlugin> copy = new ArrayList<DuplexPlugin>(duplexPlugins);
|
||||
return Collections.unmodifiableList(copy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<DuplexPlugin> getInvitationPlugins() {
|
||||
List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>();
|
||||
@@ -160,149 +180,24 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
|
||||
return Collections.unmodifiableList(supported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof ContactStatusChangedEvent) {
|
||||
ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
|
||||
if (c.isActive()) {
|
||||
// Connect to the newly activated contact
|
||||
connectToContact(c.getContactId());
|
||||
}
|
||||
} else if (e instanceof ConnectionClosedEvent) {
|
||||
ConnectionClosedEvent c = (ConnectionClosedEvent) e;
|
||||
if (!c.isIncoming()) {
|
||||
// Connect to the disconnected contact
|
||||
connectToContact(c.getContactId(), c.getTransportId());
|
||||
}
|
||||
}
|
||||
}
|
||||
private class PluginStarter implements Runnable {
|
||||
|
||||
private void connectToContact(ContactId c) {
|
||||
for (SimplexPlugin s : simplexPlugins)
|
||||
if (s.shouldPoll()) connectToContact(c, s);
|
||||
for (DuplexPlugin d : duplexPlugins)
|
||||
if (d.shouldPoll()) connectToContact(c, d);
|
||||
}
|
||||
|
||||
private void connectToContact(ContactId c, TransportId t) {
|
||||
Plugin p = plugins.get(t);
|
||||
if (p instanceof SimplexPlugin && p.shouldPoll())
|
||||
connectToContact(c, (SimplexPlugin) p);
|
||||
else if (p instanceof DuplexPlugin && p.shouldPoll())
|
||||
connectToContact(c, (DuplexPlugin) p);
|
||||
}
|
||||
|
||||
private void connectToContact(final ContactId c, final SimplexPlugin p) {
|
||||
ioExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
TransportId t = p.getId();
|
||||
if (!connectionRegistry.isConnected(c, t)) {
|
||||
TransportConnectionWriter w = p.createWriter(c);
|
||||
if (w != null)
|
||||
connectionManager.manageOutgoingConnection(c, t, w);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void connectToContact(final ContactId c, final DuplexPlugin p) {
|
||||
ioExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
TransportId t = p.getId();
|
||||
if (!connectionRegistry.isConnected(c, t)) {
|
||||
DuplexTransportConnection d = p.createConnection(c);
|
||||
if (d != null)
|
||||
connectionManager.manageOutgoingConnection(c, t, d);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class SimplexPluginStarter implements Runnable {
|
||||
|
||||
private final SimplexPluginFactory factory;
|
||||
private final Plugin plugin;
|
||||
private final CountDownLatch latch;
|
||||
|
||||
private SimplexPluginStarter(SimplexPluginFactory factory,
|
||||
CountDownLatch latch) {
|
||||
this.factory = factory;
|
||||
private PluginStarter(Plugin plugin, CountDownLatch latch) {
|
||||
this.plugin = plugin;
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
TransportId id = factory.getId();
|
||||
SimplexCallback callback = new SimplexCallback(id);
|
||||
SimplexPlugin plugin = factory.createPlugin(callback);
|
||||
if (plugin == null) {
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
String name = factory.getClass().getSimpleName();
|
||||
LOG.info(name + " did not create a plugin");
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
long start = System.currentTimeMillis();
|
||||
boolean started = plugin.start();
|
||||
long duration = System.currentTimeMillis() - start;
|
||||
if (started) {
|
||||
plugins.put(id, plugin);
|
||||
simplexPlugins.add(plugin);
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
String name = plugin.getClass().getSimpleName();
|
||||
LOG.info("Starting " + name + " took " +
|
||||
duration + " ms");
|
||||
}
|
||||
} else {
|
||||
if (LOG.isLoggable(WARNING)) {
|
||||
String name = plugin.getClass().getSimpleName();
|
||||
LOG.warning(name + " did not start");
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DuplexPluginStarter implements Runnable {
|
||||
|
||||
private final DuplexPluginFactory factory;
|
||||
private final CountDownLatch latch;
|
||||
|
||||
private DuplexPluginStarter(DuplexPluginFactory factory,
|
||||
CountDownLatch latch) {
|
||||
this.factory = factory;
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
TransportId id = factory.getId();
|
||||
DuplexCallback callback = new DuplexCallback(id);
|
||||
DuplexPlugin plugin = factory.createPlugin(callback);
|
||||
if (plugin == null) {
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
String name = factory.getClass().getSimpleName();
|
||||
LOG.info(name + " did not create a plugin");
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
long start = System.currentTimeMillis();
|
||||
boolean started = plugin.start();
|
||||
long duration = System.currentTimeMillis() - start;
|
||||
if (started) {
|
||||
plugins.put(id, plugin);
|
||||
duplexPlugins.add(plugin);
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
String name = plugin.getClass().getSimpleName();
|
||||
LOG.info("Starting " + name + " took " +
|
||||
@@ -428,8 +323,6 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
|
||||
@Override
|
||||
public void transportEnabled() {
|
||||
eventBus.broadcast(new TransportEnabledEvent(id));
|
||||
Plugin p = plugins.get(id);
|
||||
if (p != null && p.shouldPoll()) poller.pollNow(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,6 +26,8 @@ public class PluginsModule {
|
||||
public static class EagerSingletons {
|
||||
@Inject
|
||||
PluginManager pluginManager;
|
||||
@Inject
|
||||
Poller poller;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -35,7 +37,8 @@ public class PluginsModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Poller providePoller(PollerImpl poller) {
|
||||
Poller providePoller(EventBus eventBus, PollerImpl poller) {
|
||||
eventBus.addListener(poller);
|
||||
return poller;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package org.briarproject.plugins;
|
||||
|
||||
import org.briarproject.api.plugins.Plugin;
|
||||
|
||||
interface Poller {
|
||||
|
||||
/** Tells the poller to poll the given plugin immediately. */
|
||||
void pollNow(Plugin p);
|
||||
// TODO: Remove this interface
|
||||
}
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
package org.briarproject.plugins;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.event.ConnectionClosedEvent;
|
||||
import org.briarproject.api.event.ContactStatusChangedEvent;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.TransportEnabledEvent;
|
||||
import org.briarproject.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.api.plugins.ConnectionManager;
|
||||
import org.briarproject.api.plugins.ConnectionRegistry;
|
||||
import org.briarproject.api.plugins.Plugin;
|
||||
import org.briarproject.api.plugins.PluginManager;
|
||||
import org.briarproject.api.plugins.TransportConnectionWriter;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Map;
|
||||
@@ -17,30 +29,100 @@ import javax.inject.Inject;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.logging.Level.INFO;
|
||||
|
||||
class PollerImpl implements Poller {
|
||||
class PollerImpl implements Poller, EventListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(PollerImpl.class.getName());
|
||||
|
||||
private final Executor ioExecutor;
|
||||
private final ScheduledExecutorService scheduler;
|
||||
private final ConnectionManager connectionManager;
|
||||
private final ConnectionRegistry connectionRegistry;
|
||||
private final PluginManager pluginManager;
|
||||
private final SecureRandom random;
|
||||
private final Map<TransportId, PollTask> tasks;
|
||||
|
||||
@Inject
|
||||
PollerImpl(@IoExecutor Executor ioExecutor,
|
||||
ScheduledExecutorService scheduler,
|
||||
ConnectionRegistry connectionRegistry, SecureRandom random) {
|
||||
ConnectionManager connectionManager,
|
||||
ConnectionRegistry connectionRegistry, PluginManager pluginManager,
|
||||
SecureRandom random) {
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.connectionManager = connectionManager;
|
||||
this.connectionRegistry = connectionRegistry;
|
||||
this.pluginManager = pluginManager;
|
||||
this.random = random;
|
||||
this.scheduler = scheduler;
|
||||
tasks = new ConcurrentHashMap<TransportId, PollTask>();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void pollNow(Plugin p) {
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof ContactStatusChangedEvent) {
|
||||
ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
|
||||
if (c.isActive()) {
|
||||
// Connect to the newly activated contact
|
||||
connectToContact(c.getContactId());
|
||||
}
|
||||
} else if (e instanceof ConnectionClosedEvent) {
|
||||
ConnectionClosedEvent c = (ConnectionClosedEvent) e;
|
||||
if (!c.isIncoming()) {
|
||||
// Connect to the disconnected contact
|
||||
connectToContact(c.getContactId(), c.getTransportId());
|
||||
}
|
||||
} else if (e instanceof TransportEnabledEvent) {
|
||||
TransportEnabledEvent t = (TransportEnabledEvent) e;
|
||||
Plugin p = pluginManager.getPlugin(t.getTransportId());
|
||||
if (p.shouldPoll()) pollNow(p);
|
||||
}
|
||||
}
|
||||
|
||||
private void connectToContact(ContactId c) {
|
||||
for (SimplexPlugin s : pluginManager.getSimplexPlugins())
|
||||
if (s.shouldPoll()) connectToContact(c, s);
|
||||
for (DuplexPlugin d : pluginManager.getDuplexPlugins())
|
||||
if (d.shouldPoll()) connectToContact(c, d);
|
||||
}
|
||||
|
||||
private void connectToContact(ContactId c, TransportId t) {
|
||||
Plugin p = pluginManager.getPlugin(t);
|
||||
if (p instanceof SimplexPlugin && p.shouldPoll())
|
||||
connectToContact(c, (SimplexPlugin) p);
|
||||
else if (p instanceof DuplexPlugin && p.shouldPoll())
|
||||
connectToContact(c, (DuplexPlugin) p);
|
||||
}
|
||||
|
||||
private void connectToContact(final ContactId c, final SimplexPlugin p) {
|
||||
ioExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
TransportId t = p.getId();
|
||||
if (!connectionRegistry.isConnected(c, t)) {
|
||||
TransportConnectionWriter w = p.createWriter(c);
|
||||
if (w != null)
|
||||
connectionManager.manageOutgoingConnection(c, t, w);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void connectToContact(final ContactId c, final DuplexPlugin p) {
|
||||
ioExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
TransportId t = p.getId();
|
||||
if (!connectionRegistry.isConnected(c, t)) {
|
||||
DuplexTransportConnection d = p.createConnection(c);
|
||||
if (d != null)
|
||||
connectionManager.manageOutgoingConnection(c, t, d);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void pollNow(Plugin p) {
|
||||
// Randomise next polling interval
|
||||
schedule(p, 0, true);
|
||||
}
|
||||
|
||||
20
briar-tests/src/org/briarproject/RunAction.java
Normal file
20
briar-tests/src/org/briarproject/RunAction.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package org.briarproject;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.jmock.api.Action;
|
||||
import org.jmock.api.Invocation;
|
||||
|
||||
public class RunAction implements Action {
|
||||
|
||||
@Override
|
||||
public Object invoke(Invocation invocation) throws Throwable {
|
||||
Runnable task = (Runnable) invocation.getParameter(0);
|
||||
task.run();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("runs a runnable");
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,13 @@
|
||||
package org.briarproject.plugins;
|
||||
|
||||
import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.ImmediateExecutor;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.event.ContactStatusChangedEvent;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.plugins.ConnectionManager;
|
||||
import org.briarproject.api.plugins.ConnectionRegistry;
|
||||
import org.briarproject.api.plugins.PluginConfig;
|
||||
import org.briarproject.api.plugins.TransportConnectionWriter;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginFactory;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||
import org.briarproject.api.plugins.simplex.SimplexPluginCallback;
|
||||
import org.briarproject.api.plugins.simplex.SimplexPluginFactory;
|
||||
@@ -40,11 +33,8 @@ public class PluginManagerImplTest extends BriarTestCase {
|
||||
final Executor ioExecutor = Executors.newSingleThreadExecutor();
|
||||
final EventBus eventBus = context.mock(EventBus.class);
|
||||
final PluginConfig pluginConfig = context.mock(PluginConfig.class);
|
||||
final Poller poller = context.mock(Poller.class);
|
||||
final ConnectionManager connectionManager =
|
||||
context.mock(ConnectionManager.class);
|
||||
final ConnectionRegistry connectionRegistry =
|
||||
context.mock(ConnectionRegistry.class);
|
||||
final SettingsManager settingsManager =
|
||||
context.mock(SettingsManager.class);
|
||||
final TransportPropertyManager transportPropertyManager =
|
||||
@@ -108,19 +98,16 @@ public class PluginManagerImplTest extends BriarTestCase {
|
||||
oneOf(duplexFailFactory).createPlugin(with(any(
|
||||
DuplexPluginCallback.class)));
|
||||
will(returnValue(null)); // Failed to create a plugin
|
||||
// Start listening for events
|
||||
oneOf(eventBus).addListener(with(any(EventListener.class)));
|
||||
// stop()
|
||||
// Stop listening for events
|
||||
oneOf(eventBus).removeListener(with(any(EventListener.class)));
|
||||
// Stop the plugins
|
||||
oneOf(simplexPlugin).stop();
|
||||
oneOf(simplexFailPlugin).stop();
|
||||
oneOf(duplexPlugin).stop();
|
||||
}});
|
||||
|
||||
PluginManagerImpl p = new PluginManagerImpl(ioExecutor, eventBus,
|
||||
pluginConfig, poller, connectionManager, connectionRegistry,
|
||||
settingsManager, transportPropertyManager, uiCallback);
|
||||
pluginConfig, connectionManager, settingsManager,
|
||||
transportPropertyManager, uiCallback);
|
||||
|
||||
// Two plugins should be started and stopped
|
||||
p.startService();
|
||||
@@ -128,139 +115,4 @@ public class PluginManagerImplTest extends BriarTestCase {
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectToNewContact() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
final Executor ioExecutor = new ImmediateExecutor();
|
||||
final EventBus eventBus = context.mock(EventBus.class);
|
||||
final PluginConfig pluginConfig = context.mock(PluginConfig.class);
|
||||
final Poller poller = context.mock(Poller.class);
|
||||
final ConnectionManager connectionManager =
|
||||
context.mock(ConnectionManager.class);
|
||||
final ConnectionRegistry connectionRegistry =
|
||||
context.mock(ConnectionRegistry.class);
|
||||
final SettingsManager settingsManager =
|
||||
context.mock(SettingsManager.class);
|
||||
final TransportPropertyManager transportPropertyManager =
|
||||
context.mock(TransportPropertyManager.class);
|
||||
final UiCallback uiCallback = context.mock(UiCallback.class);
|
||||
final TransportConnectionWriter transportConnectionWriter =
|
||||
context.mock(TransportConnectionWriter.class);
|
||||
final DuplexTransportConnection duplexTransportConnection =
|
||||
context.mock(DuplexTransportConnection.class);
|
||||
|
||||
final ContactId contactId = new ContactId(234);
|
||||
|
||||
// Two simplex plugins: one supports polling, the other doesn't
|
||||
final SimplexPluginFactory simplexFactory =
|
||||
context.mock(SimplexPluginFactory.class);
|
||||
final SimplexPlugin simplexPlugin = context.mock(SimplexPlugin.class);
|
||||
final TransportId simplexId = new TransportId("simplex");
|
||||
final SimplexPluginFactory simplexFactory1 =
|
||||
context.mock(SimplexPluginFactory.class, "simplexFactory1");
|
||||
final SimplexPlugin simplexPlugin1 =
|
||||
context.mock(SimplexPlugin.class, "simplexPlugin1");
|
||||
final TransportId simplexId1 = new TransportId("simplex1");
|
||||
|
||||
// Two duplex plugins: one supports polling, the other doesn't
|
||||
final DuplexPluginFactory duplexFactory =
|
||||
context.mock(DuplexPluginFactory.class);
|
||||
final DuplexPlugin duplexPlugin = context.mock(DuplexPlugin.class);
|
||||
final TransportId duplexId = new TransportId("duplex");
|
||||
final DuplexPluginFactory duplexFactory1 =
|
||||
context.mock(DuplexPluginFactory.class, "duplexFactory1");
|
||||
final DuplexPlugin duplexPlugin1 =
|
||||
context.mock(DuplexPlugin.class, "duplexPlugin1");
|
||||
final TransportId duplexId1 = new TransportId("duplex1");
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
// start()
|
||||
// First simplex plugin
|
||||
oneOf(pluginConfig).getSimplexFactories();
|
||||
will(returnValue(Arrays.asList(simplexFactory, simplexFactory1)));
|
||||
oneOf(simplexFactory).getId();
|
||||
will(returnValue(simplexId));
|
||||
oneOf(simplexFactory).createPlugin(with(any(
|
||||
SimplexPluginCallback.class)));
|
||||
will(returnValue(simplexPlugin)); // Created
|
||||
oneOf(simplexPlugin).start();
|
||||
will(returnValue(true)); // Started
|
||||
// Second simplex plugin
|
||||
oneOf(simplexFactory1).getId();
|
||||
will(returnValue(simplexId1));
|
||||
oneOf(simplexFactory1).createPlugin(with(any(
|
||||
SimplexPluginCallback.class)));
|
||||
will(returnValue(simplexPlugin1)); // Created
|
||||
oneOf(simplexPlugin1).start();
|
||||
will(returnValue(true)); // Started
|
||||
// First duplex plugin
|
||||
oneOf(pluginConfig).getDuplexFactories();
|
||||
will(returnValue(Arrays.asList(duplexFactory, duplexFactory1)));
|
||||
oneOf(duplexFactory).getId();
|
||||
will(returnValue(duplexId));
|
||||
oneOf(duplexFactory).createPlugin(with(any(
|
||||
DuplexPluginCallback.class)));
|
||||
will(returnValue(duplexPlugin)); // Created
|
||||
oneOf(duplexPlugin).start();
|
||||
will(returnValue(true)); // Started
|
||||
// Second duplex plugin
|
||||
oneOf(duplexFactory1).getId();
|
||||
will(returnValue(duplexId1));
|
||||
oneOf(duplexFactory1).createPlugin(with(any(
|
||||
DuplexPluginCallback.class)));
|
||||
will(returnValue(duplexPlugin1)); // Created
|
||||
oneOf(duplexPlugin1).start();
|
||||
will(returnValue(true)); // Started
|
||||
// Start listening for events
|
||||
oneOf(eventBus).addListener(with(any(EventListener.class)));
|
||||
// eventOccurred()
|
||||
// First simplex plugin
|
||||
oneOf(simplexPlugin).shouldPoll();
|
||||
will(returnValue(true));
|
||||
oneOf(simplexPlugin).getId();
|
||||
will(returnValue(simplexId));
|
||||
oneOf(connectionRegistry).isConnected(contactId, simplexId);
|
||||
will(returnValue(false));
|
||||
oneOf(simplexPlugin).createWriter(contactId);
|
||||
will(returnValue(transportConnectionWriter));
|
||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||
simplexId, transportConnectionWriter);
|
||||
// Second simplex plugin
|
||||
oneOf(simplexPlugin1).shouldPoll();
|
||||
will(returnValue(false));
|
||||
// First duplex plugin
|
||||
oneOf(duplexPlugin).shouldPoll();
|
||||
will(returnValue(true));
|
||||
oneOf(duplexPlugin).getId();
|
||||
will(returnValue(duplexId));
|
||||
oneOf(connectionRegistry).isConnected(contactId, duplexId);
|
||||
will(returnValue(false));
|
||||
oneOf(duplexPlugin).createConnection(contactId);
|
||||
will(returnValue(duplexTransportConnection));
|
||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||
duplexId, duplexTransportConnection);
|
||||
// Second duplex plugin
|
||||
oneOf(duplexPlugin1).shouldPoll();
|
||||
will(returnValue(false));
|
||||
// stop()
|
||||
// Stop listening for events
|
||||
oneOf(eventBus).removeListener(with(any(EventListener.class)));
|
||||
// Stop the plugins
|
||||
oneOf(simplexPlugin).stop();
|
||||
oneOf(simplexPlugin1).stop();
|
||||
oneOf(duplexPlugin).stop();
|
||||
oneOf(duplexPlugin1).stop();
|
||||
}});
|
||||
|
||||
PluginManagerImpl p = new PluginManagerImpl(ioExecutor, eventBus,
|
||||
pluginConfig, poller, connectionManager, connectionRegistry,
|
||||
settingsManager, transportPropertyManager, uiCallback);
|
||||
|
||||
p.startService();
|
||||
p.eventOccurred(new ContactStatusChangedEvent(contactId, true));
|
||||
p.stopService();
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
}
|
||||
|
||||
222
briar-tests/src/org/briarproject/plugins/PollerImplTest.java
Normal file
222
briar-tests/src/org/briarproject/plugins/PollerImplTest.java
Normal file
@@ -0,0 +1,222 @@
|
||||
package org.briarproject.plugins;
|
||||
|
||||
import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.ImmediateExecutor;
|
||||
import org.briarproject.RunAction;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.event.ConnectionClosedEvent;
|
||||
import org.briarproject.api.event.ContactStatusChangedEvent;
|
||||
import org.briarproject.api.event.TransportEnabledEvent;
|
||||
import org.briarproject.api.plugins.ConnectionManager;
|
||||
import org.briarproject.api.plugins.ConnectionRegistry;
|
||||
import org.briarproject.api.plugins.Plugin;
|
||||
import org.briarproject.api.plugins.PluginManager;
|
||||
import org.briarproject.api.plugins.TransportConnectionWriter;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.jmock.lib.legacy.ClassImposteriser;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
public class PollerImplTest extends BriarTestCase {
|
||||
|
||||
private final ContactId contactId = new ContactId(234);
|
||||
|
||||
@Test
|
||||
public void testConnectToNewContact() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
context.setImposteriser(ClassImposteriser.INSTANCE);
|
||||
final Executor ioExecutor = new ImmediateExecutor();
|
||||
final ScheduledExecutorService scheduler =
|
||||
context.mock(ScheduledExecutorService.class);
|
||||
final ConnectionManager connectionManager =
|
||||
context.mock(ConnectionManager.class);
|
||||
final ConnectionRegistry connectionRegistry =
|
||||
context.mock(ConnectionRegistry.class);
|
||||
final PluginManager pluginManager = context.mock(PluginManager.class);
|
||||
final SecureRandom random = context.mock(SecureRandom.class);
|
||||
|
||||
// Two simplex plugins: one supports polling, the other doesn't
|
||||
final SimplexPlugin simplexPlugin = context.mock(SimplexPlugin.class);
|
||||
final SimplexPlugin simplexPlugin1 =
|
||||
context.mock(SimplexPlugin.class, "simplexPlugin1");
|
||||
final TransportId simplexId1 = new TransportId("simplex1");
|
||||
final List<SimplexPlugin> simplexPlugins = Arrays.asList(simplexPlugin,
|
||||
simplexPlugin1);
|
||||
final TransportConnectionWriter simplexWriter =
|
||||
context.mock(TransportConnectionWriter.class);
|
||||
|
||||
// Two duplex plugins: one supports polling, the other doesn't
|
||||
final DuplexPlugin duplexPlugin = context.mock(DuplexPlugin.class);
|
||||
final TransportId duplexId = new TransportId("duplex");
|
||||
final DuplexPlugin duplexPlugin1 =
|
||||
context.mock(DuplexPlugin.class, "duplexPlugin1");
|
||||
final List<DuplexPlugin> duplexPlugins = Arrays.asList(duplexPlugin,
|
||||
duplexPlugin1);
|
||||
final DuplexTransportConnection duplexConnection =
|
||||
context.mock(DuplexTransportConnection.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
// Get the simplex plugins
|
||||
oneOf(pluginManager).getSimplexPlugins();
|
||||
will(returnValue(simplexPlugins));
|
||||
// The first plugin doesn't support polling
|
||||
oneOf(simplexPlugin).shouldPoll();
|
||||
will(returnValue(false));
|
||||
// The second plugin supports polling
|
||||
oneOf(simplexPlugin1).shouldPoll();
|
||||
will(returnValue(true));
|
||||
// Check whether the contact is already connected
|
||||
oneOf(simplexPlugin1).getId();
|
||||
will(returnValue(simplexId1));
|
||||
oneOf(connectionRegistry).isConnected(contactId, simplexId1);
|
||||
will(returnValue(false));
|
||||
// Connect to the contact
|
||||
oneOf(simplexPlugin1).createWriter(contactId);
|
||||
will(returnValue(simplexWriter));
|
||||
// Pass the connection to the connection manager
|
||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||
simplexId1, simplexWriter);
|
||||
// Get the duplex plugins
|
||||
oneOf(pluginManager).getDuplexPlugins();
|
||||
will(returnValue(duplexPlugins));
|
||||
// The first plugin supports polling
|
||||
oneOf(duplexPlugin).shouldPoll();
|
||||
will(returnValue(true));
|
||||
// Check whether the contact is already connected
|
||||
oneOf(duplexPlugin).getId();
|
||||
will(returnValue(duplexId));
|
||||
oneOf(connectionRegistry).isConnected(contactId, duplexId);
|
||||
will(returnValue(false));
|
||||
// Connect to the contact
|
||||
oneOf(duplexPlugin).createConnection(contactId);
|
||||
will(returnValue(duplexConnection));
|
||||
// Pass the connection to the connection manager
|
||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||
duplexId, duplexConnection);
|
||||
// The second plugin doesn't support polling
|
||||
oneOf(duplexPlugin1).shouldPoll();
|
||||
will(returnValue(false));
|
||||
}});
|
||||
|
||||
PollerImpl p = new PollerImpl(ioExecutor, scheduler, connectionManager,
|
||||
connectionRegistry, pluginManager, random);
|
||||
|
||||
p.eventOccurred(new ContactStatusChangedEvent(contactId, true));
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReconnectToDisconnectedContact() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
context.setImposteriser(ClassImposteriser.INSTANCE);
|
||||
final Executor ioExecutor = new ImmediateExecutor();
|
||||
final ScheduledExecutorService scheduler =
|
||||
context.mock(ScheduledExecutorService.class);
|
||||
final ConnectionManager connectionManager =
|
||||
context.mock(ConnectionManager.class);
|
||||
final ConnectionRegistry connectionRegistry =
|
||||
context.mock(ConnectionRegistry.class);
|
||||
final PluginManager pluginManager = context.mock(PluginManager.class);
|
||||
final SecureRandom random = context.mock(SecureRandom.class);
|
||||
|
||||
final DuplexPlugin plugin = context.mock(DuplexPlugin.class);
|
||||
final TransportId transportId = new TransportId("id");
|
||||
final DuplexTransportConnection duplexConnection =
|
||||
context.mock(DuplexTransportConnection.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
// Get the plugin
|
||||
oneOf(pluginManager).getPlugin(transportId);
|
||||
will(returnValue(plugin));
|
||||
// The plugin supports polling
|
||||
oneOf(plugin).shouldPoll();
|
||||
will(returnValue(true));
|
||||
// Check whether the contact is already connected
|
||||
oneOf(plugin).getId();
|
||||
will(returnValue(transportId));
|
||||
oneOf(connectionRegistry).isConnected(contactId, transportId);
|
||||
will(returnValue(false));
|
||||
// Connect to the contact
|
||||
oneOf(plugin).createConnection(contactId);
|
||||
will(returnValue(duplexConnection));
|
||||
// Pass the connection to the connection manager
|
||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||
transportId, duplexConnection);
|
||||
}});
|
||||
|
||||
PollerImpl p = new PollerImpl(ioExecutor, scheduler, connectionManager,
|
||||
connectionRegistry, pluginManager, random);
|
||||
|
||||
p.eventOccurred(new ConnectionClosedEvent(contactId, transportId,
|
||||
false));
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPollWhenTransportIsEnabled() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
context.setImposteriser(ClassImposteriser.INSTANCE);
|
||||
final Executor ioExecutor = new ImmediateExecutor();
|
||||
final ScheduledExecutorService scheduler =
|
||||
context.mock(ScheduledExecutorService.class);
|
||||
final ConnectionManager connectionManager =
|
||||
context.mock(ConnectionManager.class);
|
||||
final ConnectionRegistry connectionRegistry =
|
||||
context.mock(ConnectionRegistry.class);
|
||||
final PluginManager pluginManager = context.mock(PluginManager.class);
|
||||
final SecureRandom random = context.mock(SecureRandom.class);
|
||||
|
||||
final Plugin plugin = context.mock(Plugin.class);
|
||||
final TransportId transportId = new TransportId("id");
|
||||
final int pollingInterval = 60 * 1000;
|
||||
final List<ContactId> connected = Collections.singletonList(contactId);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
allowing(plugin).getId();
|
||||
will(returnValue(transportId));
|
||||
// Get the plugin
|
||||
oneOf(pluginManager).getPlugin(transportId);
|
||||
will(returnValue(plugin));
|
||||
// The plugin supports polling
|
||||
oneOf(plugin).shouldPoll();
|
||||
will(returnValue(true));
|
||||
// Schedule a polling task immediately
|
||||
oneOf(scheduler).schedule(with(any(Runnable.class)), with(0L),
|
||||
with(MILLISECONDS));
|
||||
will(new RunAction());
|
||||
// Run the polling task
|
||||
oneOf(plugin).getPollingInterval();
|
||||
will(returnValue(pollingInterval));
|
||||
oneOf(random).nextDouble();
|
||||
will(returnValue(0.5));
|
||||
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||
with((long) (pollingInterval * 0.5)), with(MILLISECONDS));
|
||||
// Poll the plugin
|
||||
oneOf(connectionRegistry).getConnectedContacts(transportId);
|
||||
will(returnValue(connected));
|
||||
oneOf(plugin).poll(connected);
|
||||
}});
|
||||
|
||||
PollerImpl p = new PollerImpl(ioExecutor, scheduler, connectionManager,
|
||||
connectionRegistry, pluginManager, random);
|
||||
|
||||
p.eventOccurred(new TransportEnabledEvent(transportId));
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.briarproject.transport;
|
||||
|
||||
import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.RunAction;
|
||||
import org.briarproject.TestUtils;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
@@ -501,19 +502,4 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
||||
description.appendText("encodes a tag");
|
||||
}
|
||||
}
|
||||
|
||||
private static class RunAction implements Action {
|
||||
|
||||
@Override
|
||||
public Object invoke(Invocation invocation) throws Throwable {
|
||||
Runnable task = (Runnable) invocation.getParameter(0);
|
||||
task.run();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("runs a runnable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user