Broadcast events asynchronously.

This commit is contained in:
akwizgran
2018-11-07 13:26:00 +00:00
parent 8b3164e107
commit c3b5b04b71
15 changed files with 104 additions and 8 deletions

View File

@@ -1,10 +1,13 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.SecureRandomProvider;
import java.util.concurrent.Executor;
import javax.inject.Singleton;
import dagger.Module;
@@ -32,6 +35,13 @@ public class AndroidSystemModule {
return androidExecutor;
}
@Provides
@Singleton
@EventExecutor
Executor provideEventExecutor(AndroidExecutor androidExecutor) {
return androidExecutor::runOnUiThread;
}
@Provides
@Singleton
ResourceProvider provideResourceProvider(AndroidResourceProvider provider) {

View File

@@ -16,7 +16,8 @@ public interface EventBus {
void removeListener(EventListener l);
/**
* Notifies all listeners of an event.
* Asynchronously notifies all listeners of an event. Listeners are
* notified on the {@link EventExecutor}.
*/
void broadcast(Event e);
}

View File

@@ -0,0 +1,25 @@
package org.briarproject.bramble.api.event;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for injecting the executor for broadcasting events. Also used for
* annotating methods that should run on the event executor.
* <p>
* The contract of this executor is that tasks are run in the order they're
* submitted, tasks are not run concurrently, and submitting a task will never
* block. Tasks must not block. Tasks submitted during shutdown are discarded.
*/
@Qualifier
@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
public @interface EventExecutor {
}

View File

@@ -12,5 +12,6 @@ public interface EventListener {
* Called when an event is broadcast. Implementations of this method must
* not block.
*/
@EventExecutor
void eventOccurred(Event e);
}

View File

@@ -160,13 +160,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
public void endTransaction(Transaction transaction) {
try {
T txn = txnClass.cast(transaction.unbox());
if (!transaction.isCommitted()) db.abortTransaction(txn);
if (transaction.isCommitted()) {
for (Event e : transaction.getEvents()) eventBus.broadcast(e);
} else {
db.abortTransaction(txn);
}
} finally {
if (transaction.isReadOnly()) lock.readLock().unlock();
else lock.writeLock().unlock();
}
if (transaction.isCommitted())
for (Event e : transaction.getEvents()) eventBus.broadcast(e);
}
@Override

View File

@@ -0,0 +1,32 @@
package org.briarproject.bramble.event;
import org.briarproject.bramble.api.event.EventExecutor;
import java.util.concurrent.Executor;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
/**
* Default implementation of {@link EventExecutor} that uses a dedicated thread
* to notify listeners of events. Applications may prefer to supply an
* implementation that uses an existing thread, such as the UI thread.
*/
@Module
public class DefaultEventExecutorModule {
@Provides
@Singleton
@EventExecutor
Executor provideEventExecutor() {
return newSingleThreadExecutor(r -> {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
});
}
}

View File

@@ -7,6 +7,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import javax.annotation.concurrent.ThreadSafe;
@@ -16,6 +17,11 @@ class EventBusImpl implements EventBus {
private final Collection<EventListener> listeners =
new CopyOnWriteArrayList<>();
private final Executor eventExecutor;
EventBusImpl(Executor eventExecutor) {
this.eventExecutor = eventExecutor;
}
@Override
public void addListener(EventListener l) {
@@ -29,6 +35,8 @@ class EventBusImpl implements EventBus {
@Override
public void broadcast(Event e) {
for (EventListener l : listeners) l.eventOccurred(e);
eventExecutor.execute(() -> {
for (EventListener l : listeners) l.eventOccurred(e);
});
}
}

View File

@@ -1,6 +1,9 @@
package org.briarproject.bramble.event;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor;
import java.util.concurrent.Executor;
import javax.inject.Singleton;
@@ -12,7 +15,7 @@ public class EventModule {
@Provides
@Singleton
EventBus provideEventBus() {
return new EventBusImpl();
EventBus provideEventBus(@EventExecutor Executor eventExecutor) {
return new EventBusImpl(eventExecutor);
}
}

View File

@@ -2,6 +2,7 @@ package org.briarproject.bramble.test;
import org.briarproject.bramble.BrambleJavaModule;
import org.briarproject.bramble.battery.DefaultBatteryManagerModule;
import org.briarproject.bramble.event.DefaultEventExecutorModule;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.plugin.tor.BridgeTest;
@@ -17,8 +18,9 @@ import dagger.Component;
BrambleJavaModule.class,
TestLifecycleModule.class,
DefaultBatteryManagerModule.class,
PluginModule.class, // needed for BackoffFactory
DefaultEventExecutorModule.class,
EventModule.class,
PluginModule.class, // needed for BackoffFactory
SystemModule.class,
})
public interface BrambleJavaIntegrationTestComponent {

View File

@@ -8,6 +8,7 @@ import org.briarproject.bramble.crypto.CryptoExecutorModule;
import org.briarproject.bramble.crypto.CryptoModule;
import org.briarproject.bramble.data.DataModule;
import org.briarproject.bramble.db.DatabaseModule;
import org.briarproject.bramble.event.DefaultEventExecutorModule;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.identity.IdentityModule;
import org.briarproject.bramble.lifecycle.LifecycleModule;
@@ -46,6 +47,7 @@ import dagger.Component;
FeedModule.class,
DataModule.class,
DatabaseModule.class,
DefaultEventExecutorModule.class,
EventModule.class,
IdentityModule.class,
LifecycleModule.class,

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.crypto.CryptoExecutorModule;
import org.briarproject.bramble.crypto.CryptoModule;
import org.briarproject.bramble.data.DataModule;
import org.briarproject.bramble.db.DatabaseModule;
import org.briarproject.bramble.event.DefaultEventExecutorModule;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.identity.IdentityModule;
import org.briarproject.bramble.lifecycle.LifecycleModule;
@@ -45,6 +46,7 @@ import dagger.Component;
CryptoExecutorModule.class,
DataModule.class,
DatabaseModule.class,
DefaultEventExecutorModule.class,
EventModule.class,
ForumModule.class,
GroupInvitationModule.class,

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.crypto.CryptoExecutorModule;
import org.briarproject.bramble.crypto.CryptoModule;
import org.briarproject.bramble.data.DataModule;
import org.briarproject.bramble.db.DatabaseModule;
import org.briarproject.bramble.event.DefaultEventExecutorModule;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.identity.IdentityModule;
import org.briarproject.bramble.sync.SyncModule;
@@ -37,6 +38,7 @@ import dagger.Component;
CryptoExecutorModule.class,
DataModule.class,
DatabaseModule.class,
DefaultEventExecutorModule.class,
EventModule.class,
ForumModule.class,
IdentityModule.class,

View File

@@ -13,6 +13,7 @@ import org.briarproject.bramble.contact.ContactModule;
import org.briarproject.bramble.crypto.CryptoModule;
import org.briarproject.bramble.data.DataModule;
import org.briarproject.bramble.db.DatabaseModule;
import org.briarproject.bramble.event.DefaultEventExecutorModule;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.identity.IdentityModule;
import org.briarproject.bramble.lifecycle.LifecycleModule;
@@ -46,6 +47,7 @@ import dagger.Component;
CryptoModule.class,
DataModule.class,
DatabaseModule.class,
DefaultEventExecutorModule.class,
EventModule.class,
IdentityModule.class,
LifecycleModule.class,

View File

@@ -15,6 +15,7 @@ import org.briarproject.bramble.crypto.CryptoExecutorModule;
import org.briarproject.bramble.crypto.CryptoModule;
import org.briarproject.bramble.data.DataModule;
import org.briarproject.bramble.db.DatabaseModule;
import org.briarproject.bramble.event.DefaultEventExecutorModule;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.identity.IdentityModule;
import org.briarproject.bramble.lifecycle.LifecycleModule;
@@ -63,6 +64,7 @@ import dagger.Component;
CryptoExecutorModule.class,
DataModule.class,
DatabaseModule.class,
DefaultEventExecutorModule.class,
EventModule.class,
ForumModule.class,
GroupInvitationModule.class,

View File

@@ -21,6 +21,7 @@ import org.briarproject.bramble.api.system.Clock
import org.briarproject.bramble.api.system.LocationUtils
import org.briarproject.bramble.api.system.ResourceProvider
import org.briarproject.bramble.battery.DefaultBatteryManagerModule
import org.briarproject.bramble.event.DefaultEventExecutorModule
import org.briarproject.bramble.network.JavaNetworkModule
import org.briarproject.bramble.plugin.tor.CircumventionModule
import org.briarproject.bramble.plugin.tor.CircumventionProvider
@@ -47,6 +48,7 @@ import javax.net.SocketFactory
JavaSystemModule::class,
CircumventionModule::class,
DefaultBatteryManagerModule::class,
DefaultEventExecutorModule::class,
HeadlessBlogModule::class,
HeadlessContactModule::class,
HeadlessEventModule::class,