Compare commits

..

7 Commits

Author SHA1 Message Date
akwizgran
68738a5a03 Refactor layouts for alias and link dialogs. 2018-10-31 15:28:58 +00:00
Torsten Grote
1a025d0f40 [android] Show existing alias in alias edit text view
This commit also uses LiveData Transformations to expose contact related information
2018-10-30 08:36:10 -03:00
Torsten Grote
a3593ea8ca [android] Show contact alias inside private groups and their memberlist 2018-10-29 19:41:01 -03:00
Torsten Grote
34eaedbd63 Show alias for introduction notices in private conversation 2018-10-29 19:23:22 -03:00
Torsten Grote
44e1ce32ce [android] Show alias for creator of private group in list of private groups 2018-10-29 18:38:20 -03:00
Torsten Grote
7af4b3d3ca [android] Show Author alias in AuthorView 2018-10-29 18:18:05 -03:00
Torsten Grote
1423ca7a15 [android] Add UI for changing and displaying contact alias
Note that this commit only shows the alias where the Contact is
available. In cases, where we only have the Author, only its name is
shown.

This also introduces the first ViewModel to share state between the
ConversationActivity and the AliasDialogFragment.
2018-10-29 18:18:05 -03:00
235 changed files with 2649 additions and 2894 deletions

View File

@@ -3,7 +3,7 @@
<module name="briar-headless" /> <module name="briar-headless" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" /> <option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="org.briarproject.briar.headless" /> <option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" /> <option name="TEST_OBJECT" value="package" />

View File

@@ -1,5 +1,3 @@
import com.android.build.gradle.tasks.MergeResources
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
apply plugin: 'witness' apply plugin: 'witness'
apply from: 'witness.gradle' apply from: 'witness.gradle'
@@ -11,8 +9,8 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 26 targetSdkVersion 26
versionCode 10105 versionCode 10103
versionName "1.1.5" versionName "1.1.3"
consumerProguardFiles 'proguard-rules.txt' consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -31,9 +29,8 @@ configurations {
dependencies { dependencies {
implementation project(path: ':bramble-core', configuration: 'default') implementation project(path: ':bramble-core', configuration: 'default')
tor 'org.briarproject:tor-android:0.3.4.8@zip' tor 'org.briarproject:tor-android:0.3.4.8@zip'
tor 'org.briarproject:obfs4proxy-android:0.0.7@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.19' annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
compileOnly 'javax.annotation:jsr250-api:1.0' compileOnly 'javax.annotation:jsr250-api:1.0'
@@ -42,29 +39,13 @@ dependencies {
testImplementation "org.jmock:jmock:2.8.2" testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2" testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2" testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
} }
def torBinariesDir = 'src/main/res/raw' project.afterEvaluate {
copy {
task cleanTorBinaries { from configurations.tor.collect { zipTree(it) }
doLast { into 'src/main/res/raw'
delete fileTree(torBinariesDir) { include '*.zip' }
} }
} }
clean.dependsOn cleanTorBinaries
task unpackTorBinaries {
doLast {
copy {
from configurations.tor.collect { zipTree(it) }
into torBinariesDir
}
}
dependsOn cleanTorBinaries
}
tasks.withType(MergeResources) {
inputs.dir torBinariesDir
dependsOn unpackTorBinaries
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble; package org.briarproject.bramble;
import org.briarproject.bramble.battery.AndroidBatteryModule;
import org.briarproject.bramble.network.AndroidNetworkModule; import org.briarproject.bramble.network.AndroidNetworkModule;
import org.briarproject.bramble.plugin.tor.CircumventionModule; import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.system.AndroidSystemModule; import org.briarproject.bramble.system.AndroidSystemModule;
@@ -8,7 +7,6 @@ import org.briarproject.bramble.system.AndroidSystemModule;
import dagger.Module; import dagger.Module;
@Module(includes = { @Module(includes = {
AndroidBatteryModule.class,
AndroidNetworkModule.class, AndroidNetworkModule.class,
AndroidSystemModule.class, AndroidSystemModule.class,
CircumventionModule.class CircumventionModule.class

View File

@@ -1,84 +0,0 @@
package org.briarproject.bramble.battery;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.battery.event.BatteryEvent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.Service;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.inject.Inject;
import static android.content.Intent.ACTION_BATTERY_CHANGED;
import static android.content.Intent.ACTION_POWER_CONNECTED;
import static android.content.Intent.ACTION_POWER_DISCONNECTED;
import static android.os.BatteryManager.BATTERY_STATUS_CHARGING;
import static android.os.BatteryManager.BATTERY_STATUS_FULL;
import static android.os.BatteryManager.EXTRA_STATUS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
class AndroidBatteryManager implements BatteryManager, Service {
private static final Logger LOG =
getLogger(AndroidBatteryManager.class.getName());
private final Context appContext;
private final EventBus eventBus;
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile BroadcastReceiver batteryReceiver = null;
@Inject
AndroidBatteryManager(Application app, EventBus eventBus) {
this.appContext = app.getApplicationContext();
this.eventBus = eventBus;
}
@Override
public boolean isCharging() {
// Get the sticky intent for ACTION_BATTERY_CHANGED
IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
Intent i = appContext.registerReceiver(null, filter);
if (i == null) return false;
int status = i.getIntExtra(EXTRA_STATUS, -1);
return status == BATTERY_STATUS_CHARGING ||
status == BATTERY_STATUS_FULL;
}
@Override
public void startService() {
if (used.getAndSet(true)) throw new IllegalStateException();
batteryReceiver = new BatteryReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_POWER_CONNECTED);
filter.addAction(ACTION_POWER_DISCONNECTED);
appContext.registerReceiver(batteryReceiver, filter);
}
@Override
public void stopService() {
if (batteryReceiver != null)
appContext.unregisterReceiver(batteryReceiver);
}
private class BatteryReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent i) {
String action = i.getAction();
if (LOG.isLoggable(INFO)) LOG.info("Received broadcast " + action);
if (ACTION_POWER_CONNECTED.equals(action))
eventBus.broadcast(new BatteryEvent(true));
else if (ACTION_POWER_DISCONNECTED.equals(action))
eventBus.broadcast(new BatteryEvent(false));
}
}
}

View File

@@ -1,21 +0,0 @@
package org.briarproject.bramble.battery;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AndroidBatteryModule {
@Provides
@Singleton
BatteryManager provideBatteryManager(LifecycleManager lifecycleManager,
AndroidBatteryManager batteryManager) {
lifecycleManager.registerService(batteryManager);
return batteryManager;
}
}

View File

@@ -6,7 +6,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.os.PowerManager; import android.os.PowerManager;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
@@ -42,18 +41,17 @@ class AndroidTorPlugin extends TorPlugin {
Context appContext, NetworkManager networkManager, Context appContext, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory, LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider, Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, CircumventionProvider circumventionProvider, Backoff backoff,
BatteryManager batteryManager, Backoff backoff,
DuplexPluginCallback callback, String architecture, int maxLatency, DuplexPluginCallback callback, String architecture, int maxLatency,
int maxIdleTime) { int maxIdleTime) {
super(ioExecutor, networkManager, locationUtils, torSocketFactory, super(ioExecutor, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager, clock, resourceProvider, circumventionProvider, backoff,
backoff, callback, architecture, maxLatency, maxIdleTime, callback, architecture, maxLatency, maxIdleTime,
appContext.getDir("tor", MODE_PRIVATE)); appContext.getDir("tor", MODE_PRIVATE));
this.appContext = appContext; this.appContext = appContext;
PowerManager pm = (PowerManager) PowerManager pm = (PowerManager)
appContext.getSystemService(POWER_SERVICE); appContext.getSystemService(POWER_SERVICE);
if (pm == null) throw new AssertionError(); assert pm != null;
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK, wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
WAKE_LOCK_TAG, 1, MINUTES); WAKE_LOCK_TAG, 1, MINUTES);
} }

View File

@@ -3,7 +3,6 @@ package org.briarproject.bramble.plugin.tor;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -49,7 +48,6 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
private final BackoffFactory backoffFactory; private final BackoffFactory backoffFactory;
private final ResourceProvider resourceProvider; private final ResourceProvider resourceProvider;
private final CircumventionProvider circumventionProvider; private final CircumventionProvider circumventionProvider;
private final BatteryManager batteryManager;
private final Clock clock; private final Clock clock;
public AndroidTorPluginFactory(Executor ioExecutor, public AndroidTorPluginFactory(Executor ioExecutor,
@@ -57,8 +55,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
NetworkManager networkManager, LocationUtils locationUtils, NetworkManager networkManager, LocationUtils locationUtils,
EventBus eventBus, SocketFactory torSocketFactory, EventBus eventBus, SocketFactory torSocketFactory,
BackoffFactory backoffFactory, ResourceProvider resourceProvider, BackoffFactory backoffFactory, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, CircumventionProvider circumventionProvider, Clock clock) {
BatteryManager batteryManager, Clock clock) {
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
this.scheduler = scheduler; this.scheduler = scheduler;
this.appContext = appContext; this.appContext = appContext;
@@ -69,7 +66,6 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
this.backoffFactory = backoffFactory; this.backoffFactory = backoffFactory;
this.resourceProvider = resourceProvider; this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider; this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.clock = clock; this.clock = clock;
} }
@@ -108,8 +104,8 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
MAX_POLLING_INTERVAL, BACKOFF_BASE); MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler, AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
appContext, networkManager, locationUtils, torSocketFactory, appContext, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager, clock, resourceProvider, circumventionProvider, backoff,
backoff, callback, architecture, MAX_LATENCY, MAX_IDLE_TIME); callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin); eventBus.addListener(plugin);
return plugin; return plugin;
} }

View File

@@ -11,12 +11,15 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.logging.Logger;
import static android.content.Context.MODE_PRIVATE; import static android.content.Context.MODE_PRIVATE;
import static android.os.Build.VERSION.SDK_INT;
public class AndroidUtils { public class AndroidUtils {
private static final Logger LOG =
Logger.getLogger(AndroidUtils.class.getName());
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later // Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00"; private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
@@ -25,7 +28,7 @@ public class AndroidUtils {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static Collection<String> getSupportedArchitectures() { public static Collection<String> getSupportedArchitectures() {
List<String> abis = new ArrayList<>(); List<String> abis = new ArrayList<>();
if (SDK_INT >= 21) { if (Build.VERSION.SDK_INT >= 21) {
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS)); abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
} else { } else {
abis.add(Build.CPU_ABI); abis.add(Build.CPU_ABI);

View File

@@ -31,21 +31,16 @@ dependencyVerification {
'com.android.tools:sdklib:26.2.1:sdklib-26.2.1.jar:248df7ad5eac4aeb6f96c394c76760de4b7b89ac056e54d0c21a739368b91b45', 'com.android.tools:sdklib:26.2.1:sdklib-26.2.1.jar:248df7ad5eac4aeb6f96c394c76760de4b7b89ac056e54d0c21a739368b91b45',
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed', 'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
'com.google.code.gson:gson:2.8.0:gson-2.8.0.jar:c6221763bd79c4f1c3dc7f750b5f29a0bb38b367b81314c4f71896e340c40825', 'com.google.code.gson:gson:2.8.0:gson-2.8.0.jar:c6221763bd79c4f1c3dc7f750b5f29a0bb38b367b81314c4f71896e340c40825',
'com.google.dagger:dagger-compiler:2.19:dagger-compiler-2.19.jar:27a4b202a2de908182edb261f8c0a264e08e5e4733d7514bc7fbf0d31da5c0fc', 'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.dagger:dagger-producers:2.19:dagger-producers-2.19.jar:a17663abe0fc38b676026950907d4c5f5e2bf338375415861eaff6e3bdb0b768', 'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.dagger:dagger-spi:2.19:dagger-spi-2.19.jar:e7a6379d82c841f6aac2866948ad1eed716528707814602842a8d844ce04e2e1', 'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b', 'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b',
'com.google.errorprone:error_prone_annotations:2.1.3:error_prone_annotations-2.1.3.jar:03d0329547c13da9e17c634d1049ea2ead093925e290567e1a364fd6b1fc7ff8', 'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
'com.google.guava:guava:23.0:guava-23.0.jar:7baa80df284117e5b945b19b98d367a85ea7b7801bd358ff657946c3bd1b6596', 'com.google.guava:guava:23.0:guava-23.0.jar:7baa80df284117e5b945b19b98d367a85ea7b7801bd358ff657946c3bd1b6596',
'com.google.guava:guava:25.0-jre:guava-25.0-jre.jar:3fd4341776428c7e0e5c18a7c10de129475b69ab9d30aeafbb5c277bb6074fa9',
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f', 'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd', 'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4', 'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439', 'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0', 'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce', 'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4', 'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
@@ -68,9 +63,7 @@ dependencyVerification {
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8', 'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca', 'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349', 'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'org.briarproject:obfs4proxy-android:0.0.7:obfs4proxy-android-0.0.7.zip:abdfb5d889d848de9bf214f9276abbf454808a505b870819eccc9a9e985bf617',
'org.briarproject:tor-android:0.3.4.8:tor-android-0.3.4.8.zip:989a0352d9d8d8172cd6c2137654e165e5d2beb10ed1211bab3814e224ad1926', 'org.briarproject:tor-android:0.3.4.8:tor-android-0.3.4.8.zip:989a0352d9d8d8172cd6c2137654e165e5d2beb10ed1211bab3814e224ad1926',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4', 'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d', 'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa', 'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',

View File

@@ -7,13 +7,15 @@ apply plugin: 'witness'
apply from: 'witness.gradle' apply from: 'witness.gradle'
dependencies { dependencies {
implementation "com.google.dagger:dagger:2.19" implementation "com.google.dagger:dagger:2.0.2"
implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation 'com.google.code.findbugs:jsr305:3.0.2'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2" testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2" testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2" testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
signature 'org.codehaus.mojo.signature:java16:1.1@signature' signature 'org.codehaus.mojo.signature:java16:1.1@signature'
} }

View File

@@ -1,26 +0,0 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class Pair<A, B> {
private final A first;
private final B second;
public Pair(A first, B second) {
this.first = first;
this.second = second;
}
public A getFirst() {
return first;
}
public B getSecond() {
return second;
}
}

View File

@@ -1,6 +0,0 @@
package org.briarproject.bramble.api.battery;
public interface BatteryManager {
boolean isCharging();
}

View File

@@ -1,19 +0,0 @@
package org.briarproject.bramble.api.battery.event;
import org.briarproject.bramble.api.event.Event;
/**
* An event that is broadcast when the device starts or stops charging.
*/
public class BatteryEvent extends Event {
private final boolean charging;
public BatteryEvent(boolean charging) {
this.charging = charging;
}
public boolean isCharging() {
return charging;
}
}

View File

@@ -96,12 +96,6 @@ public interface ContactManager {
void setContactActive(Transaction txn, ContactId c, boolean active) void setContactActive(Transaction txn, ContactId c, boolean active)
throws DbException; throws DbException;
/**
* Sets an alias name for the contact or unsets it if alias is null.
*/
void setContactAlias(Transaction txn, ContactId c, @Nullable String alias)
throws DbException;
/** /**
* Sets an alias name for the contact or unsets it if alias is null. * Sets an alias name for the contact or unsets it if alias is null.
*/ */

View File

@@ -1,71 +0,0 @@
package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nullable;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
import static org.briarproject.bramble.util.StringUtils.toHexString;
@NotNullByDefault
public class BdfStringUtils {
public static String toString(@Nullable Object o) throws FormatException {
return toString(o, 0);
}
private static String toString(@Nullable Object o, int indent)
throws FormatException {
if (o == null || o == NULL_VALUE) return "null";
if (o instanceof Boolean) return o.toString();
if (o instanceof Number) return o.toString();
if (o instanceof String) return "\"" + o + "\"";
if (o instanceof Bytes)
return "x" + toHexString(((Bytes) o).getBytes());
if (o instanceof byte[])
return "x" + toHexString((byte[]) o);
if (o instanceof List) {
List<?> list = (List) o;
StringBuilder sb = new StringBuilder();
sb.append("[\n");
int i = 0, size = list.size();
for (Object e : list) {
indent(sb, indent + 1);
sb.append(toString(e, indent + 1));
if (i++ < size - 1) sb.append(',');
sb.append('\n');
}
indent(sb, indent);
sb.append(']');
return sb.toString();
}
if (o instanceof Map) {
Map<?, ?> map = (Map) o;
StringBuilder sb = new StringBuilder();
sb.append("{\n");
int i = 0, size = map.size();
for (Entry e : map.entrySet()) {
indent(sb, indent + 1);
sb.append(toString(e.getKey(), indent + 1));
sb.append(": ");
sb.append(toString(e.getValue(), indent + 1));
if (i++ < size - 1) sb.append(',');
sb.append('\n');
}
indent(sb, indent);
sb.append('}');
return sb.toString();
}
throw new FormatException();
}
private static void indent(StringBuilder sb, int indent) {
for (int i = 0; i < indent; i++) sb.append('\t');
}
}

View File

@@ -89,14 +89,6 @@ public interface DatabaseComponent {
<R, E extends Exception> R transactionWithResult(boolean readOnly, <R, E extends Exception> R transactionWithResult(boolean readOnly,
DbCallable<R, E> task) throws DbException, E; DbCallable<R, E> task) throws DbException, E;
/**
* Runs the given task within a transaction and returns the result of the
* task, which may be null.
*/
@Nullable
<R, E extends Exception> R transactionWithNullableResult(boolean readOnly,
NullableDbCallable<R, E> task) throws DbException, E;
/** /**
* Stores a contact associated with the given local and remote pseudonyms, * Stores a contact associated with the given local and remote pseudonyms,
* and returns an ID for the contact. * and returns an ID for the contact.

View File

@@ -1,8 +1,5 @@
package org.briarproject.bramble.api.db; package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface DbCallable<R, E extends Exception> { public interface DbCallable<R, E extends Exception> {
R call(Transaction txn) throws DbException, E; R call(Transaction txn) throws DbException, E;

View File

@@ -1,8 +1,5 @@
package org.briarproject.bramble.api.db; package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface DbRunnable<E extends Exception> { public interface DbRunnable<E extends Exception> {
void run(Transaction txn) throws DbException, E; void run(Transaction txn) throws DbException, E;

View File

@@ -1,12 +0,0 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
public interface NullableDbCallable<R, E extends Exception> {
@Nullable
R call(Transaction txn) throws DbException, E;
}

View File

@@ -39,18 +39,4 @@ public class AuthorInfo {
return alias; return alias;
} }
@Override
public int hashCode() {
int hashCode = status.ordinal();
if (alias != null) hashCode += alias.hashCode();
return hashCode;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof AuthorInfo)) return false;
AuthorInfo info = (AuthorInfo) o;
return status == info.status &&
(alias == null ? info.alias == null : alias.equals(info.alias));
}
} }

View File

@@ -47,7 +47,7 @@ public class StringUtils {
try { try {
return s.getBytes("UTF-8"); return s.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new AssertionError(e); throw new RuntimeException(e);
} }
} }
@@ -63,7 +63,7 @@ public class StringUtils {
try { try {
return decoder.decode(buffer).toString(); return decoder.decode(buffer).toString();
} catch (CharacterCodingException e) { } catch (CharacterCodingException e) {
throw new AssertionError(e); throw new RuntimeException(e);
} }
} }

View File

@@ -1,42 +0,0 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.NONE;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
public class AuthorInfoTest extends BrambleTestCase {
@Test
public void testEquals() {
assertEquals(
new AuthorInfo(NONE),
new AuthorInfo(NONE, null)
);
assertEquals(
new AuthorInfo(NONE, "test"),
new AuthorInfo(NONE, "test")
);
assertNotEquals(
new AuthorInfo(NONE),
new AuthorInfo(VERIFIED)
);
assertNotEquals(
new AuthorInfo(NONE, "test"),
new AuthorInfo(NONE)
);
assertNotEquals(
new AuthorInfo(NONE),
new AuthorInfo(NONE, "test")
);
assertNotEquals(
new AuthorInfo(NONE, "a"),
new AuthorInfo(NONE, "b")
);
}
}

View File

@@ -2,7 +2,7 @@ dependencyVerification {
verify = [ verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861', 'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7', 'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939', 'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a', 'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d', 'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',

View File

@@ -3,10 +3,10 @@ sourceCompatibility = 1.8
targetCompatibility = 1.8 targetCompatibility = 1.8
apply plugin: 'ru.vyarus.animalsniffer' apply plugin: 'ru.vyarus.animalsniffer'
apply plugin: 'net.ltgt.apt'
apply plugin: 'idea' apply plugin: 'idea'
apply plugin: 'witness' apply plugin: 'witness'
apply from: 'witness.gradle' apply from: 'witness.gradle'
apply from: '../dagger.gradle'
dependencies { dependencies {
implementation project(path: ':bramble-api', configuration: 'default') implementation project(path: ':bramble-api', configuration: 'default')
@@ -17,7 +17,7 @@ dependencies {
implementation 'org.whispersystems:curve25519-java:0.5.0' implementation 'org.whispersystems:curve25519-java:0.5.0'
implementation 'org.briarproject:jtorctl:0.3' implementation 'org.briarproject:jtorctl:0.3'
annotationProcessor 'com.google.dagger:dagger-compiler:2.19' apt 'com.google.dagger:dagger-compiler:2.0.2'
testImplementation project(path: ':bramble-api', configuration: 'testOutput') testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation 'org.hsqldb:hsqldb:2.3.5' // The last version that supports Java 1.6 testImplementation 'org.hsqldb:hsqldb:2.3.5' // The last version that supports Java 1.6
@@ -25,8 +25,10 @@ dependencies {
testImplementation "org.jmock:jmock:2.8.2" testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2" testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2" testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.19' testApt 'com.google.dagger:dagger-compiler:2.0.2'
signature 'org.codehaus.mojo.signature:java16:1.1@signature' signature 'org.codehaus.mojo.signature:java16:1.1@signature'
} }

View File

@@ -1,19 +0,0 @@
package org.briarproject.bramble.battery;
import org.briarproject.bramble.api.battery.BatteryManager;
import dagger.Module;
import dagger.Provides;
/**
* Provides a default implementation of {@link BatteryManager} for systems
* without batteries.
*/
@Module
public class DefaultBatteryManagerModule {
@Provides
BatteryManager provideBatteryManager() {
return () -> false;
}
}

View File

@@ -82,7 +82,13 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public void addLocalMessage(Message m, BdfDictionary metadata, public void addLocalMessage(Message m, BdfDictionary metadata,
boolean shared) throws DbException, FormatException { boolean shared) throws DbException, FormatException {
db.transaction(false, txn -> addLocalMessage(txn, m, metadata, shared)); Transaction txn = db.startTransaction(false);
try {
addLocalMessage(txn, m, metadata, shared);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
@@ -107,7 +113,15 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public Message getMessage(MessageId m) throws DbException { public Message getMessage(MessageId m) throws DbException {
return db.transactionWithResult(true, txn -> getMessage(txn, m)); Message message;
Transaction txn = db.startTransaction(true);
try {
message = getMessage(txn, m);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return message;
} }
@Override @Override
@@ -118,7 +132,15 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfList getMessageAsList(MessageId m) throws DbException, public BdfList getMessageAsList(MessageId m) throws DbException,
FormatException { FormatException {
return db.transactionWithResult(true, txn -> getMessageAsList(txn, m)); BdfList list;
Transaction txn = db.startTransaction(true);
try {
list = getMessageAsList(txn, m);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return list;
} }
@Override @Override
@@ -130,8 +152,15 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfDictionary getGroupMetadataAsDictionary(GroupId g) public BdfDictionary getGroupMetadataAsDictionary(GroupId g)
throws DbException, FormatException { throws DbException, FormatException {
return db.transactionWithResult(true, txn -> BdfDictionary dictionary;
getGroupMetadataAsDictionary(txn, g)); Transaction txn = db.startTransaction(true);
try {
dictionary = getGroupMetadataAsDictionary(txn, g);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return dictionary;
} }
@Override @Override
@@ -144,8 +173,15 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfDictionary getMessageMetadataAsDictionary(MessageId m) public BdfDictionary getMessageMetadataAsDictionary(MessageId m)
throws DbException, FormatException { throws DbException, FormatException {
return db.transactionWithResult(true, txn -> BdfDictionary dictionary;
getMessageMetadataAsDictionary(txn, m)); Transaction txn = db.startTransaction(true);
try {
dictionary = getMessageMetadataAsDictionary(txn, m);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return dictionary;
} }
@Override @Override
@@ -158,8 +194,15 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary( public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
GroupId g) throws DbException, FormatException { GroupId g) throws DbException, FormatException {
return db.transactionWithResult(true, txn -> Map<MessageId, BdfDictionary> map;
getMessageMetadataAsDictionary(txn, g)); Transaction txn = db.startTransaction(true);
try {
map = getMessageMetadataAsDictionary(txn, g);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return map;
} }
@Override @Override
@@ -176,8 +219,15 @@ class ClientHelperImpl implements ClientHelper {
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary( public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
GroupId g, BdfDictionary query) throws DbException, GroupId g, BdfDictionary query) throws DbException,
FormatException { FormatException {
return db.transactionWithResult(true, txn -> Map<MessageId, BdfDictionary> map;
getMessageMetadataAsDictionary(txn, g, query)); Transaction txn = db.startTransaction(true);
try {
map = getMessageMetadataAsDictionary(txn, g, query);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return map;
} }
@Override @Override
@@ -195,7 +245,13 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public void mergeGroupMetadata(GroupId g, BdfDictionary metadata) public void mergeGroupMetadata(GroupId g, BdfDictionary metadata)
throws DbException, FormatException { throws DbException, FormatException {
db.transaction(false, txn -> mergeGroupMetadata(txn, g, metadata)); Transaction txn = db.startTransaction(false);
try {
mergeGroupMetadata(txn, g, metadata);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
@@ -207,7 +263,13 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public void mergeMessageMetadata(MessageId m, BdfDictionary metadata) public void mergeMessageMetadata(MessageId m, BdfDictionary metadata)
throws DbException, FormatException { throws DbException, FormatException {
db.transaction(false, txn -> mergeMessageMetadata(txn, m, metadata)); Transaction txn = db.startTransaction(false);
try {
mergeMessageMetadata(txn, m, metadata);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
@Override @Override

View File

@@ -13,6 +13,7 @@ import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.db.ContactExistsException; import org.briarproject.bramble.api.db.ContactExistsException;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
@@ -157,8 +158,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
streamWriterFactory.createContactExchangeStreamWriter(out, streamWriterFactory.createContactExchangeStreamWriter(out,
alice ? aliceHeaderKey : bobHeaderKey); alice ? aliceHeaderKey : bobHeaderKey);
RecordWriter recordWriter = RecordWriter recordWriter =
recordWriterFactory recordWriterFactory.createRecordWriter(streamWriter.getOutputStream());
.createRecordWriter(streamWriter.getOutputStream());
// Derive the nonces to be signed // Derive the nonces to be signed
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret, byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
@@ -287,14 +287,19 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
private ContactId addContact(Author remoteAuthor, long timestamp, private ContactId addContact(Author remoteAuthor, long timestamp,
Map<TransportId, TransportProperties> remoteProperties) Map<TransportId, TransportProperties> remoteProperties)
throws DbException { throws DbException {
return db.transactionWithResult(false, txn -> { ContactId contactId;
ContactId contactId = contactManager.addContact(txn, remoteAuthor, Transaction txn = db.startTransaction(false);
try {
contactId = contactManager.addContact(txn, remoteAuthor,
localAuthor.getId(), masterSecret, timestamp, alice, localAuthor.getId(), masterSecret, timestamp, alice,
true, true); true, true);
transportPropertyManager.addRemoteProperties(txn, contactId, transportPropertyManager.addRemoteProperties(txn, contactId,
remoteProperties); remoteProperties);
return contactId; db.commitTransaction(txn);
}); } finally {
db.endTransaction(txn);
}
return contactId;
} }
private void tryToClose(DuplexTransportConnection conn) { private void tryToClose(DuplexTransportConnection conn) {

View File

@@ -79,21 +79,42 @@ class ContactManagerImpl implements ContactManager {
public ContactId addContact(Author remote, AuthorId local, SecretKey master, public ContactId addContact(Author remote, AuthorId local, SecretKey master,
long timestamp, boolean alice, boolean verified, boolean active) long timestamp, boolean alice, boolean verified, boolean active)
throws DbException { throws DbException {
return db.transactionWithResult(false, txn -> ContactId c;
addContact(txn, remote, local, master, timestamp, alice, Transaction txn = db.startTransaction(false);
verified, active)); try {
c = addContact(txn, remote, local, master, timestamp, alice,
verified, active);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return c;
} }
@Override @Override
public Contact getContact(ContactId c) throws DbException { public Contact getContact(ContactId c) throws DbException {
return db.transactionWithResult(true, txn -> db.getContact(txn, c)); Contact contact;
Transaction txn = db.startTransaction(true);
try {
contact = db.getContact(txn, c);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return contact;
} }
@Override @Override
public Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId) public Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException { throws DbException {
return db.transactionWithResult(true, txn -> Transaction txn = db.startTransaction(true);
getContact(txn, remoteAuthorId, localAuthorId)); try {
Contact c = getContact(txn, remoteAuthorId, localAuthorId);
db.commitTransaction(txn);
return c;
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
@@ -111,8 +132,14 @@ class ContactManagerImpl implements ContactManager {
@Override @Override
public Collection<Contact> getActiveContacts() throws DbException { public Collection<Contact> getActiveContacts() throws DbException {
Collection<Contact> contacts = Collection<Contact> contacts;
db.transactionWithResult(true, db::getContacts); Transaction txn = db.startTransaction(true);
try {
contacts = db.getContacts(txn);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
List<Contact> active = new ArrayList<>(contacts.size()); List<Contact> active = new ArrayList<>(contacts.size());
for (Contact c : contacts) if (c.isActive()) active.add(c); for (Contact c : contacts) if (c.isActive()) active.add(c);
return active; return active;
@@ -120,7 +147,13 @@ class ContactManagerImpl implements ContactManager {
@Override @Override
public void removeContact(ContactId c) throws DbException { public void removeContact(ContactId c) throws DbException {
db.transaction(false, txn -> removeContact(txn, c)); Transaction txn = db.startTransaction(false);
try {
removeContact(txn, c);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
@@ -130,20 +163,14 @@ class ContactManagerImpl implements ContactManager {
} }
@Override @Override
public void setContactAlias(Transaction txn, ContactId c, public void setContactAlias(ContactId c, @Nullable String alias)
@Nullable String alias) throws DbException { throws DbException {
if (alias != null) { if (alias != null) {
int aliasLength = toUtf8(alias).length; int aliasLength = toUtf8(alias).length;
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH) if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
db.setContactAlias(txn, c, alias); db.transaction(false, txn -> db.setContactAlias(txn, c, alias));
}
@Override
public void setContactAlias(ContactId c, @Nullable String alias)
throws DbException {
db.transaction(false, txn -> setContactAlias(txn, c, alias));
} }
@Override @Override
@@ -155,8 +182,15 @@ class ContactManagerImpl implements ContactManager {
@Override @Override
public boolean contactExists(AuthorId remoteAuthorId, public boolean contactExists(AuthorId remoteAuthorId,
AuthorId localAuthorId) throws DbException { AuthorId localAuthorId) throws DbException {
return db.transactionWithResult(true, txn -> boolean exists;
contactExists(txn, remoteAuthorId, localAuthorId)); Transaction txn = db.startTransaction(true);
try {
exists = contactExists(txn, remoteAuthorId, localAuthorId);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return exists;
} }
@Override @Override

View File

@@ -29,7 +29,6 @@ import static org.briarproject.bramble.data.Types.STRING_16;
import static org.briarproject.bramble.data.Types.STRING_32; import static org.briarproject.bramble.data.Types.STRING_32;
import static org.briarproject.bramble.data.Types.STRING_8; import static org.briarproject.bramble.data.Types.STRING_8;
import static org.briarproject.bramble.data.Types.TRUE; import static org.briarproject.bramble.data.Types.TRUE;
import static org.briarproject.bramble.util.StringUtils.fromUtf8;
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
@@ -254,7 +253,7 @@ class BdfReaderImpl implements BdfReader {
if (length < 0 || length > maxBufferSize) throw new FormatException(); if (length < 0 || length > maxBufferSize) throw new FormatException();
if (length == 0) return ""; if (length == 0) return "";
readIntoBuffer(length); readIntoBuffer(length);
return fromUtf8(buf, 0, length); return new String(buf, 0, length, "UTF-8");
} }
private int readStringLength() throws IOException { private int readStringLength() throws IOException {

View File

@@ -19,7 +19,6 @@ import org.briarproject.bramble.api.db.NoSuchGroupException;
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException; import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
import org.briarproject.bramble.api.db.NoSuchMessageException; import org.briarproject.bramble.api.db.NoSuchMessageException;
import org.briarproject.bramble.api.db.NoSuchTransportException; import org.briarproject.bramble.api.db.NoSuchTransportException;
import org.briarproject.bramble.api.db.NullableDbCallable;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
@@ -194,20 +193,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
} }
@Override
public <R, E extends Exception> R transactionWithNullableResult(
boolean readOnly, NullableDbCallable<R, E> task)
throws DbException, E {
Transaction txn = startTransaction(readOnly);
try {
R result = task.call(txn);
commitTransaction(txn);
return result;
} finally {
endTransaction(txn);
}
}
private T unbox(Transaction transaction) { private T unbox(Transaction transaction) {
if (transaction.isCommitted()) throw new IllegalStateException(); if (transaction.isCommitted()) throw new IllegalStateException();
return txnClass.cast(transaction.unbox()); return txnClass.cast(transaction.unbox());
@@ -876,7 +861,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Override @Override
public void setContactAlias(Transaction transaction, ContactId c, public void setContactAlias(Transaction transaction, ContactId c,
@Nullable String alias) throws DbException { String alias) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException(); if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsContact(txn, c)) if (!db.containsContact(txn, c))

View File

@@ -3,7 +3,7 @@ package org.briarproject.bramble.db;
class DatabaseTypes { class DatabaseTypes {
private final String hashType, secretType, binaryType; private final String hashType, secretType, binaryType;
private final String counterType, stringType; private final String counterType, stringType;
public DatabaseTypes(String hashType, String secretType, String binaryType, public DatabaseTypes(String hashType, String secretType, String binaryType,
String counterType, String stringType) { String counterType, String stringType) {
@@ -17,11 +17,11 @@ class DatabaseTypes {
/** /**
* Replaces database type placeholders in a statement with the actual types. * Replaces database type placeholders in a statement with the actual types.
* These placeholders are currently supported: * These placeholders are currently supported:
* <li> _HASH * <li> _HASH
* <li> _SECRET * <li> _SECRET
* <li> _BINARY * <li> _BINARY
* <li> _COUNTER * <li> _COUNTER
* <li> _STRING * <li> _STRING
*/ */
String replaceTypes(String s) { String replaceTypes(String s) {
s = s.replaceAll("_HASH", hashType); s = s.replaceAll("_HASH", hashType);

View File

@@ -39,7 +39,7 @@ class Migration40_41 implements Migration<Connection> {
try { try {
s = txn.createStatement(); s = txn.createStatement();
s.execute("ALTER TABLE contacts" s.execute("ALTER TABLE contacts"
+ dbTypes.replaceTypes(" ADD alias _STRING")); + dbTypes.replaceTypes(" ADD alias VARCHAR"));
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s); tryToClose(s);
throw new DbException(e); throw new DbException(e);

View File

@@ -67,16 +67,27 @@ class IdentityManagerImpl implements IdentityManager {
LOG.info("No local author to store"); LOG.info("No local author to store");
return; return;
} }
db.transaction(false, txn -> db.addLocalAuthor(txn, cached)); Transaction txn = db.startTransaction(false);
LOG.info("Local author stored"); try {
db.addLocalAuthor(txn, cached);
db.commitTransaction(txn);
LOG.info("Local author stored");
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
public LocalAuthor getLocalAuthor() throws DbException { public LocalAuthor getLocalAuthor() throws DbException {
if (cachedAuthor == null) { if (cachedAuthor == null) {
cachedAuthor = Transaction txn = db.startTransaction(true);
db.transactionWithResult(true, this::loadLocalAuthor); try {
LOG.info("Local author loaded"); cachedAuthor = loadLocalAuthor(txn);
LOG.info("Local author loaded");
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
LocalAuthor cached = cachedAuthor; LocalAuthor cached = cachedAuthor;
if (cached == null) throw new AssertionError(); if (cached == null) throw new AssertionError();

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MigrationListener; import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
@@ -114,16 +115,20 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
dbLatch.countDown(); dbLatch.countDown();
eventBus.broadcast(new LifecycleEvent(STARTING_SERVICES)); eventBus.broadcast(new LifecycleEvent(STARTING_SERVICES));
db.transaction(false, txn -> { Transaction txn = db.startTransaction(false);
try {
for (Client c : clients) { for (Client c : clients) {
long start1 = now(); start = now();
c.createLocalState(txn); c.createLocalState(txn);
if (LOG.isLoggable(FINE)) { if (LOG.isLoggable(FINE)) {
logDuration(LOG, "Starting client " logDuration(LOG, "Starting client "
+ c.getClass().getSimpleName(), start1); + c.getClass().getSimpleName(), start);
} }
} }
}); db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
for (Service s : services) { for (Service s : services) {
start = now(); start = now();
s.startService(); s.startService();

View File

@@ -4,8 +4,6 @@ import net.freehaven.tor.control.EventHandler;
import net.freehaven.tor.control.TorControlConnection; import net.freehaven.tor.control.TorControlConnection;
import org.briarproject.bramble.PoliteExecutor; import org.briarproject.bramble.PoliteExecutor;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.battery.event.BatteryEvent;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
@@ -98,14 +96,13 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private final LocationUtils locationUtils; private final LocationUtils locationUtils;
private final SocketFactory torSocketFactory; private final SocketFactory torSocketFactory;
private final Clock clock; private final Clock clock;
private final BatteryManager batteryManager;
private final Backoff backoff; private final Backoff backoff;
private final DuplexPluginCallback callback; private final DuplexPluginCallback callback;
private final String architecture; private final String architecture;
private final CircumventionProvider circumventionProvider; private final CircumventionProvider circumventionProvider;
private final ResourceProvider resourceProvider; private final ResourceProvider resourceProvider;
private final int maxLatency, maxIdleTime, socketTimeout; private final int maxLatency, maxIdleTime, socketTimeout;
private final File torDirectory, torFile, geoIpFile, obfs4File, configFile; private final File torDirectory, torFile, geoIpFile, configFile;
private final File doneFile, cookieFile; private final File doneFile, cookieFile;
private final ConnectionStatus connectionStatus; private final ConnectionStatus connectionStatus;
private final AtomicBoolean used = new AtomicBoolean(false); private final AtomicBoolean used = new AtomicBoolean(false);
@@ -124,8 +121,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
TorPlugin(Executor ioExecutor, NetworkManager networkManager, TorPlugin(Executor ioExecutor, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory, LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider, Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, CircumventionProvider circumventionProvider, Backoff backoff,
BatteryManager batteryManager, Backoff backoff,
DuplexPluginCallback callback, String architecture, int maxLatency, DuplexPluginCallback callback, String architecture, int maxLatency,
int maxIdleTime, File torDirectory) { int maxIdleTime, File torDirectory) {
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
@@ -135,7 +131,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
this.clock = clock; this.clock = clock;
this.resourceProvider = resourceProvider; this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider; this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.backoff = backoff; this.backoff = backoff;
this.callback = callback; this.callback = callback;
this.architecture = architecture; this.architecture = architecture;
@@ -147,7 +142,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
this.torDirectory = torDirectory; this.torDirectory = torDirectory;
torFile = new File(torDirectory, "tor"); torFile = new File(torDirectory, "tor");
geoIpFile = new File(torDirectory, "geoip"); geoIpFile = new File(torDirectory, "geoip");
obfs4File = new File(torDirectory, "obfs4proxy");
configFile = new File(torDirectory, "torrc"); configFile = new File(torDirectory, "torrc");
doneFile = new File(torDirectory, "done"); doneFile = new File(torDirectory, "done");
cookieFile = new File(torDirectory, ".tor/control_auth_cookie"); cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
@@ -266,8 +260,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
throw new PluginException(e); throw new PluginException(e);
} }
// Check whether we're online // Check whether we're online
updateConnectionStatus(networkManager.getNetworkStatus(), updateConnectionStatus(networkManager.getNetworkStatus());
batteryManager.isCharging());
// Bind a server socket to receive incoming hidden service connections // Bind a server socket to receive incoming hidden service connections
bind(); bind();
} }
@@ -291,12 +284,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
in = getGeoIpInputStream(); in = getGeoIpInputStream();
out = new FileOutputStream(geoIpFile); out = new FileOutputStream(geoIpFile);
IoUtils.copyAndClose(in, out); IoUtils.copyAndClose(in, out);
// Unzip the Obfs4 proxy to the filesystem
in = getObfs4InputStream();
out = new FileOutputStream(obfs4File);
IoUtils.copyAndClose(in, out);
// Make the Obfs4 proxy executable
if (!obfs4File.setExecutable(true, true)) throw new IOException();
// Copy the config file to the filesystem // Copy the config file to the filesystem
in = getConfigInputStream(); in = getConfigInputStream();
out = new FileOutputStream(configFile); out = new FileOutputStream(configFile);
@@ -327,16 +314,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
return zin; return zin;
} }
private InputStream getObfs4InputStream() throws IOException {
if (LOG.isLoggable(INFO))
LOG.info("Installing obfs4proxy binary for " + architecture);
InputStream in = resourceProvider
.getResourceInputStream("obfs4proxy_" + architecture, ".zip");
ZipInputStream zin = new ZipInputStream(in);
if (zin.getNextEntry() == null) throw new IOException();
return zin;
}
private InputStream getConfigInputStream() { private InputStream getConfigInputStream() {
return getClass().getClassLoader().getResourceAsStream("torrc"); return getClass().getClassLoader().getResourceAsStream("torrc");
} }
@@ -495,8 +472,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (enable) { if (enable) {
Collection<String> conf = new ArrayList<>(); Collection<String> conf = new ArrayList<>();
conf.add("UseBridges 1"); conf.add("UseBridges 1");
conf.add("ClientTransportPlugin obfs4 exec " +
obfs4File.getAbsolutePath());
conf.addAll(circumventionProvider.getBridges()); conf.addAll(circumventionProvider.getBridges());
controlConnection.setConf(conf); controlConnection.setConf(conf);
} else { } else {
@@ -634,8 +609,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
LOG.info("OR connection " + status + " " + orName); LOG.info("OR connection " + status + " " + orName);
if (status.equals("CLOSED") || status.equals("FAILED")) { if (status.equals("CLOSED") || status.equals("FAILED")) {
// Check whether we've lost connectivity // Check whether we've lost connectivity
updateConnectionStatus(networkManager.getNetworkStatus(), updateConnectionStatus(networkManager.getNetworkStatus());
batteryManager.isCharging());
} }
} }
@@ -673,15 +647,10 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
// Works around a bug introduced in Tor 0.3.4.8. Could be // Works around a bug introduced in Tor 0.3.4.8. Could be
// replaced with callback.transportDisabled() when fixed. // replaced with callback.transportDisabled() when fixed.
disableNetwork(); disableNetwork();
updateConnectionStatus(networkManager.getNetworkStatus(), updateConnectionStatus(networkManager.getNetworkStatus());
batteryManager.isCharging());
} }
} else if (e instanceof NetworkStatusEvent) { } else if (e instanceof NetworkStatusEvent) {
updateConnectionStatus(((NetworkStatusEvent) e).getStatus(), updateConnectionStatus(((NetworkStatusEvent) e).getStatus());
batteryManager.isCharging());
} else if (e instanceof BatteryEvent) {
updateConnectionStatus(networkManager.getNetworkStatus(),
((BatteryEvent) e).isCharging());
} }
} }
@@ -695,8 +664,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}); });
} }
private void updateConnectionStatus(NetworkStatus status, private void updateConnectionStatus(NetworkStatus status) {
boolean charging) {
connectionStatusExecutor.execute(() -> { connectionStatusExecutor.execute(() -> {
if (!running) return; if (!running) return;
boolean online = status.isConnected(); boolean online = status.isConnected();
@@ -714,7 +682,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
LOG.info("Online: " + online + ", wifi: " + wifi); LOG.info("Online: " + online + ", wifi: " + wifi);
if ("".equals(country)) LOG.info("Country code unknown"); if ("".equals(country)) LOG.info("Country code unknown");
else LOG.info("Country code: " + country); else LOG.info("Country code: " + country);
LOG.info("Charging: " + charging);
} }
try { try {
@@ -738,24 +705,12 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
enableBridges(false); enableBridges(false);
enableNetwork(true); enableNetwork(true);
} }
if (online && wifi && charging) {
LOG.info("Enabling connection padding");
enableConnectionPadding(true);
} else {
LOG.info("Disabling connection padding");
enableConnectionPadding(false);
}
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
} }
}); });
} }
private void enableConnectionPadding(boolean enable) throws IOException {
if (!running) return;
controlConnection.setConf("ConnectionPadding", enable ? "1" : "0");
}
// TODO remove when sufficient time has passed. Added 2018-08-15 // TODO remove when sufficient time has passed. Added 2018-08-15
private void migrateSettings() { private void migrateSettings() {
Settings sOld = callback.getSettings(); Settings sOld = callback.getSettings();

View File

@@ -142,7 +142,15 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
@Override @Override
public Map<TransportId, TransportProperties> getLocalProperties() public Map<TransportId, TransportProperties> getLocalProperties()
throws DbException { throws DbException {
return db.transactionWithResult(true, this::getLocalProperties); Map<TransportId, TransportProperties> local;
Transaction txn = db.startTransaction(true);
try {
local = getLocalProperties(txn);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return local;
} }
@Override @Override
@@ -168,8 +176,9 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
public TransportProperties getLocalProperties(TransportId t) public TransportProperties getLocalProperties(TransportId t)
throws DbException { throws DbException {
try { try {
return db.transactionWithResult(true, txn -> { TransportProperties p = null;
TransportProperties p = null; Transaction txn = db.startTransaction(true);
try {
// Find the latest local update // Find the latest local update
LatestUpdate latest = findLatest(txn, localGroup.getId(), t, LatestUpdate latest = findLatest(txn, localGroup.getId(), t,
true); true);
@@ -179,8 +188,11 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
latest.messageId); latest.messageId);
p = parseProperties(message); p = parseProperties(message);
} }
return p == null ? new TransportProperties() : p; db.commitTransaction(txn);
}); } finally {
db.endTransaction(txn);
}
return p == null ? new TransportProperties() : p;
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }
@@ -189,12 +201,16 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
@Override @Override
public Map<ContactId, TransportProperties> getRemoteProperties( public Map<ContactId, TransportProperties> getRemoteProperties(
TransportId t) throws DbException { TransportId t) throws DbException {
return db.transactionWithResult(true, txn -> { Map<ContactId, TransportProperties> remote = new HashMap<>();
Map<ContactId, TransportProperties> remote = new HashMap<>(); Transaction txn = db.startTransaction(true);
try {
for (Contact c : db.getContacts(txn)) for (Contact c : db.getContacts(txn))
remote.put(c.getId(), getRemoteProperties(txn, c, t)); remote.put(c.getId(), getRemoteProperties(txn, c, t));
return remote; db.commitTransaction(txn);
}); } finally {
db.endTransaction(txn);
}
return remote;
} }
private TransportProperties getRemoteProperties(Transaction txn, Contact c, private TransportProperties getRemoteProperties(Transaction txn, Contact c,
@@ -218,15 +234,23 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
@Override @Override
public TransportProperties getRemoteProperties(ContactId c, TransportId t) public TransportProperties getRemoteProperties(ContactId c, TransportId t)
throws DbException { throws DbException {
return db.transactionWithResult(true, txn -> TransportProperties p;
getRemoteProperties(txn, db.getContact(txn, c), t)); Transaction txn = db.startTransaction(true);
try {
p = getRemoteProperties(txn, db.getContact(txn, c), t);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return p;
} }
@Override @Override
public void mergeLocalProperties(TransportId t, TransportProperties p) public void mergeLocalProperties(TransportId t, TransportProperties p)
throws DbException { throws DbException {
try { try {
db.transaction(false, txn -> { Transaction txn = db.startTransaction(false);
try {
// Merge the new properties with any existing properties // Merge the new properties with any existing properties
TransportProperties merged; TransportProperties merged;
boolean changed; boolean changed;
@@ -263,7 +287,10 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
db.removeMessage(txn, latest.messageId); db.removeMessage(txn, latest.messageId);
} }
} }
}); db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }

View File

@@ -23,8 +23,15 @@ class SettingsManagerImpl implements SettingsManager {
@Override @Override
public Settings getSettings(String namespace) throws DbException { public Settings getSettings(String namespace) throws DbException {
return db.transactionWithResult(true, txn -> Settings s;
db.getSettings(txn, namespace)); Transaction txn = db.startTransaction(true);
try {
s = db.getSettings(txn, namespace);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return s;
} }
@Override @Override
@@ -35,6 +42,12 @@ class SettingsManagerImpl implements SettingsManager {
@Override @Override
public void mergeSettings(Settings s, String namespace) throws DbException { public void mergeSettings(Settings s, String namespace) throws DbException {
db.transaction(false, txn -> db.mergeSettings(txn, s, namespace)); Transaction txn = db.startTransaction(false);
try {
db.mergeSettings(txn, s, namespace);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
} }

View File

@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.event.EventListener;
@@ -229,8 +230,14 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
if (interrupted) return; if (interrupted) return;
if (!generateAckQueued.getAndSet(false)) throw new AssertionError(); if (!generateAckQueued.getAndSet(false)) throw new AssertionError();
try { try {
Ack a = db.transactionWithNullableResult(false, txn -> Ack a;
db.generateAck(txn, contactId, MAX_MESSAGE_IDS)); Transaction txn = db.startTransaction(false);
try {
a = db.generateAck(txn, contactId, MAX_MESSAGE_IDS);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Generated ack: " + (a != null)); LOG.info("Generated ack: " + (a != null));
if (a != null) writerTasks.add(new WriteAck(a)); if (a != null) writerTasks.add(new WriteAck(a));
@@ -268,15 +275,16 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
if (!generateBatchQueued.getAndSet(false)) if (!generateBatchQueued.getAndSet(false))
throw new AssertionError(); throw new AssertionError();
try { try {
Collection<Message> b = Collection<Message> b;
db.transactionWithNullableResult(false, txn -> { Transaction txn = db.startTransaction(false);
Collection<Message> batch = try {
db.generateRequestedBatch(txn, contactId, b = db.generateRequestedBatch(txn, contactId,
MAX_RECORD_PAYLOAD_BYTES, MAX_RECORD_PAYLOAD_BYTES, maxLatency);
maxLatency); setNextSendTime(db.getNextSendTime(txn, contactId));
setNextSendTime(db.getNextSendTime(txn, contactId)); db.commitTransaction(txn);
return batch; } finally {
}); db.endTransaction(txn);
}
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Generated batch: " + (b != null)); LOG.info("Generated batch: " + (b != null));
if (b != null) writerTasks.add(new WriteBatch(b)); if (b != null) writerTasks.add(new WriteBatch(b));
@@ -314,12 +322,16 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
if (!generateOfferQueued.getAndSet(false)) if (!generateOfferQueued.getAndSet(false))
throw new AssertionError(); throw new AssertionError();
try { try {
Offer o = db.transactionWithNullableResult(false, txn -> { Offer o;
Offer offer = db.generateOffer(txn, contactId, Transaction txn = db.startTransaction(false);
MAX_MESSAGE_IDS, maxLatency); try {
o = db.generateOffer(txn, contactId, MAX_MESSAGE_IDS,
maxLatency);
setNextSendTime(db.getNextSendTime(txn, contactId)); setNextSendTime(db.getNextSendTime(txn, contactId));
return offer; db.commitTransaction(txn);
}); } finally {
db.endTransaction(txn);
}
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Generated offer: " + (o != null)); LOG.info("Generated offer: " + (o != null));
if (o != null) writerTasks.add(new WriteOffer(o)); if (o != null) writerTasks.add(new WriteOffer(o));
@@ -357,8 +369,14 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
if (!generateRequestQueued.getAndSet(false)) if (!generateRequestQueued.getAndSet(false))
throw new AssertionError(); throw new AssertionError();
try { try {
Request r = db.transactionWithNullableResult(false, txn -> Request r;
db.generateRequest(txn, contactId, MAX_MESSAGE_IDS)); Transaction txn = db.startTransaction(false);
try {
r = db.generateRequest(txn, contactId, MAX_MESSAGE_IDS);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Generated request: " + (r != null)); LOG.info("Generated request: " + (r != null));
if (r != null) writerTasks.add(new WriteRequest(r)); if (r != null) writerTasks.add(new WriteRequest(r));

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.event.EventListener;
@@ -119,8 +120,13 @@ class IncomingSession implements SyncSession, EventListener {
@Override @Override
public void run() { public void run() {
try { try {
db.transaction(false, txn -> Transaction txn = db.startTransaction(false);
db.receiveAck(txn, contactId, ack)); try {
db.receiveAck(txn, contactId, ack);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
interrupt(); interrupt();
@@ -140,8 +146,13 @@ class IncomingSession implements SyncSession, EventListener {
@Override @Override
public void run() { public void run() {
try { try {
db.transaction(false, txn -> Transaction txn = db.startTransaction(false);
db.receiveMessage(txn, contactId, message)); try {
db.receiveMessage(txn, contactId, message);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
interrupt(); interrupt();
@@ -161,8 +172,13 @@ class IncomingSession implements SyncSession, EventListener {
@Override @Override
public void run() { public void run() {
try { try {
db.transaction(false, txn -> Transaction txn = db.startTransaction(false);
db.receiveOffer(txn, contactId, offer)); try {
db.receiveOffer(txn, contactId, offer);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
interrupt(); interrupt();
@@ -182,8 +198,13 @@ class IncomingSession implements SyncSession, EventListener {
@Override @Override
public void run() { public void run() {
try { try {
db.transaction(false, txn -> Transaction txn = db.startTransaction(false);
db.receiveRequest(txn, contactId, request)); try {
db.receiveRequest(txn, contactId, request);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
interrupt(); interrupt();

View File

@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.event.EventListener;
@@ -46,8 +47,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(SimplexOutgoingSession.class.getName()); Logger.getLogger(SimplexOutgoingSession.class.getName());
private static final ThrowingRunnable<IOException> CLOSE = () -> { private static final ThrowingRunnable<IOException> CLOSE = () -> {};
};
private final DatabaseComponent db; private final DatabaseComponent db;
private final Executor dbExecutor; private final Executor dbExecutor;
@@ -128,8 +128,14 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
public void run() { public void run() {
if (interrupted) return; if (interrupted) return;
try { try {
Ack a = db.transactionWithNullableResult(false, txn -> Ack a;
db.generateAck(txn, contactId, MAX_MESSAGE_IDS)); Transaction txn = db.startTransaction(false);
try {
a = db.generateAck(txn, contactId, MAX_MESSAGE_IDS);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Generated ack: " + (a != null)); LOG.info("Generated ack: " + (a != null));
if (a == null) decrementOutstandingQueries(); if (a == null) decrementOutstandingQueries();
@@ -166,10 +172,15 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
public void run() { public void run() {
if (interrupted) return; if (interrupted) return;
try { try {
Collection<Message> b = Collection<Message> b;
db.transactionWithNullableResult(false, txn -> Transaction txn = db.startTransaction(false);
db.generateBatch(txn, contactId, try {
MAX_RECORD_PAYLOAD_BYTES, maxLatency)); b = db.generateBatch(txn, contactId,
MAX_RECORD_PAYLOAD_BYTES, maxLatency);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Generated batch: " + (b != null)); LOG.info("Generated batch: " + (b != null));
if (b == null) decrementOutstandingQueries(); if (b == null) decrementOutstandingQueries();

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.sync; package org.briarproject.bramble.sync;
import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
@@ -98,8 +97,14 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor @DatabaseExecutor
private void validateOutstandingMessages() { private void validateOutstandingMessages() {
try { try {
Queue<MessageId> unvalidated = new LinkedList<>( Queue<MessageId> unvalidated = new LinkedList<>();
db.transactionWithResult(true, db::getMessagesToValidate)); Transaction txn = db.startTransaction(true);
try {
unvalidated.addAll(db.getMessagesToValidate(txn));
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
validateNextMessageAsync(unvalidated); validateNextMessageAsync(unvalidated);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
@@ -114,14 +119,18 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor @DatabaseExecutor
private void validateNextMessage(Queue<MessageId> unvalidated) { private void validateNextMessage(Queue<MessageId> unvalidated) {
try { try {
Pair<Message, Group> mg = db.transactionWithResult(true, txn -> { Message m;
Group g;
Transaction txn = db.startTransaction(true);
try {
MessageId id = unvalidated.poll(); MessageId id = unvalidated.poll();
if (id == null) throw new AssertionError(); m = db.getMessage(txn, id);
Message m = db.getMessage(txn, id); g = db.getGroup(txn, m.getGroupId());
Group g = db.getGroup(txn, m.getGroupId()); db.commitTransaction(txn);
return new Pair<>(m, g); } finally {
}); db.endTransaction(txn);
validateMessageAsync(mg.getFirst(), mg.getSecond()); }
validateMessageAsync(m, g);
validateNextMessageAsync(unvalidated); validateNextMessageAsync(unvalidated);
} catch (NoSuchMessageException e) { } catch (NoSuchMessageException e) {
LOG.info("Message removed before validation"); LOG.info("Message removed before validation");
@@ -141,8 +150,14 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor @DatabaseExecutor
private void deliverOutstandingMessages() { private void deliverOutstandingMessages() {
try { try {
Queue<MessageId> pending = new LinkedList<>( Queue<MessageId> pending = new LinkedList<>();
db.transactionWithResult(true, db::getPendingMessages)); Transaction txn = db.startTransaction(true);
try {
pending.addAll(db.getPendingMessages(txn));
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
deliverNextPendingMessageAsync(pending); deliverNextPendingMessageAsync(pending);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
@@ -157,12 +172,12 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor @DatabaseExecutor
private void deliverNextPendingMessage(Queue<MessageId> pending) { private void deliverNextPendingMessage(Queue<MessageId> pending) {
try { try {
Queue<MessageId> toShare = new LinkedList<>(); boolean anyInvalid = false, allDelivered = true;
Queue<MessageId> invalidate = new LinkedList<>(); Queue<MessageId> toShare = null;
db.transaction(false, txn -> { Queue<MessageId> invalidate = null;
boolean anyInvalid = false, allDelivered = true; Transaction txn = db.startTransaction(false);
try {
MessageId id = pending.poll(); MessageId id = pending.poll();
if (id == null) throw new AssertionError();
// Check if message is still pending // Check if message is still pending
if (db.getMessageState(txn, id) == PENDING) { if (db.getMessageState(txn, id) == PENDING) {
// Check if dependencies are valid and delivered // Check if dependencies are valid and delivered
@@ -174,7 +189,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
} }
if (anyInvalid) { if (anyInvalid) {
invalidateMessage(txn, id); invalidateMessage(txn, id);
addDependentsToInvalidate(txn, id, invalidate); invalidate = getDependentsToInvalidate(txn, id);
} else if (allDelivered) { } else if (allDelivered) {
Message m = db.getMessage(txn, id); Message m = db.getMessage(txn, id);
Group g = db.getGroup(txn, m.getGroupId()); Group g = db.getGroup(txn, m.getGroupId());
@@ -185,19 +200,22 @@ class ValidationManagerImpl implements ValidationManager, Service,
DeliveryResult result = DeliveryResult result =
deliverMessage(txn, m, c, majorVersion, meta); deliverMessage(txn, m, c, majorVersion, meta);
if (result.valid) { if (result.valid) {
addPendingDependents(txn, id, pending); pending.addAll(getPendingDependents(txn, id));
if (result.share) { if (result.share) {
db.setMessageShared(txn, id); db.setMessageShared(txn, id);
toShare.addAll(states.keySet()); toShare = new LinkedList<>(states.keySet());
} }
} else { } else {
addDependentsToInvalidate(txn, id, invalidate); invalidate = getDependentsToInvalidate(txn, id);
} }
} }
} }
}); db.commitTransaction(txn);
if (!invalidate.isEmpty()) invalidateNextMessageAsync(invalidate); } finally {
if (!toShare.isEmpty()) shareNextMessageAsync(toShare); db.endTransaction(txn);
}
if (invalidate != null) invalidateNextMessageAsync(invalidate);
if (toShare != null) shareNextMessageAsync(toShare);
deliverNextPendingMessageAsync(pending); deliverNextPendingMessageAsync(pending);
} catch (NoSuchMessageException e) { } catch (NoSuchMessageException e) {
LOG.info("Message removed before delivery"); LOG.info("Message removed before delivery");
@@ -246,11 +264,12 @@ class ValidationManagerImpl implements ValidationManager, Service,
MessageContext context) { MessageContext context) {
try { try {
MessageId id = m.getId(); MessageId id = m.getId();
Queue<MessageId> invalidate = new LinkedList<>(); boolean anyInvalid = false, allDelivered = true;
Queue<MessageId> pending = new LinkedList<>(); Queue<MessageId> invalidate = null;
Queue<MessageId> toShare = new LinkedList<>(); Queue<MessageId> pending = null;
db.transaction(false, txn -> { Queue<MessageId> toShare = null;
boolean anyInvalid = false, allDelivered = true; Transaction txn = db.startTransaction(false);
try {
// Check if message has any dependencies // Check if message has any dependencies
Collection<MessageId> dependencies = context.getDependencies(); Collection<MessageId> dependencies = context.getDependencies();
if (!dependencies.isEmpty()) { if (!dependencies.isEmpty()) {
@@ -266,7 +285,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
if (anyInvalid) { if (anyInvalid) {
if (db.getMessageState(txn, id) != INVALID) { if (db.getMessageState(txn, id) != INVALID) {
invalidateMessage(txn, id); invalidateMessage(txn, id);
addDependentsToInvalidate(txn, id, invalidate); invalidate = getDependentsToInvalidate(txn, id);
} }
} else { } else {
Metadata meta = context.getMetadata(); Metadata meta = context.getMetadata();
@@ -275,22 +294,25 @@ class ValidationManagerImpl implements ValidationManager, Service,
DeliveryResult result = DeliveryResult result =
deliverMessage(txn, m, c, majorVersion, meta); deliverMessage(txn, m, c, majorVersion, meta);
if (result.valid) { if (result.valid) {
addPendingDependents(txn, id, pending); pending = getPendingDependents(txn, id);
if (result.share) { if (result.share) {
db.setMessageShared(txn, id); db.setMessageShared(txn, id);
toShare.addAll(dependencies); toShare = new LinkedList<>(dependencies);
} }
} else { } else {
addDependentsToInvalidate(txn, id, invalidate); invalidate = getDependentsToInvalidate(txn, id);
} }
} else { } else {
db.setMessageState(txn, id, PENDING); db.setMessageState(txn, id, PENDING);
} }
} }
}); db.commitTransaction(txn);
if (!invalidate.isEmpty()) invalidateNextMessageAsync(invalidate); } finally {
if (!pending.isEmpty()) deliverNextPendingMessageAsync(pending); db.endTransaction(txn);
if (!toShare.isEmpty()) shareNextMessageAsync(toShare); }
if (invalidate != null) invalidateNextMessageAsync(invalidate);
if (pending != null) deliverNextPendingMessageAsync(pending);
if (toShare != null) shareNextMessageAsync(toShare);
} catch (NoSuchMessageException e) { } catch (NoSuchMessageException e) {
LOG.info("Message removed during validation"); LOG.info("Message removed during validation");
} catch (NoSuchGroupException e) { } catch (NoSuchGroupException e) {
@@ -320,12 +342,14 @@ class ValidationManagerImpl implements ValidationManager, Service,
} }
@DatabaseExecutor @DatabaseExecutor
private void addPendingDependents(Transaction txn, MessageId m, private Queue<MessageId> getPendingDependents(Transaction txn, MessageId m)
Queue<MessageId> pending) throws DbException { throws DbException {
Queue<MessageId> pending = new LinkedList<>();
Map<MessageId, State> states = db.getMessageDependents(txn, m); Map<MessageId, State> states = db.getMessageDependents(txn, m);
for (Entry<MessageId, State> e : states.entrySet()) { for (Entry<MessageId, State> e : states.entrySet()) {
if (e.getValue() == PENDING) pending.add(e.getKey()); if (e.getValue() == PENDING) pending.add(e.getKey());
} }
return pending;
} }
private void shareOutstandingMessagesAsync() { private void shareOutstandingMessagesAsync() {
@@ -335,8 +359,14 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor @DatabaseExecutor
private void shareOutstandingMessages() { private void shareOutstandingMessages() {
try { try {
Queue<MessageId> toShare = new LinkedList<>( Queue<MessageId> toShare = new LinkedList<>();
db.transactionWithResult(true, db::getMessagesToShare)); Transaction txn = db.startTransaction(true);
try {
toShare.addAll(db.getMessagesToShare(txn));
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
shareNextMessageAsync(toShare); shareNextMessageAsync(toShare);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
@@ -357,12 +387,15 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor @DatabaseExecutor
private void shareNextMessage(Queue<MessageId> toShare) { private void shareNextMessage(Queue<MessageId> toShare) {
try { try {
db.transaction(false, txn -> { Transaction txn = db.startTransaction(false);
try {
MessageId id = toShare.poll(); MessageId id = toShare.poll();
if (id == null) throw new AssertionError();
db.setMessageShared(txn, id); db.setMessageShared(txn, id);
toShare.addAll(db.getMessageDependencies(txn, id).keySet()); toShare.addAll(db.getMessageDependencies(txn, id).keySet());
}); db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
shareNextMessageAsync(toShare); shareNextMessageAsync(toShare);
} catch (NoSuchMessageException e) { } catch (NoSuchMessageException e) {
LOG.info("Message removed before sharing"); LOG.info("Message removed before sharing");
@@ -383,14 +416,17 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor @DatabaseExecutor
private void invalidateNextMessage(Queue<MessageId> invalidate) { private void invalidateNextMessage(Queue<MessageId> invalidate) {
try { try {
db.transaction(false, txn -> { Transaction txn = db.startTransaction(false);
try {
MessageId id = invalidate.poll(); MessageId id = invalidate.poll();
if (id == null) throw new AssertionError();
if (db.getMessageState(txn, id) != INVALID) { if (db.getMessageState(txn, id) != INVALID) {
invalidateMessage(txn, id); invalidateMessage(txn, id);
addDependentsToInvalidate(txn, id, invalidate); invalidate.addAll(getDependentsToInvalidate(txn, id));
} }
}); db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
invalidateNextMessageAsync(invalidate); invalidateNextMessageAsync(invalidate);
} catch (NoSuchMessageException e) { } catch (NoSuchMessageException e) {
LOG.info("Message removed before invalidation"); LOG.info("Message removed before invalidation");
@@ -409,12 +445,14 @@ class ValidationManagerImpl implements ValidationManager, Service,
} }
@DatabaseExecutor @DatabaseExecutor
private void addDependentsToInvalidate(Transaction txn, private Queue<MessageId> getDependentsToInvalidate(Transaction txn,
MessageId m, Queue<MessageId> invalidate) throws DbException { MessageId m) throws DbException {
Queue<MessageId> invalidate = new LinkedList<>();
Map<MessageId, State> states = db.getMessageDependents(txn, m); Map<MessageId, State> states = db.getMessageDependents(txn, m);
for (Entry<MessageId, State> e : states.entrySet()) { for (Entry<MessageId, State> e : states.entrySet()) {
if (e.getValue() != INVALID) invalidate.add(e.getKey()); if (e.getValue() != INVALID) invalidate.add(e.getKey());
} }
return invalidate;
} }
@Override @Override
@@ -434,8 +472,14 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor @DatabaseExecutor
private void loadGroupAndValidate(Message m) { private void loadGroupAndValidate(Message m) {
try { try {
Group g = db.transactionWithResult(true, txn -> Group g;
db.getGroup(txn, m.getGroupId())); Transaction txn = db.startTransaction(true);
try {
g = db.getGroup(txn, m.getGroupId());
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
validateMessageAsync(m, g); validateMessageAsync(m, g);
} catch (NoSuchGroupException e) { } catch (NoSuchGroupException e) {
LOG.info("Group removed before validation"); LOG.info("Group removed before validation");

View File

@@ -72,7 +72,8 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
for (DuplexPluginFactory f : pluginConfig.getDuplexFactories()) for (DuplexPluginFactory f : pluginConfig.getDuplexFactories())
transports.put(f.getId(), f.getMaxLatency()); transports.put(f.getId(), f.getMaxLatency());
try { try {
db.transaction(false, txn -> { Transaction txn = db.startTransaction(false);
try {
for (Contact c : db.getContacts(txn)) for (Contact c : db.getContacts(txn))
if (c.isActive()) activeContacts.put(c.getId(), true); if (c.isActive()) activeContacts.put(c.getId(), true);
for (Entry<TransportId, Integer> e : transports.entrySet()) for (Entry<TransportId, Integer> e : transports.entrySet())
@@ -84,7 +85,10 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
managers.put(e.getKey(), m); managers.put(e.getKey(), m);
m.start(txn); m.start(txn);
} }
}); db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} catch (DbException e) { } catch (DbException e) {
throw new ServiceException(e); throw new ServiceException(e);
} }
@@ -137,8 +141,15 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t); if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
return null; return null;
} }
return db.transactionWithNullableResult(false, txn -> StreamContext ctx;
m.getStreamContext(txn, c)); Transaction txn = db.startTransaction(false);
try {
ctx = m.getStreamContext(txn, c);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return ctx;
} }
@Override @Override
@@ -149,8 +160,15 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t); if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
return null; return null;
} }
return db.transactionWithNullableResult(false, txn -> StreamContext ctx;
m.getStreamContext(txn, tag)); Transaction txn = db.startTransaction(false);
try {
ctx = m.getStreamContext(txn, tag);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return ctx;
} }
@Override @Override

View File

@@ -162,7 +162,13 @@ class TransportKeyManagerImpl implements TransportKeyManager {
private void rotateKeys() { private void rotateKeys() {
dbExecutor.execute(() -> { dbExecutor.execute(() -> {
try { try {
db.transaction(false, this::rotateKeys); Transaction txn = db.startTransaction(false);
try {
rotateKeys(txn);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
} }

View File

@@ -123,12 +123,16 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
List<ClientVersion> versions = new ArrayList<>(clients); List<ClientVersion> versions = new ArrayList<>(clients);
Collections.sort(versions); Collections.sort(versions);
try { try {
db.transaction(false, txn -> { Transaction txn = db.startTransaction(false);
try {
if (updateClientVersions(txn, versions)) { if (updateClientVersions(txn, versions)) {
for (Contact c : db.getContacts(txn)) for (Contact c : db.getContacts(txn))
clientVersionsUpdated(txn, c, versions); clientVersionsUpdated(txn, c, versions);
} }
}); db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} catch (DbException e) { } catch (DbException e) {
throw new ServiceException(e); throw new ServiceException(e);
} }

View File

@@ -1,4 +1,8 @@
Bridge obfs4 78.46.188.239:37356 5A2D2F4158D0453E00C7C176978D3F41D69C45DB cert=3c0SwxpOisbohNxEc4tb875RVW8eOu1opRTVXJhafaKA/PNNtI7ElQIVOVZg1AdL5bxGCw iat-mode=0 Bridge 131.252.210.150:8081 0E858AC201BF0F3FA3C462F64844CBFFC7297A42
Bridge obfs4 52.15.78.72:9443 02069A3C5362476936B62BA6F5ACC41ABD573A9B cert=ijYG/OKc7kqu2YzKNFfeXN7/BG2BOgfEP2KyYEiGDQthnHbsOiTWHeIG0WJVW+BckzDgKw iat-mode=0 Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98
Bridge obfs4 13.58.29.242:9443 0C58939A77DA6B6B29D4B5236A75865659607AE0 cert=OylWIEHb/ezpq1zWxW0sgKRn+9ARH2eOcQOZ8/Gew+4l+oKOhQ2jUX/Y+FSl61JorXZUWA iat-mode=0 Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D
Bridge obfs4 45.33.37.112:9443 60A609BB4ABE8D46E634AE81ED29ADAB7776B399 cert=t5v19WmNv5Sc2YPNr8RQids365W7MY8zJwQVkOxBjUMFomMWARDzsbYpcWLLcw0J9Gm+BQ iat-mode=0 Bridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC
Bridge 45.55.1.74:8443 6F18FEFBB0CAECD5ABA755312FCCB34FC11A7AB8
Bridge 85.229.131.78:444 50E433CCC5FEC11CC34CB4D92033561E065EA106
Bridge 178.62.62.193:8443 391B1F9B6A28A1C5FAE1872283985F975E5DB029
Bridge 45.76.29.92:8443 ECF1DD51A46FDEF2C50CED992EEEAE8DED18DA0C

View File

@@ -22,7 +22,6 @@ import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageFactory; import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.briarproject.bramble.util.StringUtils; import org.briarproject.bramble.util.StringUtils;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.jmock.Mockery; import org.jmock.Mockery;
@@ -86,11 +85,14 @@ public class ClientHelperImplTest extends BrambleTestCase {
boolean shared = new Random().nextBoolean(); boolean shared = new Random().nextBoolean();
Transaction txn = new Transaction(null, false); Transaction txn = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
oneOf(metadataEncoder).encode(dictionary); oneOf(metadataEncoder).encode(dictionary);
will(returnValue(metadata)); will(returnValue(metadata));
oneOf(db).addLocalMessage(txn, message, metadata, shared); oneOf(db).addLocalMessage(txn, message, metadata, shared);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
clientHelper.addLocalMessage(message, dictionary, shared); clientHelper.addLocalMessage(message, dictionary, shared);
@@ -114,10 +116,13 @@ public class ClientHelperImplTest extends BrambleTestCase {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
expectToList(true); expectToList(true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessage(txn, messageId); oneOf(db).getMessage(txn, messageId);
will(returnValue(message)); will(returnValue(message));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
clientHelper.getMessageAsList(messageId); clientHelper.getMessageAsList(messageId);
@@ -128,12 +133,15 @@ public class ClientHelperImplTest extends BrambleTestCase {
public void testGetGroupMetadataAsDictionary() throws Exception { public void testGetGroupMetadataAsDictionary() throws Exception {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getGroupMetadata(txn, groupId); oneOf(db).getGroupMetadata(txn, groupId);
will(returnValue(metadata)); will(returnValue(metadata));
oneOf(metadataParser).parse(metadata); oneOf(metadataParser).parse(metadata);
will(returnValue(dictionary)); will(returnValue(dictionary));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
assertEquals(dictionary, assertEquals(dictionary,
@@ -145,12 +153,15 @@ public class ClientHelperImplTest extends BrambleTestCase {
public void testGetMessageMetadataAsDictionary() throws Exception { public void testGetMessageMetadataAsDictionary() throws Exception {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessageMetadata(txn, messageId); oneOf(db).getMessageMetadata(txn, messageId);
will(returnValue(metadata)); will(returnValue(metadata));
oneOf(metadataParser).parse(metadata); oneOf(metadataParser).parse(metadata);
will(returnValue(dictionary)); will(returnValue(dictionary));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
assertEquals(dictionary, assertEquals(dictionary,
@@ -164,12 +175,15 @@ public class ClientHelperImplTest extends BrambleTestCase {
map.put(messageId, dictionary); map.put(messageId, dictionary);
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessageMetadata(txn, groupId); oneOf(db).getMessageMetadata(txn, groupId);
will(returnValue(Collections.singletonMap(messageId, metadata))); will(returnValue(Collections.singletonMap(messageId, metadata)));
oneOf(metadataParser).parse(metadata); oneOf(metadataParser).parse(metadata);
will(returnValue(dictionary)); will(returnValue(dictionary));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
assertEquals(map, clientHelper.getMessageMetadataAsDictionary(groupId)); assertEquals(map, clientHelper.getMessageMetadataAsDictionary(groupId));
@@ -186,14 +200,17 @@ public class ClientHelperImplTest extends BrambleTestCase {
queryMetadata.put("query", getRandomBytes(42)); queryMetadata.put("query", getRandomBytes(42));
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(metadataEncoder).encode(query); oneOf(metadataEncoder).encode(query);
will(returnValue(queryMetadata)); will(returnValue(queryMetadata));
oneOf(db).getMessageMetadata(txn, groupId, queryMetadata); oneOf(db).getMessageMetadata(txn, groupId, queryMetadata);
will(returnValue(Collections.singletonMap(messageId, metadata))); will(returnValue(Collections.singletonMap(messageId, metadata)));
oneOf(metadataParser).parse(metadata); oneOf(metadataParser).parse(metadata);
will(returnValue(dictionary)); will(returnValue(dictionary));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
assertEquals(map, assertEquals(map,
@@ -205,11 +222,14 @@ public class ClientHelperImplTest extends BrambleTestCase {
public void testMergeGroupMetadata() throws Exception { public void testMergeGroupMetadata() throws Exception {
Transaction txn = new Transaction(null, false); Transaction txn = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
oneOf(metadataEncoder).encode(dictionary); oneOf(metadataEncoder).encode(dictionary);
will(returnValue(metadata)); will(returnValue(metadata));
oneOf(db).mergeGroupMetadata(txn, groupId, metadata); oneOf(db).mergeGroupMetadata(txn, groupId, metadata);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
clientHelper.mergeGroupMetadata(groupId, dictionary); clientHelper.mergeGroupMetadata(groupId, dictionary);
@@ -220,11 +240,14 @@ public class ClientHelperImplTest extends BrambleTestCase {
public void testMergeMessageMetadata() throws Exception { public void testMergeMessageMetadata() throws Exception {
Transaction txn = new Transaction(null, false); Transaction txn = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
oneOf(metadataEncoder).encode(dictionary); oneOf(metadataEncoder).encode(dictionary);
will(returnValue(metadata)); will(returnValue(metadata));
oneOf(db).mergeMessageMetadata(txn, messageId, metadata); oneOf(db).mergeMessageMetadata(txn, messageId, metadata);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
clientHelper.mergeMessageMetadata(messageId, dictionary); clientHelper.mergeMessageMetadata(messageId, dictionary);

View File

@@ -69,14 +69,17 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
boolean alice = new Random().nextBoolean(); boolean alice = new Random().nextBoolean();
Transaction txn = new Transaction(null, false); Transaction txn = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(false), withDbCallable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
oneOf(db).addContact(txn, remote, local, verified, active); oneOf(db).addContact(txn, remote, local, verified, active);
will(returnValue(contactId)); will(returnValue(contactId));
oneOf(keyManager).addContact(txn, contactId, master, timestamp, oneOf(keyManager).addContact(txn, contactId, master, timestamp,
alice, active); alice, active);
oneOf(db).getContact(txn, contactId); oneOf(db).getContact(txn, contactId);
will(returnValue(contact)); will(returnValue(contact));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
assertEquals(contactId, contactManager.addContact(remote, local, assertEquals(contactId, contactManager.addContact(remote, local,
@@ -86,10 +89,13 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
@Test @Test
public void testGetContact() throws Exception { public void testGetContact() throws Exception {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getContact(txn, contactId); oneOf(db).getContact(txn, contactId);
will(returnValue(contact)); will(returnValue(contact));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
assertEquals(contact, contactManager.getContact(contactId)); assertEquals(contact, contactManager.getContact(contactId));
@@ -99,10 +105,13 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
public void testGetContactByAuthor() throws Exception { public void testGetContactByAuthor() throws Exception {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
Collection<Contact> contacts = Collections.singleton(contact); Collection<Contact> contacts = Collections.singleton(contact);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getContactsByAuthorId(txn, remote.getId()); oneOf(db).getContactsByAuthorId(txn, remote.getId());
will(returnValue(contacts)); will(returnValue(contacts));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
assertEquals(contact, contactManager.getContact(remote.getId(), local)); assertEquals(contact, contactManager.getContact(remote.getId(), local));
@@ -111,10 +120,12 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
@Test(expected = NoSuchContactException.class) @Test(expected = NoSuchContactException.class)
public void testGetContactByUnknownAuthor() throws Exception { public void testGetContactByUnknownAuthor() throws Exception {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getContactsByAuthorId(txn, remote.getId()); oneOf(db).getContactsByAuthorId(txn, remote.getId());
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).endTransaction(txn);
}}); }});
contactManager.getContact(remote.getId(), local); contactManager.getContact(remote.getId(), local);
@@ -124,26 +135,31 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
public void testGetContactByUnknownLocalAuthor() throws Exception { public void testGetContactByUnknownLocalAuthor() throws Exception {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
Collection<Contact> contacts = Collections.singleton(contact); Collection<Contact> contacts = Collections.singleton(contact);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getContactsByAuthorId(txn, remote.getId()); oneOf(db).getContactsByAuthorId(txn, remote.getId());
will(returnValue(contacts)); will(returnValue(contacts));
oneOf(db).endTransaction(txn);
}}); }});
contactManager.getContact(remote.getId(), new AuthorId(getRandomId())); contactManager.getContact(remote.getId(), new AuthorId(getRandomId()));
} }
@Test @Test
public void testGetActiveContacts() throws Exception { public void testActiveContacts() throws Exception {
Collection<Contact> activeContacts = Collections.singletonList(contact); Collection<Contact> activeContacts = Collections.singletonList(contact);
Collection<Contact> contacts = new ArrayList<>(activeContacts); Collection<Contact> contacts = new ArrayList<>(activeContacts);
contacts.add(new Contact(new ContactId(3), remote, local, alias, true, contacts.add(new Contact(new ContactId(3), remote, local, alias, true,
false)); false));
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getContacts(txn); oneOf(db).getContacts(txn);
will(returnValue(contacts)); will(returnValue(contacts));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
assertEquals(activeContacts, contactManager.getActiveContacts()); assertEquals(activeContacts, contactManager.getActiveContacts());
@@ -152,11 +168,14 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
@Test @Test
public void testRemoveContact() throws Exception { public void testRemoveContact() throws Exception {
Transaction txn = new Transaction(null, false); Transaction txn = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
oneOf(db).getContact(txn, contactId); oneOf(db).getContact(txn, contactId);
will(returnValue(contact)); will(returnValue(contact));
oneOf(db).removeContact(txn, contactId); oneOf(db).removeContact(txn, contactId);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
contactManager.removeContact(contactId); contactManager.removeContact(contactId);
@@ -176,7 +195,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
public void testSetContactAlias() throws Exception { public void testSetContactAlias() throws Exception {
Transaction txn = new Transaction(null, false); Transaction txn = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new DbExpectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).transaction(with(equal(false)), withDbRunnable(txn));
oneOf(db).setContactAlias(txn, contactId, alias); oneOf(db).setContactAlias(txn, contactId, alias);
}}); }});
@@ -185,32 +204,35 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void testSetContactAliasTooLong() throws Exception { public void testSetContactAliasTooLong() throws Exception {
Transaction txn = new Transaction(null, false); contactManager.setContactAlias(contactId,
contactManager.setContactAlias(txn, contactId,
getRandomString(MAX_AUTHOR_NAME_LENGTH + 1)); getRandomString(MAX_AUTHOR_NAME_LENGTH + 1));
} }
@Test @Test
public void testContactExists() throws Exception { public void testContactExists() throws Exception {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).containsContact(txn, remote.getId(), local); oneOf(db).containsContact(txn, remote.getId(), local);
will(returnValue(true)); will(returnValue(true));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
assertTrue(contactManager.contactExists(remote.getId(), local)); assertTrue(contactManager.contactExists(remote.getId(), local));
} }
@Test @Test
public void testGetAuthorInfo() throws Exception { public void testGetAuthorStatus() throws Exception {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
Collection<Contact> contacts = singletonList( Collection<Contact> contacts = singletonList(
new Contact(new ContactId(1), remote, localAuthor.getId(), new Contact(new ContactId(1), remote, localAuthor.getId(),
alias, false, true)); alias, false, true));
context.checking(new DbExpectations() {{ context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).transactionWithResult(with(equal(true)),
withDbCallable(txn));
oneOf(identityManager).getLocalAuthor(txn); oneOf(identityManager).getLocalAuthor(txn);
will(returnValue(localAuthor)); will(returnValue(localAuthor));
oneOf(db).getContactsByAuthorId(txn, remote.getId()); oneOf(db).getContactsByAuthorId(txn, remote.getId());
@@ -223,7 +245,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
} }
@Test @Test
public void testGetAuthorInfoTransaction() throws DbException { public void testGetAuthorStatusTransaction() throws DbException {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
// check unknown author // check unknown author
@@ -242,7 +264,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
Collection<Contact> contacts = singletonList( Collection<Contact> contacts = singletonList(
new Contact(new ContactId(1), remote, localAuthor.getId(), new Contact(new ContactId(1), remote, localAuthor.getId(),
alias, false, true)); alias, false, true));
checkAuthorInfoContext(txn, remote.getId(), contacts); checkAuthorStatusContext(txn, remote.getId(), contacts);
authorInfo = contactManager.getAuthorInfo(txn, remote.getId()); authorInfo = contactManager.getAuthorInfo(txn, remote.getId());
assertEquals(UNVERIFIED, authorInfo.getStatus()); assertEquals(UNVERIFIED, authorInfo.getStatus());
assertEquals(alias, contact.getAlias()); assertEquals(alias, contact.getAlias());
@@ -250,7 +272,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
// check verified contact // check verified contact
contacts = singletonList(new Contact(new ContactId(1), remote, contacts = singletonList(new Contact(new ContactId(1), remote,
localAuthor.getId(), alias, true, true)); localAuthor.getId(), alias, true, true));
checkAuthorInfoContext(txn, remote.getId(), contacts); checkAuthorStatusContext(txn, remote.getId(), contacts);
authorInfo = contactManager.getAuthorInfo(txn, remote.getId()); authorInfo = contactManager.getAuthorInfo(txn, remote.getId());
assertEquals(VERIFIED, authorInfo.getStatus()); assertEquals(VERIFIED, authorInfo.getStatus());
assertEquals(alias, contact.getAlias()); assertEquals(alias, contact.getAlias());
@@ -266,7 +288,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
assertNull(authorInfo.getAlias()); assertNull(authorInfo.getAlias());
} }
private void checkAuthorInfoContext(Transaction txn, AuthorId authorId, private void checkAuthorStatusContext(Transaction txn, AuthorId authorId,
Collection<Contact> contacts) throws DbException { Collection<Contact> contacts) throws DbException {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(identityManager).getLocalAuthor(txn); oneOf(identityManager).getLocalAuthor(txn);

View File

@@ -1,41 +0,0 @@
package org.briarproject.bramble.data;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.util.Random;
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_NESTED_LIMIT;
import static org.briarproject.bramble.test.TestUtils.isOptionalTestEnabled;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
public class BdfReaderImplFuzzingTest extends BrambleTestCase {
@Before
public void setUp() {
assumeTrue(isOptionalTestEnabled(BdfReaderImplFuzzingTest.class));
}
@Test
public void testStringFuzzing() throws Exception {
Random random = new Random();
byte[] buf = new byte[22];
ByteArrayInputStream in = new ByteArrayInputStream(buf);
for (int i = 0; i < 100_000_000; i++) {
random.nextBytes(buf);
buf[0] = 0x41; // String with 1-byte length
buf[1] = 0x14; // Length 20 bytes
in.reset();
BdfReaderImpl r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
DEFAULT_MAX_BUFFER_SIZE);
int length = r.readString().length();
assertTrue(length >= 0);
assertTrue(length <= 20);
assertTrue(r.eof());
}
}
}

View File

@@ -11,7 +11,6 @@ import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -65,10 +64,13 @@ public class IdentityManagerImplTest extends BrambleMockTestCase {
} }
@Test @Test
public void testRegisterAndStoreLocalAuthor() throws Exception { public void testRegisterAndStoreLocalAuthor() throws DbException {
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
oneOf(db).addLocalAuthor(txn, localAuthor); oneOf(db).addLocalAuthor(txn, localAuthor);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
identityManager.registerLocalAuthor(localAuthor); identityManager.registerLocalAuthor(localAuthor);
@@ -77,11 +79,14 @@ public class IdentityManagerImplTest extends BrambleMockTestCase {
} }
@Test @Test
public void testGetLocalAuthor() throws Exception { public void testGetLocalAuthor() throws DbException {
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getLocalAuthors(txn); oneOf(db).getLocalAuthors(txn);
will(returnValue(localAuthors)); will(returnValue(localAuthors));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
assertEquals(localAuthor, identityManager.getLocalAuthor()); assertEquals(localAuthor, identityManager.getLocalAuthor());
} }

View File

@@ -21,18 +21,16 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.junit.Test; import org.junit.Test;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.briarproject.bramble.api.properties.TransportPropertyManager.CLIENT_ID; import static org.briarproject.bramble.api.properties.TransportPropertyManager.CLIENT_ID;
import static org.briarproject.bramble.api.properties.TransportPropertyManager.MAJOR_VERSION; import static org.briarproject.bramble.api.properties.TransportPropertyManager.MAJOR_VERSION;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
@@ -353,11 +351,14 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
new BdfEntry("local", true) new BdfEntry("local", true)
)); ));
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
TransportPropertyManagerImpl t = createInstance(); TransportPropertyManagerImpl t = createInstance();
@@ -385,8 +386,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
)); ));
BdfList fooUpdate = BdfList.of("foo", 1, fooPropertiesDict); BdfList fooUpdate = BdfList.of("foo", 1, fooPropertiesDict);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
@@ -395,6 +397,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
will(returnValue(fooProperties)); will(returnValue(fooProperties));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
TransportPropertyManagerImpl t = createInstance(); TransportPropertyManagerImpl t = createInstance();
@@ -409,7 +413,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
Contact contact1 = getContact(false); Contact contact1 = getContact(false);
Contact contact2 = getContact(true); Contact contact2 = getContact(true);
Contact contact3 = getContact(true); Contact contact3 = getContact(true);
List<Contact> contacts = asList(contact1, contact2, contact3); List<Contact> contacts =
Arrays.asList(contact1, contact2, contact3);
Group contactGroup2 = getGroup(CLIENT_ID, MAJOR_VERSION); Group contactGroup2 = getGroup(CLIENT_ID, MAJOR_VERSION);
Group contactGroup3 = getGroup(CLIENT_ID, MAJOR_VERSION); Group contactGroup3 = getGroup(CLIENT_ID, MAJOR_VERSION);
Map<MessageId, BdfDictionary> messageMetadata3 = Map<MessageId, BdfDictionary> messageMetadata3 =
@@ -437,8 +442,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
)); ));
BdfList fooUpdate = BdfList.of("foo", 1, fooPropertiesDict); BdfList fooUpdate = BdfList.of("foo", 1, fooPropertiesDict);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getContacts(txn); oneOf(db).getContacts(txn);
will(returnValue(contacts)); will(returnValue(contacts));
// First contact: skipped because not active // First contact: skipped because not active
@@ -461,6 +467,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
will(returnValue(fooProperties)); will(returnValue(fooProperties));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
TransportPropertyManagerImpl t = createInstance(); TransportPropertyManagerImpl t = createInstance();
@@ -477,16 +485,17 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
throws Exception { throws Exception {
Transaction txn = new Transaction(null, false); Transaction txn = new Transaction(null, false);
MessageId updateId = new MessageId(getRandomId()); MessageId updateId = new MessageId(getRandomId());
Map<MessageId, BdfDictionary> messageMetadata = singletonMap(updateId, Map<MessageId, BdfDictionary> messageMetadata =
BdfDictionary.of( Collections.singletonMap(updateId, BdfDictionary.of(
new BdfEntry("transportId", "foo"), new BdfEntry("transportId", "foo"),
new BdfEntry("version", 1), new BdfEntry("version", 1),
new BdfEntry("local", true) new BdfEntry("local", true)
)); ));
BdfList update = BdfList.of("foo", 1, fooPropertiesDict); BdfList update = BdfList.of("foo", 1, fooPropertiesDict);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
// Merge the new properties with the existing properties // Merge the new properties with the existing properties
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
@@ -497,6 +506,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
fooPropertiesDict); fooPropertiesDict);
will(returnValue(fooProperties)); will(returnValue(fooProperties));
// Properties are unchanged so we're done // Properties are unchanged so we're done
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
TransportPropertyManagerImpl t = createInstance(); TransportPropertyManagerImpl t = createInstance();
@@ -509,8 +520,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
Contact contact = getContact(true); Contact contact = getContact(true);
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION); Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
// There are no existing properties to merge with // There are no existing properties to merge with
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
@@ -529,6 +541,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
will(returnValue(Collections.emptyMap())); will(returnValue(Collections.emptyMap()));
expectStoreMessage(txn, contactGroup.getId(), "foo", expectStoreMessage(txn, contactGroup.getId(), "foo",
fooPropertiesDict, 1, true, true); fooPropertiesDict, 1, true, true);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
TransportPropertyManagerImpl t = createInstance(); TransportPropertyManagerImpl t = createInstance();
@@ -547,10 +561,10 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
); );
MessageId localGroupUpdateId = new MessageId(getRandomId()); MessageId localGroupUpdateId = new MessageId(getRandomId());
Map<MessageId, BdfDictionary> localGroupMessageMetadata = Map<MessageId, BdfDictionary> localGroupMessageMetadata =
singletonMap(localGroupUpdateId, oldMetadata); Collections.singletonMap(localGroupUpdateId, oldMetadata);
MessageId contactGroupUpdateId = new MessageId(getRandomId()); MessageId contactGroupUpdateId = new MessageId(getRandomId());
Map<MessageId, BdfDictionary> contactGroupMessageMetadata = Map<MessageId, BdfDictionary> contactGroupMessageMetadata =
singletonMap(contactGroupUpdateId, oldMetadata); Collections.singletonMap(contactGroupUpdateId, oldMetadata);
TransportProperties oldProperties = new TransportProperties(); TransportProperties oldProperties = new TransportProperties();
oldProperties.put("fooKey1", "oldFooValue1"); oldProperties.put("fooKey1", "oldFooValue1");
BdfDictionary oldPropertiesDict = BdfDictionary.of( BdfDictionary oldPropertiesDict = BdfDictionary.of(
@@ -558,8 +572,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
); );
BdfList oldUpdate = BdfList.of("foo", 1, oldPropertiesDict); BdfList oldUpdate = BdfList.of("foo", 1, oldPropertiesDict);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
// Merge the new properties with the existing properties // Merge the new properties with the existing properties
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
@@ -587,6 +602,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
fooPropertiesDict, 2, true, true); fooPropertiesDict, 2, true, true);
// Delete the previous update // Delete the previous update
oneOf(db).removeMessage(txn, contactGroupUpdateId); oneOf(db).removeMessage(txn, contactGroupUpdateId);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
TransportPropertyManagerImpl t = createInstance(); TransportPropertyManagerImpl t = createInstance();

View File

@@ -11,8 +11,8 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.SyncRecordWriter; import org.briarproject.bramble.api.sync.SyncRecordWriter;
import org.briarproject.bramble.api.transport.StreamWriter; import org.briarproject.bramble.api.transport.StreamWriter;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.briarproject.bramble.test.ImmediateExecutor; import org.briarproject.bramble.test.ImmediateExecutor;
import org.jmock.Expectations;
import org.junit.Test; import org.junit.Test;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -45,20 +45,24 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
Transaction noAckTxn = new Transaction(null, false); Transaction noAckTxn = new Transaction(null, false);
Transaction noMsgTxn = new Transaction(null, false); Transaction noMsgTxn = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Add listener // Add listener
oneOf(eventBus).addListener(session); oneOf(eventBus).addListener(session);
// No acks to send // No acks to send
oneOf(db).transactionWithNullableResult(with(false), oneOf(db).startTransaction(false);
withNullableDbCallable(noAckTxn)); will(returnValue(noAckTxn));
oneOf(db).generateAck(noAckTxn, contactId, MAX_MESSAGE_IDS); oneOf(db).generateAck(noAckTxn, contactId, MAX_MESSAGE_IDS);
will(returnValue(null)); will(returnValue(null));
oneOf(db).commitTransaction(noAckTxn);
oneOf(db).endTransaction(noAckTxn);
// No messages to send // No messages to send
oneOf(db).transactionWithNullableResult(with(false), oneOf(db).startTransaction(false);
withNullableDbCallable(noMsgTxn)); will(returnValue(noMsgTxn));
oneOf(db).generateBatch(with(noMsgTxn), with(contactId), oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY)); with(any(int.class)), with(MAX_LATENCY));
will(returnValue(null)); will(returnValue(null));
oneOf(db).commitTransaction(noMsgTxn);
oneOf(db).endTransaction(noMsgTxn);
// Send the end of stream marker // Send the end of stream marker
oneOf(streamWriter).sendEndOfStream(); oneOf(streamWriter).sendEndOfStream();
// Remove listener // Remove listener
@@ -79,33 +83,41 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
Transaction msgTxn = new Transaction(null, false); Transaction msgTxn = new Transaction(null, false);
Transaction noMsgTxn = new Transaction(null, false); Transaction noMsgTxn = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Add listener // Add listener
oneOf(eventBus).addListener(session); oneOf(eventBus).addListener(session);
// One ack to send // One ack to send
oneOf(db).transactionWithNullableResult(with(false), oneOf(db).startTransaction(false);
withNullableDbCallable(ackTxn)); will(returnValue(ackTxn));
oneOf(db).generateAck(ackTxn, contactId, MAX_MESSAGE_IDS); oneOf(db).generateAck(ackTxn, contactId, MAX_MESSAGE_IDS);
will(returnValue(ack)); will(returnValue(ack));
oneOf(db).commitTransaction(ackTxn);
oneOf(db).endTransaction(ackTxn);
oneOf(recordWriter).writeAck(ack); oneOf(recordWriter).writeAck(ack);
// One message to send // One message to send
oneOf(db).transactionWithNullableResult(with(false), oneOf(db).startTransaction(false);
withNullableDbCallable(msgTxn)); will(returnValue(msgTxn));
oneOf(db).generateBatch(with(msgTxn), with(contactId), oneOf(db).generateBatch(with(msgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY)); with(any(int.class)), with(MAX_LATENCY));
will(returnValue(singletonList(message))); will(returnValue(singletonList(message)));
oneOf(db).commitTransaction(msgTxn);
oneOf(db).endTransaction(msgTxn);
oneOf(recordWriter).writeMessage(message); oneOf(recordWriter).writeMessage(message);
// No more acks // No more acks
oneOf(db).transactionWithNullableResult(with(false), oneOf(db).startTransaction(false);
withNullableDbCallable(noAckTxn)); will(returnValue(noAckTxn));
oneOf(db).generateAck(noAckTxn, contactId, MAX_MESSAGE_IDS); oneOf(db).generateAck(noAckTxn, contactId, MAX_MESSAGE_IDS);
will(returnValue(null)); will(returnValue(null));
oneOf(db).commitTransaction(noAckTxn);
oneOf(db).endTransaction(noAckTxn);
// No more messages // No more messages
oneOf(db).transactionWithNullableResult(with(false), oneOf(db).startTransaction(false);
withNullableDbCallable(noMsgTxn)); will(returnValue(noMsgTxn));
oneOf(db).generateBatch(with(noMsgTxn), with(contactId), oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY)); with(any(int.class)), with(MAX_LATENCY));
will(returnValue(null)); will(returnValue(null));
oneOf(db).commitTransaction(noMsgTxn);
oneOf(db).endTransaction(noMsgTxn);
// Send the end of stream marker // Send the end of stream marker
oneOf(streamWriter).sendEndOfStream(); oneOf(streamWriter).sendEndOfStream();
// Remove listener // Remove listener

View File

@@ -18,16 +18,16 @@ import org.briarproject.bramble.api.sync.ValidationManager.MessageValidator;
import org.briarproject.bramble.api.sync.ValidationManager.State; import org.briarproject.bramble.api.sync.ValidationManager.State;
import org.briarproject.bramble.api.sync.event.MessageAddedEvent; import org.briarproject.bramble.api.sync.event.MessageAddedEvent;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.briarproject.bramble.test.ImmediateExecutor; import org.briarproject.bramble.test.ImmediateExecutor;
import org.jmock.Expectations;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import java.util.Arrays;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap; import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
@@ -83,19 +83,28 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn1 = new Transaction(null, true); Transaction txn1 = new Transaction(null, true);
Transaction txn2 = new Transaction(null, true); Transaction txn2 = new Transaction(null, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// validateOutstandingMessages() // validateOutstandingMessages()
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessagesToValidate(txn); oneOf(db).getMessagesToValidate(txn);
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// deliverOutstandingMessages() // deliverOutstandingMessages()
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1)); oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getPendingMessages(txn1); oneOf(db).getPendingMessages(txn1);
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// shareOutstandingMessages() // shareOutstandingMessages()
oneOf(db).transactionWithResult(with(true), withDbCallable(txn2)); oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).getMessagesToShare(txn2); oneOf(db).getMessagesToShare(txn2);
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}}); }});
vm.startService(); vm.startService();
@@ -112,22 +121,29 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn5 = new Transaction(null, true); Transaction txn5 = new Transaction(null, true);
Transaction txn6 = new Transaction(null, true); Transaction txn6 = new Transaction(null, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Get messages to validate // Get messages to validate
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessagesToValidate(txn); oneOf(db).getMessagesToValidate(txn);
will(returnValue(asList(messageId, messageId1))); will(returnValue(Arrays.asList(messageId, messageId1)));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Load the first raw message and group // Load the first raw message and group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1)); oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getMessage(txn1, messageId); oneOf(db).getMessage(txn1, messageId);
will(returnValue(message)); will(returnValue(message));
oneOf(db).getGroup(txn1, groupId); oneOf(db).getGroup(txn1, groupId);
will(returnValue(group)); will(returnValue(group));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Validate the first message: valid // Validate the first message: valid
oneOf(validator).validateMessage(message, group); oneOf(validator).validateMessage(message, group);
will(returnValue(validResult)); will(returnValue(validResult));
// Store the validation result for the first message // Store the validation result for the first message
oneOf(db).transaction(with(false), withDbRunnable(txn2)); oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).mergeMessageMetadata(txn2, messageId, metadata); oneOf(db).mergeMessageMetadata(txn2, messageId, metadata);
// Deliver the first message // Deliver the first message
oneOf(hook).incomingMessage(txn2, message, metadata); oneOf(hook).incomingMessage(txn2, message, metadata);
@@ -136,17 +152,23 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Get any pending dependents // Get any pending dependents
oneOf(db).getMessageDependents(txn2, messageId); oneOf(db).getMessageDependents(txn2, messageId);
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Load the second raw message and group // Load the second raw message and group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn3)); oneOf(db).startTransaction(true);
will(returnValue(txn3));
oneOf(db).getMessage(txn3, messageId1); oneOf(db).getMessage(txn3, messageId1);
will(returnValue(message1)); will(returnValue(message1));
oneOf(db).getGroup(txn3, groupId); oneOf(db).getGroup(txn3, groupId);
will(returnValue(group)); will(returnValue(group));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Validate the second message: invalid // Validate the second message: invalid
oneOf(validator).validateMessage(message1, group); oneOf(validator).validateMessage(message1, group);
will(throwException(new InvalidMessageException())); will(throwException(new InvalidMessageException()));
// Store the validation result for the second message // Store the validation result for the second message
oneOf(db).transaction(with(false), withDbRunnable(txn4)); oneOf(db).startTransaction(false);
will(returnValue(txn4));
oneOf(db).getMessageState(txn4, messageId1); oneOf(db).getMessageState(txn4, messageId1);
will(returnValue(UNKNOWN)); will(returnValue(UNKNOWN));
oneOf(db).setMessageState(txn4, messageId1, INVALID); oneOf(db).setMessageState(txn4, messageId1, INVALID);
@@ -155,14 +177,22 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Recursively invalidate any dependents // Recursively invalidate any dependents
oneOf(db).getMessageDependents(txn4, messageId1); oneOf(db).getMessageDependents(txn4, messageId1);
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Get pending messages to deliver // Get pending messages to deliver
oneOf(db).transactionWithResult(with(true), withDbCallable(txn5)); oneOf(db).startTransaction(true);
will(returnValue(txn5));
oneOf(db).getPendingMessages(txn5); oneOf(db).getPendingMessages(txn5);
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
// Get messages to share // Get messages to share
oneOf(db).transactionWithResult(with(true), withDbCallable(txn6)); oneOf(db).startTransaction(true);
will(returnValue(txn6));
oneOf(db).getMessagesToShare(txn6); oneOf(db).getMessagesToShare(txn6);
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn6);
oneOf(db).endTransaction(txn6);
}}); }});
vm.startService(); vm.startService();
@@ -176,17 +206,24 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn3 = new Transaction(null, false); Transaction txn3 = new Transaction(null, false);
Transaction txn4 = new Transaction(null, true); Transaction txn4 = new Transaction(null, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Get messages to validate // Get messages to validate
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessagesToValidate(txn); oneOf(db).getMessagesToValidate(txn);
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Get pending messages to deliver // Get pending messages to deliver
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1)); oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getPendingMessages(txn1); oneOf(db).getPendingMessages(txn1);
will(returnValue(singletonList(messageId))); will(returnValue(singletonList(messageId)));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Check whether the message is ready to deliver // Check whether the message is ready to deliver
oneOf(db).transaction(with(false), withDbRunnable(txn2)); oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).getMessageState(txn2, messageId); oneOf(db).getMessageState(txn2, messageId);
will(returnValue(PENDING)); will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn2, messageId); oneOf(db).getMessageDependencies(txn2, messageId);
@@ -205,8 +242,11 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Get any pending dependents // Get any pending dependents
oneOf(db).getMessageDependents(txn2, messageId); oneOf(db).getMessageDependents(txn2, messageId);
will(returnValue(singletonMap(messageId2, PENDING))); will(returnValue(singletonMap(messageId2, PENDING)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Check whether the dependent is ready to deliver // Check whether the dependent is ready to deliver
oneOf(db).transaction(with(false), withDbRunnable(txn3)); oneOf(db).startTransaction(false);
will(returnValue(txn3));
oneOf(db).getMessageState(txn3, messageId2); oneOf(db).getMessageState(txn3, messageId2);
will(returnValue(PENDING)); will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn3, messageId2); oneOf(db).getMessageDependencies(txn3, messageId2);
@@ -225,11 +265,16 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Get any pending dependents // Get any pending dependents
oneOf(db).getMessageDependents(txn3, messageId2); oneOf(db).getMessageDependents(txn3, messageId2);
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Get messages to share // Get messages to share
oneOf(db).transactionWithResult(with(true), withDbCallable(txn4)); oneOf(db).startTransaction(true);
will(returnValue(txn4));
oneOf(db).getMessagesToShare(txn4); oneOf(db).getMessagesToShare(txn4);
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
}}); }});
vm.startService(); vm.startService();
@@ -243,30 +288,45 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn3 = new Transaction(null, false); Transaction txn3 = new Transaction(null, false);
Transaction txn4 = new Transaction(null, false); Transaction txn4 = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// No messages to validate // No messages to validate
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessagesToValidate(txn); oneOf(db).getMessagesToValidate(txn);
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// No pending messages to deliver // No pending messages to deliver
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1)); oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getPendingMessages(txn1); oneOf(db).getPendingMessages(txn1);
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Get messages to share // Get messages to share
oneOf(db).transactionWithResult(with(true), withDbCallable(txn2)); oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).getMessagesToShare(txn2); oneOf(db).getMessagesToShare(txn2);
will(returnValue(singletonList(messageId))); will(returnValue(singletonList(messageId)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Share message and get dependencies // Share message and get dependencies
oneOf(db).transaction(with(false), withDbRunnable(txn3)); oneOf(db).startTransaction(false);
will(returnValue(txn3));
oneOf(db).setMessageShared(txn3, messageId); oneOf(db).setMessageShared(txn3, messageId);
oneOf(db).getMessageDependencies(txn3, messageId); oneOf(db).getMessageDependencies(txn3, messageId);
will(returnValue(singletonMap(messageId2, DELIVERED))); will(returnValue(singletonMap(messageId2, DELIVERED)));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Share dependency // Share dependency
oneOf(db).transaction(with(false), withDbRunnable(txn4)); oneOf(db).startTransaction(false);
will(returnValue(txn4));
oneOf(db).setMessageShared(txn4, messageId2); oneOf(db).setMessageShared(txn4, messageId2);
oneOf(db).getMessageDependencies(txn4, messageId2); oneOf(db).getMessageDependencies(txn4, messageId2);
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
}}); }});
vm.startService(); vm.startService();
@@ -278,16 +338,20 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn1 = new Transaction(null, false); Transaction txn1 = new Transaction(null, false);
Transaction txn2 = new Transaction(null, false); Transaction txn2 = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Load the group // Load the group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getGroup(txn, groupId); oneOf(db).getGroup(txn, groupId);
will(returnValue(group)); will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid // Validate the message: valid
oneOf(validator).validateMessage(message, group); oneOf(validator).validateMessage(message, group);
will(returnValue(validResultWithDependencies)); will(returnValue(validResultWithDependencies));
// Store the validation result // Store the validation result
oneOf(db).transaction(with(false), withDbRunnable(txn1)); oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).addMessageDependencies(txn1, message, oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies()); validResultWithDependencies.getDependencies());
oneOf(db).getMessageDependencies(txn1, messageId); oneOf(db).getMessageDependencies(txn1, messageId);
@@ -302,11 +366,16 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
// Share message // Share message
oneOf(db).setMessageShared(txn1, messageId); oneOf(db).setMessageShared(txn1, messageId);
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Share dependencies // Share dependencies
oneOf(db).transaction(with(false), withDbRunnable(txn2)); oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).setMessageShared(txn2, messageId1); oneOf(db).setMessageShared(txn2, messageId1);
oneOf(db).getMessageDependencies(txn2, messageId1); oneOf(db).getMessageDependencies(txn2, messageId1);
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}}); }});
vm.eventOccurred(new MessageAddedEvent(message, contactId)); vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -322,26 +391,36 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn4 = new Transaction(null, true); Transaction txn4 = new Transaction(null, true);
Transaction txn5 = new Transaction(null, true); Transaction txn5 = new Transaction(null, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Get messages to validate // Get messages to validate
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessagesToValidate(txn); oneOf(db).getMessagesToValidate(txn);
will(returnValue(asList(messageId, messageId1))); will(returnValue(Arrays.asList(messageId, messageId1)));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Load the first raw message - *gasp* it's gone! // Load the first raw message - *gasp* it's gone!
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1)); oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getMessage(txn1, messageId); oneOf(db).getMessage(txn1, messageId);
will(throwException(new NoSuchMessageException())); will(throwException(new NoSuchMessageException()));
never(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Load the second raw message and group // Load the second raw message and group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn2)); oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).getMessage(txn2, messageId1); oneOf(db).getMessage(txn2, messageId1);
will(returnValue(message1)); will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId); oneOf(db).getGroup(txn2, groupId);
will(returnValue(group)); will(returnValue(group));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Validate the second message: invalid // Validate the second message: invalid
oneOf(validator).validateMessage(message1, group); oneOf(validator).validateMessage(message1, group);
will(throwException(new InvalidMessageException())); will(throwException(new InvalidMessageException()));
// Invalidate the second message // Invalidate the second message
oneOf(db).transaction(with(false), withDbRunnable(txn3)); oneOf(db).startTransaction(false);
will(returnValue(txn3));
oneOf(db).getMessageState(txn3, messageId1); oneOf(db).getMessageState(txn3, messageId1);
will(returnValue(UNKNOWN)); will(returnValue(UNKNOWN));
oneOf(db).setMessageState(txn3, messageId1, INVALID); oneOf(db).setMessageState(txn3, messageId1, INVALID);
@@ -350,14 +429,22 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Recursively invalidate dependents // Recursively invalidate dependents
oneOf(db).getMessageDependents(txn3, messageId1); oneOf(db).getMessageDependents(txn3, messageId1);
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Get pending messages to deliver // Get pending messages to deliver
oneOf(db).transactionWithResult(with(true), withDbCallable(txn4)); oneOf(db).startTransaction(true);
will(returnValue(txn4));
oneOf(db).getPendingMessages(txn4); oneOf(db).getPendingMessages(txn4);
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Get messages to share // Get messages to share
oneOf(db).transactionWithResult(with(true), withDbCallable(txn5)); oneOf(db).startTransaction(true);
will(returnValue(txn5));
oneOf(db).getMessagesToShare(txn5); oneOf(db).getMessagesToShare(txn5);
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
}}); }});
vm.startService(); vm.startService();
@@ -373,29 +460,39 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn4 = new Transaction(null, true); Transaction txn4 = new Transaction(null, true);
Transaction txn5 = new Transaction(null, true); Transaction txn5 = new Transaction(null, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Get messages to validate // Get messages to validate
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessagesToValidate(txn); oneOf(db).getMessagesToValidate(txn);
will(returnValue(asList(messageId, messageId1))); will(returnValue(Arrays.asList(messageId, messageId1)));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Load the first raw message // Load the first raw message
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1)); oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getMessage(txn1, messageId); oneOf(db).getMessage(txn1, messageId);
will(returnValue(message)); will(returnValue(message));
// Load the group - *gasp* it's gone! // Load the group - *gasp* it's gone!
oneOf(db).getGroup(txn1, groupId); oneOf(db).getGroup(txn1, groupId);
will(throwException(new NoSuchGroupException())); will(throwException(new NoSuchGroupException()));
never(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Load the second raw message and group // Load the second raw message and group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn2)); oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).getMessage(txn2, messageId1); oneOf(db).getMessage(txn2, messageId1);
will(returnValue(message1)); will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId); oneOf(db).getGroup(txn2, groupId);
will(returnValue(group)); will(returnValue(group));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Validate the second message: invalid // Validate the second message: invalid
oneOf(validator).validateMessage(message1, group); oneOf(validator).validateMessage(message1, group);
will(throwException(new InvalidMessageException())); will(throwException(new InvalidMessageException()));
// Store the validation result for the second message // Store the validation result for the second message
oneOf(db).transaction(with(false), withDbRunnable(txn3)); oneOf(db).startTransaction(false);
will(returnValue(txn3));
oneOf(db).getMessageState(txn3, messageId1); oneOf(db).getMessageState(txn3, messageId1);
will(returnValue(UNKNOWN)); will(returnValue(UNKNOWN));
oneOf(db).setMessageState(txn3, messageId1, INVALID); oneOf(db).setMessageState(txn3, messageId1, INVALID);
@@ -404,14 +501,22 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Recursively invalidate dependents // Recursively invalidate dependents
oneOf(db).getMessageDependents(txn3, messageId1); oneOf(db).getMessageDependents(txn3, messageId1);
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Get pending messages to deliver // Get pending messages to deliver
oneOf(db).transactionWithResult(with(true), withDbCallable(txn4)); oneOf(db).startTransaction(true);
will(returnValue(txn4));
oneOf(db).getPendingMessages(txn4); oneOf(db).getPendingMessages(txn4);
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Get messages to share // Get messages to share
oneOf(db).transactionWithResult(with(true), withDbCallable(txn5)); oneOf(db).startTransaction(true);
will(returnValue(txn5));
oneOf(db).getMessagesToShare(txn5); oneOf(db).getMessagesToShare(txn5);
will(returnValue(emptyList())); will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
}}); }});
vm.startService(); vm.startService();
@@ -422,16 +527,20 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
Transaction txn1 = new Transaction(null, false); Transaction txn1 = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Load the group // Load the group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getGroup(txn, groupId); oneOf(db).getGroup(txn, groupId);
will(returnValue(group)); will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid // Validate the message: valid
oneOf(validator).validateMessage(message, group); oneOf(validator).validateMessage(message, group);
will(returnValue(validResult)); will(returnValue(validResult));
// Store the validation result // Store the validation result
oneOf(db).transaction(with(false), withDbRunnable(txn1)); oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata); oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
// Deliver the message // Deliver the message
oneOf(hook).incomingMessage(txn1, message, metadata); oneOf(hook).incomingMessage(txn1, message, metadata);
@@ -440,6 +549,8 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Get any pending dependents // Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId); oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
}}); }});
vm.eventOccurred(new MessageAddedEvent(message, contactId)); vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -456,22 +567,28 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
Transaction txn1 = new Transaction(null, false); Transaction txn1 = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Load the group // Load the group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getGroup(txn, groupId); oneOf(db).getGroup(txn, groupId);
will(returnValue(group)); will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid // Validate the message: valid
oneOf(validator).validateMessage(message, group); oneOf(validator).validateMessage(message, group);
will(returnValue(validResultWithDependencies)); will(returnValue(validResultWithDependencies));
// Store the validation result // Store the validation result
oneOf(db).transaction(with(false), withDbRunnable(txn1)); oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).addMessageDependencies(txn1, message, oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies()); validResultWithDependencies.getDependencies());
oneOf(db).getMessageDependencies(txn1, messageId); oneOf(db).getMessageDependencies(txn1, messageId);
will(returnValue(singletonMap(messageId1, UNKNOWN))); will(returnValue(singletonMap(messageId1, UNKNOWN)));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata); oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
oneOf(db).setMessageState(txn1, messageId, PENDING); oneOf(db).setMessageState(txn1, messageId, PENDING);
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
}}); }});
vm.eventOccurred(new MessageAddedEvent(message, contactId)); vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -483,16 +600,20 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
Transaction txn1 = new Transaction(null, false); Transaction txn1 = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Load the group // Load the group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getGroup(txn, groupId); oneOf(db).getGroup(txn, groupId);
will(returnValue(group)); will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid // Validate the message: valid
oneOf(validator).validateMessage(message, group); oneOf(validator).validateMessage(message, group);
will(returnValue(validResultWithDependencies)); will(returnValue(validResultWithDependencies));
// Store the validation result // Store the validation result
oneOf(db).transaction(with(false), withDbRunnable(txn1)); oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).addMessageDependencies(txn1, message, oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies()); validResultWithDependencies.getDependencies());
oneOf(db).getMessageDependencies(txn1, messageId); oneOf(db).getMessageDependencies(txn1, messageId);
@@ -505,6 +626,8 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Get any pending dependents // Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId); oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
}}); }});
vm.eventOccurred(new MessageAddedEvent(message, contactId)); vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -517,16 +640,20 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn1 = new Transaction(null, false); Transaction txn1 = new Transaction(null, false);
Transaction txn2 = new Transaction(null, false); Transaction txn2 = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Load the group // Load the group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getGroup(txn, groupId); oneOf(db).getGroup(txn, groupId);
will(returnValue(group)); will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid // Validate the message: valid
oneOf(validator).validateMessage(message, group); oneOf(validator).validateMessage(message, group);
will(returnValue(validResultWithDependencies)); will(returnValue(validResultWithDependencies));
// Store the validation result // Store the validation result
oneOf(db).transaction(with(false), withDbRunnable(txn1)); oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).addMessageDependencies(txn1, message, oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies()); validResultWithDependencies.getDependencies());
// Check for invalid dependencies // Check for invalid dependencies
@@ -541,8 +668,11 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Recursively invalidate dependents // Recursively invalidate dependents
oneOf(db).getMessageDependents(txn1, messageId); oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(singletonMap(messageId2, UNKNOWN))); will(returnValue(singletonMap(messageId2, UNKNOWN)));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Invalidate dependent in a new transaction // Invalidate dependent in a new transaction
oneOf(db).transaction(with(false), withDbRunnable(txn2)); oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).getMessageState(txn2, messageId2); oneOf(db).getMessageState(txn2, messageId2);
will(returnValue(UNKNOWN)); will(returnValue(UNKNOWN));
oneOf(db).setMessageState(txn2, messageId2, INVALID); oneOf(db).setMessageState(txn2, messageId2, INVALID);
@@ -550,6 +680,8 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn2, messageId2); oneOf(db).deleteMessageMetadata(txn2, messageId2);
oneOf(db).getMessageDependents(txn2, messageId2); oneOf(db).getMessageDependents(txn2, messageId2);
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}}); }});
vm.eventOccurred(new MessageAddedEvent(message, contactId)); vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -570,16 +702,20 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn5 = new Transaction(null, false); Transaction txn5 = new Transaction(null, false);
Transaction txn6 = new Transaction(null, false); Transaction txn6 = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Load the group // Load the group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getGroup(txn, groupId); oneOf(db).getGroup(txn, groupId);
will(returnValue(group)); will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: invalid // Validate the message: invalid
oneOf(validator).validateMessage(message, group); oneOf(validator).validateMessage(message, group);
will(throwException(new InvalidMessageException())); will(throwException(new InvalidMessageException()));
// Invalidate the message // Invalidate the message
oneOf(db).transaction(with(false), withDbRunnable(txn1)); oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).getMessageState(txn1, messageId); oneOf(db).getMessageState(txn1, messageId);
will(returnValue(UNKNOWN)); will(returnValue(UNKNOWN));
oneOf(db).setMessageState(txn1, messageId, INVALID); oneOf(db).setMessageState(txn1, messageId, INVALID);
@@ -588,8 +724,11 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// The message has two dependents: 1 and 2 // The message has two dependents: 1 and 2
oneOf(db).getMessageDependents(txn1, messageId); oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(twoDependents)); will(returnValue(twoDependents));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Invalidate message 1 // Invalidate message 1
oneOf(db).transaction(with(false), withDbRunnable(txn2)); oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).getMessageState(txn2, messageId1); oneOf(db).getMessageState(txn2, messageId1);
will(returnValue(PENDING)); will(returnValue(PENDING));
oneOf(db).setMessageState(txn2, messageId1, INVALID); oneOf(db).setMessageState(txn2, messageId1, INVALID);
@@ -598,8 +737,11 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 1 has one dependent: 3 // Message 1 has one dependent: 3
oneOf(db).getMessageDependents(txn2, messageId1); oneOf(db).getMessageDependents(txn2, messageId1);
will(returnValue(singletonMap(messageId3, PENDING))); will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Invalidate message 2 // Invalidate message 2
oneOf(db).transaction(with(false), withDbRunnable(txn3)); oneOf(db).startTransaction(false);
will(returnValue(txn3));
oneOf(db).getMessageState(txn3, messageId2); oneOf(db).getMessageState(txn3, messageId2);
will(returnValue(PENDING)); will(returnValue(PENDING));
oneOf(db).setMessageState(txn3, messageId2, INVALID); oneOf(db).setMessageState(txn3, messageId2, INVALID);
@@ -608,8 +750,11 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 2 has one dependent: 3 (same dependent as 1) // Message 2 has one dependent: 3 (same dependent as 1)
oneOf(db).getMessageDependents(txn3, messageId2); oneOf(db).getMessageDependents(txn3, messageId2);
will(returnValue(singletonMap(messageId3, PENDING))); will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Invalidate message 3 (via 1) // Invalidate message 3 (via 1)
oneOf(db).transaction(with(false), withDbRunnable(txn4)); oneOf(db).startTransaction(false);
will(returnValue(txn4));
oneOf(db).getMessageState(txn4, messageId3); oneOf(db).getMessageState(txn4, messageId3);
will(returnValue(PENDING)); will(returnValue(PENDING));
oneOf(db).setMessageState(txn4, messageId3, INVALID); oneOf(db).setMessageState(txn4, messageId3, INVALID);
@@ -618,12 +763,18 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 3 has one dependent: 4 // Message 3 has one dependent: 4
oneOf(db).getMessageDependents(txn4, messageId3); oneOf(db).getMessageDependents(txn4, messageId3);
will(returnValue(singletonMap(messageId4, PENDING))); will(returnValue(singletonMap(messageId4, PENDING)));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Invalidate message 3 (again, via 2) // Invalidate message 3 (again, via 2)
oneOf(db).transaction(with(false), withDbRunnable(txn5)); oneOf(db).startTransaction(false);
will(returnValue(txn5));
oneOf(db).getMessageState(txn5, messageId3); oneOf(db).getMessageState(txn5, messageId3);
will(returnValue(INVALID)); // Already invalidated will(returnValue(INVALID)); // Already invalidated
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
// Invalidate message 4 (via 1 and 3) // Invalidate message 4 (via 1 and 3)
oneOf(db).transaction(with(false), withDbRunnable(txn6)); oneOf(db).startTransaction(false);
will(returnValue(txn6));
oneOf(db).getMessageState(txn6, messageId4); oneOf(db).getMessageState(txn6, messageId4);
will(returnValue(PENDING)); will(returnValue(PENDING));
oneOf(db).setMessageState(txn6, messageId4, INVALID); oneOf(db).setMessageState(txn6, messageId4, INVALID);
@@ -632,6 +783,8 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 4 has no dependents // Message 4 has no dependents
oneOf(db).getMessageDependents(txn6, messageId4); oneOf(db).getMessageDependents(txn6, messageId4);
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn6);
oneOf(db).endTransaction(txn6);
}}); }});
vm.eventOccurred(new MessageAddedEvent(message, contactId)); vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -657,16 +810,20 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn5 = new Transaction(null, false); Transaction txn5 = new Transaction(null, false);
Transaction txn6 = new Transaction(null, false); Transaction txn6 = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Load the group // Load the group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getGroup(txn, groupId); oneOf(db).getGroup(txn, groupId);
will(returnValue(group)); will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid // Validate the message: valid
oneOf(validator).validateMessage(message, group); oneOf(validator).validateMessage(message, group);
will(returnValue(validResult)); will(returnValue(validResult));
// Store the validation result // Store the validation result
oneOf(db).transaction(with(false), withDbRunnable(txn1)); oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata); oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
// Deliver the message // Deliver the message
oneOf(hook).incomingMessage(txn1, message, metadata); oneOf(hook).incomingMessage(txn1, message, metadata);
@@ -675,8 +832,11 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// The message has two pending dependents: 1 and 2 // The message has two pending dependents: 1 and 2
oneOf(db).getMessageDependents(txn1, messageId); oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(twoDependents)); will(returnValue(twoDependents));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Check whether message 1 is ready to be delivered // Check whether message 1 is ready to be delivered
oneOf(db).transaction(with(false), withDbRunnable(txn2)); oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).getMessageState(txn2, messageId1); oneOf(db).getMessageState(txn2, messageId1);
will(returnValue(PENDING)); will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn2, messageId1); oneOf(db).getMessageDependencies(txn2, messageId1);
@@ -695,8 +855,11 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 1 has one pending dependent: 3 // Message 1 has one pending dependent: 3
oneOf(db).getMessageDependents(txn2, messageId1); oneOf(db).getMessageDependents(txn2, messageId1);
will(returnValue(singletonMap(messageId3, PENDING))); will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Check whether message 2 is ready to be delivered // Check whether message 2 is ready to be delivered
oneOf(db).transaction(with(false), withDbRunnable(txn3)); oneOf(db).startTransaction(false);
will(returnValue(txn3));
oneOf(db).getMessageState(txn3, messageId2); oneOf(db).getMessageState(txn3, messageId2);
will(returnValue(PENDING)); will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn3, messageId2); oneOf(db).getMessageDependencies(txn3, messageId2);
@@ -715,8 +878,11 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 2 has one pending dependent: 3 (same dependent as 1) // Message 2 has one pending dependent: 3 (same dependent as 1)
oneOf(db).getMessageDependents(txn3, messageId2); oneOf(db).getMessageDependents(txn3, messageId2);
will(returnValue(singletonMap(messageId3, PENDING))); will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Check whether message 3 is ready to be delivered (via 1) // Check whether message 3 is ready to be delivered (via 1)
oneOf(db).transaction(with(false), withDbRunnable(txn4)); oneOf(db).startTransaction(false);
will(returnValue(txn4));
oneOf(db).getMessageState(txn4, messageId3); oneOf(db).getMessageState(txn4, messageId3);
will(returnValue(PENDING)); will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn4, messageId3); oneOf(db).getMessageDependencies(txn4, messageId3);
@@ -734,12 +900,18 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 3 has one pending dependent: 4 // Message 3 has one pending dependent: 4
oneOf(db).getMessageDependents(txn4, messageId3); oneOf(db).getMessageDependents(txn4, messageId3);
will(returnValue(singletonMap(messageId4, PENDING))); will(returnValue(singletonMap(messageId4, PENDING)));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Check whether message 3 is ready to be delivered (again, via 2) // Check whether message 3 is ready to be delivered (again, via 2)
oneOf(db).transaction(with(false), withDbRunnable(txn5)); oneOf(db).startTransaction(false);
will(returnValue(txn5));
oneOf(db).getMessageState(txn5, messageId3); oneOf(db).getMessageState(txn5, messageId3);
will(returnValue(DELIVERED)); // Already delivered will(returnValue(DELIVERED)); // Already delivered
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
// Check whether message 4 is ready to be delivered (via 1 and 3) // Check whether message 4 is ready to be delivered (via 1 and 3)
oneOf(db).transaction(with(false), withDbRunnable(txn6)); oneOf(db).startTransaction(false);
will(returnValue(txn6));
oneOf(db).getMessageState(txn6, messageId4); oneOf(db).getMessageState(txn6, messageId4);
will(returnValue(PENDING)); will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn6, messageId4); oneOf(db).getMessageDependencies(txn6, messageId4);
@@ -758,6 +930,8 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 4 has no pending dependents // Message 4 has no pending dependents
oneOf(db).getMessageDependents(txn6, messageId4); oneOf(db).getMessageDependents(txn6, messageId4);
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn6);
oneOf(db).endTransaction(txn6);
}}); }});
vm.eventOccurred(new MessageAddedEvent(message, contactId)); vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -772,16 +946,20 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn1 = new Transaction(null, false); Transaction txn1 = new Transaction(null, false);
Transaction txn2 = new Transaction(null, false); Transaction txn2 = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Load the group // Load the group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getGroup(txn, groupId); oneOf(db).getGroup(txn, groupId);
will(returnValue(group)); will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid // Validate the message: valid
oneOf(validator).validateMessage(message, group); oneOf(validator).validateMessage(message, group);
will(returnValue(validResult)); will(returnValue(validResult));
// Store the validation result // Store the validation result
oneOf(db).transaction(with(false), withDbRunnable(txn1)); oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata); oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
// Deliver the message // Deliver the message
oneOf(hook).incomingMessage(txn1, message, metadata); oneOf(hook).incomingMessage(txn1, message, metadata);
@@ -790,12 +968,17 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Get any pending dependents // Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId); oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(singletonMap(messageId1, PENDING))); will(returnValue(singletonMap(messageId1, PENDING)));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Check whether the pending dependent is ready to be delivered // Check whether the pending dependent is ready to be delivered
oneOf(db).transaction(with(false), withDbRunnable(txn2)); oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).getMessageState(txn2, messageId1); oneOf(db).getMessageState(txn2, messageId1);
will(returnValue(PENDING)); will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn2, messageId1); oneOf(db).getMessageDependencies(txn2, messageId1);
will(returnValue(twoDependencies)); will(returnValue(twoDependencies));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}}); }});
vm.eventOccurred(new MessageAddedEvent(message, contactId)); vm.eventOccurred(new MessageAddedEvent(message, contactId));

View File

@@ -2,7 +2,6 @@ package org.briarproject.bramble.test;
import org.briarproject.bramble.api.db.DbCallable; import org.briarproject.bramble.api.db.DbCallable;
import org.briarproject.bramble.api.db.DbRunnable; import org.briarproject.bramble.api.db.DbRunnable;
import org.briarproject.bramble.api.db.NullableDbCallable;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.jmock.Expectations; import org.jmock.Expectations;
@@ -22,12 +21,4 @@ public class DbExpectations extends Expectations {
return null; return null;
} }
protected <R, E extends Exception> NullableDbCallable<R, E> withNullableDbCallable(
Transaction txn) {
addParameterMatcher(any(NullableDbCallable.class));
currentBuilder().setAction(
new RunTransactionWithNullableResultAction(txn));
return null;
}
} }

View File

@@ -1,28 +0,0 @@
package org.briarproject.bramble.test;
import org.briarproject.bramble.api.db.NullableDbCallable;
import org.briarproject.bramble.api.db.Transaction;
import org.hamcrest.Description;
import org.jmock.api.Action;
import org.jmock.api.Invocation;
public class RunTransactionWithNullableResultAction implements Action {
private final Transaction txn;
public RunTransactionWithNullableResultAction(Transaction txn) {
this.txn = txn;
}
@Override
public Object invoke(Invocation invocation) throws Throwable {
NullableDbCallable task =
(NullableDbCallable) invocation.getParameter(1);
return task.call(txn);
}
@Override
public void describeTo(Description description) {
description.appendText("runs a task inside a database transaction");
}
}

View File

@@ -15,7 +15,6 @@ import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.StreamContext; import org.briarproject.bramble.api.transport.StreamContext;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.jmock.lib.concurrent.DeterministicExecutor; import org.jmock.lib.concurrent.DeterministicExecutor;
import org.junit.Before; import org.junit.Before;
@@ -36,7 +35,6 @@ import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTransportId; import static org.briarproject.bramble.test.TestUtils.getTransportId;
import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class KeyManagerImplTest extends BrambleMockTestCase { public class KeyManagerImplTest extends BrambleMockTestCase {
@@ -79,7 +77,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
singletonList(pluginFactory); singletonList(pluginFactory);
int maxLatency = 1337; int maxLatency = 1337;
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(pluginConfig).getSimplexFactories(); oneOf(pluginConfig).getSimplexFactories();
will(returnValue(factories)); will(returnValue(factories));
oneOf(pluginFactory).getId(); oneOf(pluginFactory).getId();
@@ -91,10 +89,13 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
.createTransportKeyManager(transportId, maxLatency); .createTransportKeyManager(transportId, maxLatency);
will(returnValue(transportKeyManager)); will(returnValue(transportKeyManager));
oneOf(pluginConfig).getDuplexFactories(); oneOf(pluginConfig).getDuplexFactories();
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
oneOf(db).getContacts(txn); oneOf(db).getContacts(txn);
will(returnValue(contacts)); will(returnValue(contacts));
oneOf(transportKeyManager).start(txn); oneOf(transportKeyManager).start(txn);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
keyManager.startService(); keyManager.startService();
@@ -120,21 +121,25 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
@Test @Test
public void testGetStreamContextForInactiveContact() throws Exception { public void testGetStreamContextForInactiveContact() throws Exception {
assertNull(keyManager.getStreamContext(inactiveContactId, transportId)); assertEquals(null,
keyManager.getStreamContext(inactiveContactId, transportId));
} }
@Test @Test
public void testGetStreamContextForUnknownTransport() throws Exception { public void testGetStreamContextForUnknownTransport() throws Exception {
assertNull(keyManager.getStreamContext(contactId, unknownTransportId)); assertEquals(null,
keyManager.getStreamContext(contactId, unknownTransportId));
} }
@Test @Test
public void testGetStreamContextForContact() throws Exception { public void testGetStreamContextForContact() throws Exception {
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithNullableResult(with(false), oneOf(db).startTransaction(false);
withNullableDbCallable(txn)); will(returnValue(txn));
oneOf(transportKeyManager).getStreamContext(txn, contactId); oneOf(transportKeyManager).getStreamContext(txn, contactId);
will(returnValue(streamContext)); will(returnValue(streamContext));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
assertEquals(streamContext, assertEquals(streamContext,
@@ -144,16 +149,19 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
@Test @Test
public void testGetStreamContextForTagAndUnknownTransport() public void testGetStreamContextForTagAndUnknownTransport()
throws Exception { throws Exception {
assertNull(keyManager.getStreamContext(unknownTransportId, tag)); assertEquals(null,
keyManager.getStreamContext(unknownTransportId, tag));
} }
@Test @Test
public void testGetStreamContextForTag() throws Exception { public void testGetStreamContextForTag() throws Exception {
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithNullableResult(with(false), oneOf(db).startTransaction(false);
withNullableDbCallable(txn)); will(returnValue(txn));
oneOf(transportKeyManager).getStreamContext(txn, tag); oneOf(transportKeyManager).getStreamContext(txn, tag);
will(returnValue(streamContext)); will(returnValue(streamContext));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
assertEquals(streamContext, assertEquals(streamContext,
@@ -170,7 +178,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
keyManager.eventOccurred(event); keyManager.eventOccurred(event);
executor.runUntilIdle(); executor.runUntilIdle();
assertNull(keyManager.getStreamContext(contactId, transportId)); assertEquals(null, keyManager.getStreamContext(contactId, transportId));
} }
@Test @Test
@@ -178,11 +186,13 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
ContactStatusChangedEvent event = ContactStatusChangedEvent event =
new ContactStatusChangedEvent(inactiveContactId, true); new ContactStatusChangedEvent(inactiveContactId, true);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transactionWithNullableResult(with(false), oneOf(db).startTransaction(false);
withNullableDbCallable(txn)); will(returnValue(txn));
oneOf(transportKeyManager).getStreamContext(txn, inactiveContactId); oneOf(transportKeyManager).getStreamContext(txn, inactiveContactId);
will(returnValue(streamContext)); will(returnValue(streamContext));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
keyManager.eventOccurred(event); keyManager.eventOccurred(event);

View File

@@ -14,7 +14,6 @@ import org.briarproject.bramble.api.transport.OutgoingKeys;
import org.briarproject.bramble.api.transport.StreamContext; import org.briarproject.bramble.api.transport.StreamContext;
import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.api.transport.TransportKeys;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.briarproject.bramble.test.RunAction; import org.briarproject.bramble.test.RunAction;
import org.briarproject.bramble.test.TestUtils; import org.briarproject.bramble.test.TestUtils;
import org.hamcrest.Description; import org.hamcrest.Description;
@@ -319,7 +318,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
Transaction txn = new Transaction(null, false); Transaction txn = new Transaction(null, false);
Transaction txn1 = new Transaction(null, false); Transaction txn1 = new Transaction(null, false);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
// Get the current time (the start of rotation period 1000) // Get the current time (the start of rotation period 1000)
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(rotationPeriodLength * 1000)); will(returnValue(rotationPeriodLength * 1000));
@@ -343,7 +342,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
oneOf(dbExecutor).execute(with(any(Runnable.class))); oneOf(dbExecutor).execute(with(any(Runnable.class)));
will(new RunAction()); will(new RunAction());
// Start a transaction for key rotation // Start a transaction for key rotation
oneOf(db).transaction(with(false), withDbRunnable(txn1)); oneOf(db).startTransaction(false);
will(returnValue(txn1));
// Get the current time (the start of rotation period 1001) // Get the current time (the start of rotation period 1001)
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(rotationPeriodLength * 1001)); will(returnValue(rotationPeriodLength * 1001));
@@ -364,6 +364,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
// Schedule key rotation at the start of the next rotation period // Schedule key rotation at the start of the next rotation period
oneOf(scheduler).schedule(with(any(Runnable.class)), oneOf(scheduler).schedule(with(any(Runnable.class)),
with(rotationPeriodLength), with(MILLISECONDS)); with(rotationPeriodLength), with(MILLISECONDS));
// Commit the key rotation transaction
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
}}); }});
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl( TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
@@ -536,7 +539,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
} }
@Override @Override
public Object invoke(Invocation invocation) { public Object invoke(Invocation invocation) throws Throwable {
byte[] tag = (byte[]) invocation.getParameter(0); byte[] tag = (byte[]) invocation.getParameter(0);
random.nextBytes(tag); random.nextBytes(tag);
if (tags != null) tags.add(tag); if (tags != null) tags.add(tag);

View File

@@ -18,7 +18,6 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook; import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.junit.Test; import org.junit.Test;
@@ -64,7 +63,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
private final long now = System.currentTimeMillis(); private final long now = System.currentTimeMillis();
private final Transaction txn = new Transaction(null, false); private final Transaction txn = new Transaction(null, false);
private ClientVersioningManagerImpl createInstance() { private ClientVersioningManagerImpl createInstance() throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID, oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID,
MAJOR_VERSION); MAJOR_VERSION);
@@ -163,8 +162,9 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
BdfList localUpdateBody = BdfList.of(BdfList.of( BdfList localUpdateBody = BdfList.of(BdfList.of(
BdfList.of(clientId.getString(), 123, 234, false)), 1L); BdfList.of(clientId.getString(), 123, 234, false)), 1L);
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
// No client versions have been stored yet // No client versions have been stored yet
oneOf(db).getMessageIds(txn, localGroup.getId()); oneOf(db).getMessageIds(txn, localGroup.getId());
will(returnValue(emptyList())); will(returnValue(emptyList()));
@@ -190,6 +190,8 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageAsList(txn, localUpdateId); oneOf(clientHelper).getMessageAsList(txn, localUpdateId);
will(returnValue(localUpdateBody)); will(returnValue(localUpdateBody));
// Latest local update is up-to-date, no visibilities have changed // Latest local update is up-to-date, no visibilities have changed
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
ClientVersioningManagerImpl c = createInstance(); ClientVersioningManagerImpl c = createInstance();
@@ -204,14 +206,17 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
BdfList localVersionsBody = BdfList localVersionsBody =
BdfList.of(BdfList.of(clientId.getString(), 123, 234)); BdfList.of(BdfList.of(clientId.getString(), 123, 234));
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
// Load the old client versions // Load the old client versions
oneOf(db).getMessageIds(txn, localGroup.getId()); oneOf(db).getMessageIds(txn, localGroup.getId());
will(returnValue(singletonList(localVersionsId))); will(returnValue(singletonList(localVersionsId)));
oneOf(clientHelper).getMessageAsList(txn, localVersionsId); oneOf(clientHelper).getMessageAsList(txn, localVersionsId);
will(returnValue(localVersionsBody)); will(returnValue(localVersionsBody));
// Client versions are up-to-date // Client versions are up-to-date
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
ClientVersioningManagerImpl c = createInstance(); ClientVersioningManagerImpl c = createInstance();
@@ -246,8 +251,9 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
new BdfEntry(MSG_KEY_UPDATE_VERSION, 2L), new BdfEntry(MSG_KEY_UPDATE_VERSION, 2L),
new BdfEntry(MSG_KEY_LOCAL, true)); new BdfEntry(MSG_KEY_LOCAL, true));
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
// Load the old client versions // Load the old client versions
oneOf(db).getMessageIds(txn, localGroup.getId()); oneOf(db).getMessageIds(txn, localGroup.getId());
will(returnValue(singletonList(oldLocalVersionsId))); will(returnValue(singletonList(oldLocalVersionsId)));
@@ -289,6 +295,8 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).addLocalMessage(txn, newLocalUpdate, oneOf(clientHelper).addLocalMessage(txn, newLocalUpdate,
newLocalUpdateMeta, true); newLocalUpdateMeta, true);
// No visibilities have changed // No visibilities have changed
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
ClientVersioningManagerImpl c = createInstance(); ClientVersioningManagerImpl c = createInstance();
@@ -342,8 +350,9 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
new BdfEntry(MSG_KEY_UPDATE_VERSION, 2L), new BdfEntry(MSG_KEY_UPDATE_VERSION, 2L),
new BdfEntry(MSG_KEY_LOCAL, true)); new BdfEntry(MSG_KEY_LOCAL, true));
context.checking(new DbExpectations() {{ context.checking(new Expectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).startTransaction(false);
will(returnValue(txn));
// Load the old client versions // Load the old client versions
oneOf(db).getMessageIds(txn, localGroup.getId()); oneOf(db).getMessageIds(txn, localGroup.getId());
will(returnValue(singletonList(oldLocalVersionsId))); will(returnValue(singletonList(oldLocalVersionsId)));
@@ -388,6 +397,8 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
newLocalUpdateMeta, true); newLocalUpdateMeta, true);
// The client's visibility has changed // The client's visibility has changed
oneOf(hook).onClientVisibilityChanging(txn, contact, visibility); oneOf(hook).onClientVisibilityChanging(txn, contact, visibility);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
ClientVersioningManagerImpl c = createInstance(); ClientVersioningManagerImpl c = createInstance();

View File

@@ -1,20 +1,12 @@
dependencyVerification { dependencyVerification {
verify = [ verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861', 'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed', 'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.dagger:dagger-compiler:2.19:dagger-compiler-2.19.jar:27a4b202a2de908182edb261f8c0a264e08e5e4733d7514bc7fbf0d31da5c0fc', 'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.dagger:dagger-producers:2.19:dagger-producers-2.19.jar:a17663abe0fc38b676026950907d4c5f5e2bf338375415861eaff6e3bdb0b768', 'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.dagger:dagger-spi:2.19:dagger-spi-2.19.jar:e7a6379d82c841f6aac2866948ad1eed716528707814602842a8d844ce04e2e1', 'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
'com.google.errorprone:error_prone_annotations:2.1.3:error_prone_annotations-2.1.3.jar:03d0329547c13da9e17c634d1049ea2ead093925e290567e1a364fd6b1fc7ff8',
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
'com.google.guava:guava:25.0-jre:guava-25.0-jre.jar:3fd4341776428c7e0e5c18a7c10de129475b69ab9d30aeafbb5c277bb6074fa9',
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
'com.h2database:h2:1.4.192:h2-1.4.192.jar:225b22e9857235c46c93861410b60b8c81c10dc8985f4faf188985ba5445126c', 'com.h2database:h2:1.4.192:h2-1.4.192.jar:225b22e9857235c46c93861410b60b8c81c10dc8985f4faf188985ba5445126c',
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728', 'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a', 'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140', 'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
@@ -23,9 +15,7 @@ dependencyVerification {
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8', 'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb', 'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
'org.briarproject:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864', 'org.briarproject:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619', 'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90', 'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52', 'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9', 'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',

View File

@@ -2,10 +2,10 @@ apply plugin: 'java-library'
sourceCompatibility = 1.8 sourceCompatibility = 1.8
targetCompatibility = 1.8 targetCompatibility = 1.8
apply plugin: 'net.ltgt.apt'
apply plugin: 'idea' apply plugin: 'idea'
apply plugin: 'witness' apply plugin: 'witness'
apply from: 'witness.gradle' apply from: 'witness.gradle'
apply from: '../dagger.gradle'
configurations { configurations {
tor tor
@@ -17,9 +17,8 @@ dependencies {
implementation 'net.java.dev.jna:jna:4.5.2' implementation 'net.java.dev.jna:jna:4.5.2'
implementation 'net.java.dev.jna:jna-platform:4.5.2' implementation 'net.java.dev.jna:jna-platform:4.5.2'
tor 'org.briarproject:tor:0.3.4.8@zip' tor 'org.briarproject:tor:0.3.4.8@zip'
tor 'org.briarproject:obfs4proxy:0.0.7@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.19' apt 'com.google.dagger:dagger-compiler:2.0.2'
testImplementation project(path: ':bramble-api', configuration: 'testOutput') testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation project(path: ':bramble-core', configuration: 'testOutput') testImplementation project(path: ':bramble-core', configuration: 'testOutput')
@@ -27,35 +26,19 @@ dependencies {
testImplementation "org.jmock:jmock:2.8.2" testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2" testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2" testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.19' testApt 'com.google.dagger:dagger-compiler:2.0.2'
} }
def torBinariesDir = 'src/main/resources' project.afterEvaluate {
copy {
task cleanTorBinaries { from configurations.tor.collect { zipTree(it) }
doLast { into 'src/main/resources'
delete fileTree(torBinariesDir) { include '*.zip' }
} }
} }
clean.dependsOn cleanTorBinaries
task unpackTorBinaries {
doLast {
copy {
from configurations.tor.collect { zipTree(it) }
into torBinariesDir
}
}
dependsOn cleanTorBinaries
}
processResources {
inputs.dir torBinariesDir
dependsOn unpackTorBinaries
}
tasks.withType(Test) { tasks.withType(Test) {
systemProperty 'java.library.path', 'libs' systemProperty 'java.library.path', 'libs'
} }

View File

@@ -1,7 +1,10 @@
package org.briarproject.bramble.network; package org.briarproject.bramble.network;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.network.NetworkStatus; import org.briarproject.bramble.api.network.NetworkStatus;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
@@ -20,13 +23,25 @@ import static org.briarproject.bramble.util.LogUtils.logException;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
class JavaNetworkManager implements NetworkManager { class JavaNetworkManager implements NetworkManager, Service {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(JavaNetworkManager.class.getName()); Logger.getLogger(JavaNetworkManager.class.getName());
private final EventBus eventBus;
@Inject @Inject
JavaNetworkManager() { JavaNetworkManager(EventBus eventBus) {
this.eventBus = eventBus;
}
@Override
public void startService() {
eventBus.broadcast(new NetworkStatusEvent(getNetworkStatus()));
}
@Override
public void stopService() {
} }
@Override @Override

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.network; package org.briarproject.bramble.network;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import javax.inject.Singleton; import javax.inject.Singleton;
@@ -12,7 +13,9 @@ public class JavaNetworkModule {
@Provides @Provides
@Singleton @Singleton
NetworkManager provideNetworkManager(JavaNetworkManager networkManager) { NetworkManager provideNetworkManager(LifecycleManager lifecycleManager,
JavaNetworkManager networkManager) {
lifecycleManager.registerService(networkManager);
return networkManager; return networkManager;
} }
} }

View File

@@ -10,10 +10,6 @@ import org.briarproject.bramble.api.system.Clock;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Condition;
@@ -26,7 +22,6 @@ import javax.annotation.Nullable;
import jssc.SerialPortEvent; import jssc.SerialPortEvent;
import jssc.SerialPortEventListener; import jssc.SerialPortEventListener;
import static java.nio.charset.CodingErrorAction.IGNORE;
import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
@@ -40,8 +35,6 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(ModemImpl.class.getName()); Logger.getLogger(ModemImpl.class.getName());
private static final Charset US_ASCII = Charset.forName("US-ASCII");
private static final int MAX_LINE_LENGTH = 256; private static final int MAX_LINE_LENGTH = 256;
private static final int[] BAUD_RATES = { private static final int[] BAUD_RATES = {
256000, 128000, 115200, 57600, 38400, 19200, 14400, 9600, 4800, 1200 256000, 128000, 115200, 57600, 38400, 19200, 14400, 9600, 4800, 1200
@@ -113,7 +106,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
throw e; throw e;
} }
// Wait for the event thread to receive "OK" // Wait for the event thread to receive "OK"
boolean success; boolean success = false;
try { try {
lock.lock(); lock.lock();
try { try {
@@ -360,7 +353,8 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
for (int i = 0; i < b.length; i++) { for (int i = 0; i < b.length; i++) {
line[lineLen] = b[i]; line[lineLen] = b[i];
if (b[i] == '\n') { if (b[i] == '\n') {
String s = toAscii(line, lineLen).trim(); // FIXME: Use CharsetDecoder to catch invalid ASCII
String s = new String(line, 0, lineLen, "US-ASCII").trim();
lineLen = 0; lineLen = 0;
if (LOG.isLoggable(INFO)) LOG.info("Modem status: " + s); if (LOG.isLoggable(INFO)) LOG.info("Modem status: " + s);
if (s.startsWith("CONNECT")) { if (s.startsWith("CONNECT")) {
@@ -442,7 +436,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
throw e; throw e;
} }
// Wait for the event thread to receive "CONNECT" // Wait for the event thread to receive "CONNECT"
boolean success; boolean success = false;
try { try {
lock.lock(); lock.lock();
try { try {
@@ -467,16 +461,4 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
stateChange.release(); stateChange.release();
} }
} }
private String toAscii(byte[] bytes, int len) {
CharsetDecoder decoder = US_ASCII.newDecoder();
decoder.onMalformedInput(IGNORE);
decoder.onUnmappableCharacter(IGNORE);
ByteBuffer buffer = ByteBuffer.wrap(bytes, 0, len);
try {
return decoder.decode(buffer).toString();
} catch (CharacterCodingException e) {
throw new AssertionError(e);
}
}
} }

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.plugin.tor; package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff; import org.briarproject.bramble.api.plugin.Backoff;
@@ -24,14 +23,12 @@ class LinuxTorPlugin extends TorPlugin {
LinuxTorPlugin(Executor ioExecutor, NetworkManager networkManager, LinuxTorPlugin(Executor ioExecutor, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory, LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider, Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, CircumventionProvider circumventionProvider, Backoff backoff,
BatteryManager batteryManager, Backoff backoff,
DuplexPluginCallback callback, String architecture, int maxLatency, DuplexPluginCallback callback, String architecture, int maxLatency,
int maxIdleTime, File torDirectory) { int maxIdleTime, File torDirectory) {
super(ioExecutor, networkManager, locationUtils, torSocketFactory, super(ioExecutor, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager, clock, resourceProvider, circumventionProvider, backoff,
backoff, callback, architecture, maxLatency, maxIdleTime, callback, architecture, maxLatency, maxIdleTime, torDirectory);
torDirectory);
} }
@Override @Override

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.plugin.tor; package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -45,7 +44,6 @@ public class LinuxTorPluginFactory implements DuplexPluginFactory {
private final BackoffFactory backoffFactory; private final BackoffFactory backoffFactory;
private final ResourceProvider resourceProvider; private final ResourceProvider resourceProvider;
private final CircumventionProvider circumventionProvider; private final CircumventionProvider circumventionProvider;
private final BatteryManager batteryManager;
private final Clock clock; private final Clock clock;
private final File torDirectory; private final File torDirectory;
@@ -53,8 +51,8 @@ public class LinuxTorPluginFactory implements DuplexPluginFactory {
NetworkManager networkManager, LocationUtils locationUtils, NetworkManager networkManager, LocationUtils locationUtils,
EventBus eventBus, SocketFactory torSocketFactory, EventBus eventBus, SocketFactory torSocketFactory,
BackoffFactory backoffFactory, ResourceProvider resourceProvider, BackoffFactory backoffFactory, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, CircumventionProvider circumventionProvider, Clock clock,
BatteryManager batteryManager, Clock clock, File torDirectory) { File torDirectory) {
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
this.networkManager = networkManager; this.networkManager = networkManager;
this.locationUtils = locationUtils; this.locationUtils = locationUtils;
@@ -63,7 +61,6 @@ public class LinuxTorPluginFactory implements DuplexPluginFactory {
this.backoffFactory = backoffFactory; this.backoffFactory = backoffFactory;
this.resourceProvider = resourceProvider; this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider; this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.clock = clock; this.clock = clock;
this.torDirectory = torDirectory; this.torDirectory = torDirectory;
} }
@@ -95,10 +92,11 @@ public class LinuxTorPluginFactory implements DuplexPluginFactory {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE); MAX_POLLING_INTERVAL, BACKOFF_BASE);
LinuxTorPlugin plugin = new LinuxTorPlugin(ioExecutor, networkManager, LinuxTorPlugin plugin =
locationUtils, torSocketFactory, clock, resourceProvider, new LinuxTorPlugin(ioExecutor, networkManager, locationUtils,
circumventionProvider, batteryManager, backoff, callback, torSocketFactory, clock, resourceProvider,
architecture, MAX_LATENCY, MAX_IDLE_TIME, torDirectory); circumventionProvider, backoff, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME, torDirectory);
eventBus.addListener(plugin); eventBus.addListener(plugin);
return plugin; return plugin;
} }

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.plugin.tor; package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.plugin.BackoffFactory; import org.briarproject.bramble.api.plugin.BackoffFactory;
@@ -59,8 +58,6 @@ public class BridgeTest extends BrambleTestCase {
@Inject @Inject
CircumventionProvider circumventionProvider; CircumventionProvider circumventionProvider;
@Inject @Inject
BatteryManager batteryManager;
@Inject
EventBus eventBus; EventBus eventBus;
@Inject @Inject
BackoffFactory backoffFactory; BackoffFactory backoffFactory;
@@ -110,8 +107,7 @@ public class BridgeTest extends BrambleTestCase {
}; };
factory = new LinuxTorPluginFactory(ioExecutor, networkManager, factory = new LinuxTorPluginFactory(ioExecutor, networkManager,
locationUtils, eventBus, torSocketFactory, backoffFactory, locationUtils, eventBus, torSocketFactory, backoffFactory,
resourceProvider, bridgeProvider, batteryManager, clock, resourceProvider, bridgeProvider, clock, torDir);
torDir);
} }
@After @After

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.test; package org.briarproject.bramble.test;
import org.briarproject.bramble.BrambleJavaModule; import org.briarproject.bramble.BrambleJavaModule;
import org.briarproject.bramble.battery.DefaultBatteryManagerModule;
import org.briarproject.bramble.event.EventModule; import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.plugin.PluginModule; import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.plugin.tor.BridgeTest; import org.briarproject.bramble.plugin.tor.BridgeTest;
@@ -16,7 +15,6 @@ import dagger.Component;
@Component(modules = { @Component(modules = {
BrambleJavaModule.class, BrambleJavaModule.class,
TestLifecycleModule.class, TestLifecycleModule.class,
DefaultBatteryManagerModule.class,
PluginModule.class, // needed for BackoffFactory PluginModule.class, // needed for BackoffFactory
EventModule.class, EventModule.class,
SystemModule.class, SystemModule.class,

View File

@@ -1,18 +1,10 @@
dependencyVerification { dependencyVerification {
verify = [ verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861', 'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed', 'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.dagger:dagger-compiler:2.19:dagger-compiler-2.19.jar:27a4b202a2de908182edb261f8c0a264e08e5e4733d7514bc7fbf0d31da5c0fc', 'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.dagger:dagger-producers:2.19:dagger-producers-2.19.jar:a17663abe0fc38b676026950907d4c5f5e2bf338375415861eaff6e3bdb0b768', 'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.dagger:dagger-spi:2.19:dagger-spi-2.19.jar:e7a6379d82c841f6aac2866948ad1eed716528707814602842a8d844ce04e2e1', 'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
'com.google.errorprone:error_prone_annotations:2.1.3:error_prone_annotations-2.1.3.jar:03d0329547c13da9e17c634d1049ea2ead093925e290567e1a364fd6b1fc7ff8',
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
'com.google.guava:guava:25.0-jre:guava-25.0-jre.jar:3fd4341776428c7e0e5c18a7c10de129475b69ab9d30aeafbb5c277bb6074fa9',
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a', 'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'net.java.dev.jna:jna-platform:4.5.2:jna-platform-4.5.2.jar:f1d00c167d8921c6e23c626ef9f1c3ae0be473c95c68ffa012bc7ae55a87e2d6', 'net.java.dev.jna:jna-platform:4.5.2:jna-platform-4.5.2.jar:f1d00c167d8921c6e23c626ef9f1c3ae0be473c95c68ffa012bc7ae55a87e2d6',
@@ -20,10 +12,7 @@ dependencyVerification {
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d', 'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8', 'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8', 'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.briarproject:obfs4proxy:0.0.7:obfs4proxy-0.0.7.zip:5b2f693262ce43a7e130f7cc7d5d1617925330640a2eb6d71085e95df8ee0642',
'org.briarproject:tor:0.3.4.8:tor-0.3.4.8.zip:bc0158c34002f471a4fe14a6a481816c918eb520a220bb027f64be902beb757f', 'org.briarproject:tor:0.3.4.8:tor-0.3.4.8.zip:bc0158c34002f471a4fe14a6a481816c918eb520a220bb027f64be902beb757f',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9', 'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c', 'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c', 'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',

View File

@@ -22,8 +22,8 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 26 targetSdkVersion 26
versionCode 10105 versionCode 10103
versionName "1.1.5" versionName "1.1.3"
applicationId "org.briarproject.briar.android" applicationId "org.briarproject.briar.android"
buildConfigField "String", "GitHash", buildConfigField "String", "GitHash",
"\"${getStdout(['git', 'rev-parse', '--short=7', 'HEAD'], 'No commit hash')}\"" "\"${getStdout(['git', 'rev-parse', '--short=7', 'HEAD'], 'No commit hash')}\""
@@ -118,25 +118,27 @@ dependencies {
implementation 'uk.co.samuelwall:material-tap-target-prompt:2.12.4' implementation 'uk.co.samuelwall:material-tap-target-prompt:2.12.4'
implementation 'com.vanniktech:emoji-google:0.5.1' implementation 'com.vanniktech:emoji-google:0.5.1'
annotationProcessor 'com.google.dagger:dagger-compiler:2.19' annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
compileOnly 'javax.annotation:jsr250-api:1.0' compileOnly 'javax.annotation:jsr250-api:1.0'
testImplementation project(path: ':bramble-api', configuration: 'testOutput') testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation project(path: ':bramble-core', configuration: 'testOutput') testImplementation project(path: ':bramble-core', configuration: 'testOutput')
testImplementation 'org.robolectric:robolectric:4.0.1' testImplementation 'org.robolectric:robolectric:3.8'
testImplementation 'org.robolectric:shadows-support-v4:3.3.2' testImplementation 'org.robolectric:shadows-support-v4:3.3.2'
testImplementation 'org.mockito:mockito-core:2.13.0' testImplementation 'org.mockito:mockito-core:2.13.0'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2" testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2" testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2" testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
def espressoVersion = '3.0.2' def espressoVersion = '3.0.2'
androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion" androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion"
androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$espressoVersion" androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$espressoVersion"
androidTestImplementation "com.android.support.test.espresso:espresso-intents:$espressoVersion" androidTestImplementation "com.android.support.test.espresso:espresso-intents:$espressoVersion"
androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.19" androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.0.2"
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0' androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
androidTestImplementation 'junit:junit:4.12' androidTestImplementation 'junit:junit:4.12'
androidTestScreenshotImplementation "tools.fastlane:screengrab:1.2.0" androidTestScreenshotImplementation "tools.fastlane:screengrab:1.2.0"

View File

@@ -102,7 +102,7 @@
</activity> </activity>
<activity <activity
android:name="org.briarproject.briar.android.conversation.ConversationActivity" android:name="org.briarproject.briar.android.contact.ConversationActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/BriarTheme.NoActionBar" android:theme="@style/BriarTheme.NoActionBar"
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity" android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
@@ -190,10 +190,10 @@
<activity <activity
android:name="org.briarproject.briar.android.sharing.BlogInvitationActivity" android:name="org.briarproject.briar.android.sharing.BlogInvitationActivity"
android:label="@string/blogs_sharing_invitations_title" android:label="@string/blogs_sharing_invitations_title"
android:parentActivityName="org.briarproject.briar.android.conversation.ConversationActivity"> android:parentActivityName="org.briarproject.briar.android.contact.ConversationActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="org.briarproject.briar.android.conversation.ConversationActivity" android:value="org.briarproject.briar.android.contact.ConversationActivity"
/> />
</activity> </activity>
@@ -327,11 +327,11 @@
<activity <activity
android:name="org.briarproject.briar.android.introduction.IntroductionActivity" android:name="org.briarproject.briar.android.introduction.IntroductionActivity"
android:label="@string/introduction_activity_title" android:label="@string/introduction_activity_title"
android:parentActivityName="org.briarproject.briar.android.conversation.ConversationActivity" android:parentActivityName="org.briarproject.briar.android.contact.ConversationActivity"
android:windowSoftInputMode="stateHidden|adjustResize"> android:windowSoftInputMode="stateHidden|adjustResize">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="org.briarproject.briar.android.conversation.ConversationActivity" android:value="org.briarproject.briar.android.contact.ConversationActivity"
/> />
</activity> </activity>

View File

@@ -1,7 +1,5 @@
package org.briarproject.briar.android; package org.briarproject.briar.android;
import android.arch.lifecycle.ViewModelProvider;
import org.briarproject.bramble.BrambleAndroidModule; import org.briarproject.bramble.BrambleAndroidModule;
import org.briarproject.bramble.BrambleCoreEagerSingletons; import org.briarproject.bramble.BrambleCoreEagerSingletons;
import org.briarproject.bramble.BrambleCoreModule; import org.briarproject.bramble.BrambleCoreModule;
@@ -28,6 +26,7 @@ import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.plugin.tor.CircumventionProvider; import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.briar.BriarCoreEagerSingletons; import org.briarproject.briar.BriarCoreEagerSingletons;
import org.briarproject.briar.BriarCoreModule; import org.briarproject.briar.BriarCoreModule;
import org.briarproject.briar.android.contact.ConversationViewModel;
import org.briarproject.briar.android.login.SignInReminderReceiver; import org.briarproject.briar.android.login.SignInReminderReceiver;
import org.briarproject.briar.android.reporting.BriarReportSender; import org.briarproject.briar.android.reporting.BriarReportSender;
import org.briarproject.briar.android.view.TextInputView; import org.briarproject.briar.android.view.TextInputView;
@@ -43,7 +42,7 @@ import org.briarproject.briar.api.feed.FeedManager;
import org.briarproject.briar.api.forum.ForumManager; import org.briarproject.briar.api.forum.ForumManager;
import org.briarproject.briar.api.forum.ForumSharingManager; import org.briarproject.briar.api.forum.ForumSharingManager;
import org.briarproject.briar.api.introduction.IntroductionManager; import org.briarproject.briar.api.introduction.IntroductionManager;
import org.briarproject.briar.api.conversation.ConversationManager; import org.briarproject.briar.api.messaging.ConversationManager;
import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.MessagingManager;
import org.briarproject.briar.api.messaging.PrivateMessageFactory; import org.briarproject.briar.api.messaging.PrivateMessageFactory;
import org.briarproject.briar.api.privategroup.GroupMessageFactory; import org.briarproject.briar.api.privategroup.GroupMessageFactory;
@@ -156,8 +155,6 @@ public interface AndroidComponent
CircumventionProvider circumventionProvider(); CircumventionProvider circumventionProvider();
ViewModelProvider.Factory viewModelFactory();
void inject(SignInReminderReceiver briarService); void inject(SignInReminderReceiver briarService);
void inject(BriarService briarService); void inject(BriarService briarService);
@@ -168,6 +165,8 @@ public interface AndroidComponent
void inject(TextInputView textInputView); void inject(TextInputView textInputView);
void inject(ConversationViewModel conversationViewModel);
// Eager singleton load // Eager singleton load
void inject(AppModule.EagerSingletons init); void inject(AppModule.EagerSingletons init);
} }

View File

@@ -31,7 +31,7 @@ import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.StringUtils; import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.conversation.ConversationActivity; import org.briarproject.briar.android.contact.ConversationActivity;
import org.briarproject.briar.android.forum.ForumActivity; import org.briarproject.briar.android.forum.ForumActivity;
import org.briarproject.briar.android.login.SignInReminderReceiver; import org.briarproject.briar.android.login.SignInReminderReceiver;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity; import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
@@ -40,9 +40,9 @@ import org.briarproject.briar.android.splash.SplashScreenActivity;
import org.briarproject.briar.android.util.BriarNotificationBuilder; import org.briarproject.briar.android.util.BriarNotificationBuilder;
import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent; import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
import org.briarproject.briar.api.conversation.event.ConversationMessageReceivedEvent;
import org.briarproject.briar.api.forum.event.ForumPostReceivedEvent; import org.briarproject.briar.api.forum.event.ForumPostReceivedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent; import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent;
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import org.briarproject.briar.api.privategroup.event.GroupMessageAddedEvent; import org.briarproject.briar.api.privategroup.event.GroupMessageAddedEvent;
import java.util.Set; import java.util.Set;
@@ -72,7 +72,7 @@ import static android.support.v4.app.NotificationCompat.PRIORITY_MIN;
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET; import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
import static android.support.v4.content.ContextCompat.getColor; import static android.support.v4.content.ContextCompat.getColor;
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID; import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID; import static org.briarproject.briar.android.contact.ConversationActivity.CONTACT_ID;
import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.INTENT_BLOGS; import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.INTENT_BLOGS;
import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.INTENT_CONTACTS; import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.INTENT_CONTACTS;
import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.INTENT_FORUMS; import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.INTENT_FORUMS;
@@ -219,9 +219,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e; SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
if (s.getNamespace().equals(SETTINGS_NAMESPACE)) if (s.getNamespace().equals(SETTINGS_NAMESPACE))
settings = s.getSettings(); settings = s.getSettings();
} else if (e instanceof ConversationMessageReceivedEvent) { } else if (e instanceof PrivateMessageReceivedEvent) {
ConversationMessageReceivedEvent p = PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
(ConversationMessageReceivedEvent) e;
showContactNotification(p.getContactId()); showContactNotification(p.getContactId());
} else if (e instanceof GroupMessageAddedEvent) { } else if (e instanceof GroupMessageAddedEvent) {
GroupMessageAddedEvent g = (GroupMessageAddedEvent) e; GroupMessageAddedEvent g = (GroupMessageAddedEvent) e;

View File

@@ -7,7 +7,6 @@ import android.os.StrictMode;
import com.vanniktech.emoji.RecentEmoji; import com.vanniktech.emoji.RecentEmoji;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
@@ -33,7 +32,6 @@ import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.bramble.util.AndroidUtils; import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.bramble.util.StringUtils; import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.android.account.LockManagerImpl; import org.briarproject.briar.android.account.LockManagerImpl;
import org.briarproject.briar.android.viewmodel.ViewModelModule;
import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.android.DozeWatchdog; import org.briarproject.briar.api.android.DozeWatchdog;
import org.briarproject.briar.api.android.LockManager; import org.briarproject.briar.api.android.LockManager;
@@ -59,7 +57,7 @@ import static java.util.Collections.emptyList;
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS; import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS;
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX; import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX;
@Module(includes = ViewModelModule.class) @Module
public class AppModule { public class AppModule {
static class EagerSingletons { static class EagerSingletons {
@@ -105,8 +103,7 @@ public class AppModule {
Application app, NetworkManager networkManager, Application app, NetworkManager networkManager,
LocationUtils locationUtils, EventBus eventBus, LocationUtils locationUtils, EventBus eventBus,
ResourceProvider resourceProvider, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, CircumventionProvider circumventionProvider, Clock clock) {
BatteryManager batteryManager, Clock clock) {
Context appContext = app.getApplicationContext(); Context appContext = app.getApplicationContext();
DuplexPluginFactory bluetooth = DuplexPluginFactory bluetooth =
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor, new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
@@ -114,7 +111,7 @@ public class AppModule {
DuplexPluginFactory tor = new AndroidTorPluginFactory(ioExecutor, DuplexPluginFactory tor = new AndroidTorPluginFactory(ioExecutor,
scheduler, appContext, networkManager, locationUtils, eventBus, scheduler, appContext, networkManager, locationUtils, eventBus,
torSocketFactory, backoffFactory, resourceProvider, torSocketFactory, backoffFactory, resourceProvider,
circumventionProvider, batteryManager, clock); circumventionProvider, clock);
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor, DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
eventBus, backoffFactory, appContext); eventBus, backoffFactory, appContext);
Collection<DuplexPluginFactory> duplex = asList(bluetooth, tor, lan); Collection<DuplexPluginFactory> duplex = asList(bluetooth, tor, lan);

View File

@@ -18,7 +18,8 @@ import org.briarproject.bramble.util.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedList; import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -39,7 +40,7 @@ class RecentEmojiImpl implements RecentEmoji, Client {
private static final int EMOJI_LRU_SIZE = 50; private static final int EMOJI_LRU_SIZE = 50;
// UI thread // UI thread
private final LinkedList<Emoji> recentlyUsed = new LinkedList<>(); private final LinkedHashSet<Emoji> recentlyUsed = new LinkedHashSet<>();
private final Executor dbExecutor; private final Executor dbExecutor;
private final AndroidExecutor androidExecutor; private final AndroidExecutor androidExecutor;
@@ -61,9 +62,13 @@ class RecentEmojiImpl implements RecentEmoji, Client {
@Override @Override
public void addEmoji(Emoji emoji) { public void addEmoji(Emoji emoji) {
recentlyUsed.remove(emoji); recentlyUsed.remove(emoji);
recentlyUsed.add(0, emoji); recentlyUsed.add(emoji);
if (recentlyUsed.size() > EMOJI_LRU_SIZE) recentlyUsed.removeLast(); if (recentlyUsed.size() > EMOJI_LRU_SIZE) {
Iterator<Emoji> iterator = recentlyUsed.iterator();
iterator.next();
iterator.remove();
}
} }
@Override @Override

View File

@@ -15,10 +15,9 @@ import org.briarproject.briar.android.blog.ReblogFragment;
import org.briarproject.briar.android.blog.RssFeedImportActivity; import org.briarproject.briar.android.blog.RssFeedImportActivity;
import org.briarproject.briar.android.blog.RssFeedManageActivity; import org.briarproject.briar.android.blog.RssFeedManageActivity;
import org.briarproject.briar.android.blog.WriteBlogPostActivity; import org.briarproject.briar.android.blog.WriteBlogPostActivity;
import org.briarproject.briar.android.conversation.AliasDialogFragment;
import org.briarproject.briar.android.contact.ContactListFragment; import org.briarproject.briar.android.contact.ContactListFragment;
import org.briarproject.briar.android.contact.ContactModule; import org.briarproject.briar.android.contact.ContactModule;
import org.briarproject.briar.android.conversation.ConversationActivity; import org.briarproject.briar.android.contact.ConversationActivity;
import org.briarproject.briar.android.forum.CreateForumActivity; import org.briarproject.briar.android.forum.CreateForumActivity;
import org.briarproject.briar.android.forum.ForumActivity; import org.briarproject.briar.android.forum.ForumActivity;
import org.briarproject.briar.android.forum.ForumListFragment; import org.briarproject.briar.android.forum.ForumListFragment;
@@ -212,7 +211,4 @@ public interface ActivityComponent {
void inject(ScreenFilterDialogFragment fragment); void inject(ScreenFilterDialogFragment fragment);
void inject(ContactExchangeErrorFragment fragment); void inject(ContactExchangeErrorFragment fragment);
void inject(AliasDialogFragment aliasDialogFragment);
} }

View File

@@ -1,6 +1,5 @@
package org.briarproject.briar.android.conversation; package org.briarproject.briar.android.contact;
import android.arch.lifecycle.ViewModelProvider;
import android.arch.lifecycle.ViewModelProviders; import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
@@ -12,37 +11,40 @@ import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.BriarActivity;
import javax.inject.Inject;
import static java.util.Objects.requireNonNull;
public class AliasDialogFragment extends AppCompatDialogFragment { public class AliasDialogFragment extends AppCompatDialogFragment {
final static String TAG = AliasDialogFragment.class.getName(); final static String TAG = AliasDialogFragment.class.getName();
@Inject
ViewModelProvider.Factory viewModelFactory;
private ConversationViewModel viewModel; private ConversationViewModel viewModel;
private ContactId contactId;
private EditText aliasEditText; private EditText aliasEditText;
public static AliasDialogFragment newInstance() { public static AliasDialogFragment newInstance(ContactId id) {
return new AliasDialogFragment(); AliasDialogFragment f = new AliasDialogFragment();
Bundle args = new Bundle();
args.putInt("contactId", id.getInt());
f.setArguments(args);
return f;
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (getArguments() == null) throw new IllegalArgumentException();
int contactIdInt = getArguments().getInt("contactId", -1);
if (contactIdInt == -1) throw new IllegalArgumentException();
contactId = new ContactId(contactIdInt);
setStyle(STYLE_NO_TITLE, R.style.BriarDialogTheme); setStyle(STYLE_NO_TITLE, R.style.BriarDialogTheme);
if (getActivity() == null) return; viewModel =
((BriarActivity) getActivity()).getActivityComponent().inject(this); ViewModelProviders.of(getActivity()).get(ConversationViewModel.class);
viewModel = ViewModelProviders.of(getActivity(), viewModelFactory)
.get(ConversationViewModel.class);
} }
@Override @Override
@@ -53,14 +55,15 @@ public class AliasDialogFragment extends AppCompatDialogFragment {
false); false);
aliasEditText = v.findViewById(R.id.aliasEditText); aliasEditText = v.findViewById(R.id.aliasEditText);
Contact contact = requireNonNull(viewModel.getContact().getValue()); Contact contact = viewModel.getContact().getValue();
String alias = contact.getAlias(); String alias = contact == null ? null : contact.getAlias();
aliasEditText.setText(alias); aliasEditText.setText(alias);
if (alias != null) aliasEditText.setSelection(alias.length()); if (alias != null) aliasEditText.setSelection(alias.length());
Button setButton = v.findViewById(R.id.setButton); Button setButton = v.findViewById(R.id.setButton);
setButton.setOnClickListener(v1 -> { setButton.setOnClickListener(v1 -> {
viewModel.setContactAlias(aliasEditText.getText().toString()); viewModel.setContactAlias(contactId,
aliasEditText.getText().toString());
getDialog().dismiss(); getDialog().dismiss();
}); });

View File

@@ -31,15 +31,14 @@ import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.contact.BaseContactListAdapter.OnContactClickListener; import org.briarproject.briar.android.contact.BaseContactListAdapter.OnContactClickListener;
import org.briarproject.briar.android.conversation.ConversationActivity;
import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.keyagreement.ContactExchangeActivity; import org.briarproject.briar.android.keyagreement.ContactExchangeActivity;
import org.briarproject.briar.android.view.BriarRecyclerView; import org.briarproject.briar.android.view.BriarRecyclerView;
import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.client.MessageTracker.GroupCount;
import org.briarproject.briar.api.conversation.ConversationManager; import org.briarproject.briar.api.messaging.ConversationManager;
import org.briarproject.briar.api.conversation.ConversationMessageHeader; import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.conversation.event.ConversationMessageReceivedEvent; import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -55,7 +54,7 @@ import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID; import static org.briarproject.briar.android.contact.ConversationActivity.CONTACT_ID;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
@@ -243,16 +242,15 @@ public class ContactListFragment extends BaseFragment implements EventListener {
} else if (e instanceof ContactRemovedEvent) { } else if (e instanceof ContactRemovedEvent) {
LOG.info("Contact removed, removing item"); LOG.info("Contact removed, removing item");
removeItem(((ContactRemovedEvent) e).getContactId()); removeItem(((ContactRemovedEvent) e).getContactId());
} else if (e instanceof ConversationMessageReceivedEvent) { } else if (e instanceof PrivateMessageReceivedEvent) {
LOG.info("Conversation message received, updating item"); LOG.info("Private message received, updating item");
ConversationMessageReceivedEvent p = PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
(ConversationMessageReceivedEvent) e; PrivateMessageHeader h = p.getMessageHeader();
ConversationMessageHeader h = p.getMessageHeader();
updateItem(p.getContactId(), h); updateItem(p.getContactId(), h);
} }
} }
private void updateItem(ContactId c, ConversationMessageHeader h) { private void updateItem(ContactId c, PrivateMessageHeader h) {
runOnUiThreadUnlessDestroyed(() -> { runOnUiThreadUnlessDestroyed(() -> {
adapter.incrementRevision(); adapter.incrementRevision();
int position = adapter.findItemPosition(c); int position = adapter.findItemPosition(c);

View File

@@ -3,7 +3,7 @@ package org.briarproject.briar.android.contact;
import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.client.MessageTracker.GroupCount;
import org.briarproject.briar.api.conversation.ConversationMessageHeader; import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
@@ -23,7 +23,7 @@ public class ContactListItem extends ContactItem {
this.timestamp = count.getLatestMsgTime(); this.timestamp = count.getLatestMsgTime();
} }
void addMessage(ConversationMessageHeader h) { void addMessage(PrivateMessageHeader h) {
empty = false; empty = false;
if (h.getTimestamp() > timestamp) timestamp = h.getTimestamp(); if (h.getTimestamp() > timestamp) timestamp = h.getTimestamp();
if (!h.isRead()) unread++; if (!h.isRead()) unread++;

View File

@@ -1,7 +1,7 @@
package org.briarproject.briar.android.conversation; package org.briarproject.briar.android.contact;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer; import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProvider;
import android.arch.lifecycle.ViewModelProviders; import android.arch.lifecycle.ViewModelProviders;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
@@ -51,7 +51,8 @@ import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity; import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.blog.BlogActivity; import org.briarproject.briar.android.blog.BlogActivity;
import org.briarproject.briar.android.conversation.ConversationVisitor.TextCache; import org.briarproject.briar.android.contact.ConversationAdapter.ConversationListener;
import org.briarproject.briar.android.contact.ConversationVisitor.TextCache;
import org.briarproject.briar.android.forum.ForumActivity; import org.briarproject.briar.android.forum.ForumActivity;
import org.briarproject.briar.android.introduction.IntroductionActivity; import org.briarproject.briar.android.introduction.IntroductionActivity;
import org.briarproject.briar.android.privategroup.conversation.GroupActivity; import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
@@ -62,17 +63,16 @@ import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.blog.BlogSharingManager; import org.briarproject.briar.api.blog.BlogSharingManager;
import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
import org.briarproject.briar.api.conversation.ConversationRequest;
import org.briarproject.briar.api.conversation.ConversationResponse;
import org.briarproject.briar.api.conversation.event.ConversationMessageReceivedEvent;
import org.briarproject.briar.api.forum.ForumSharingManager; import org.briarproject.briar.api.forum.ForumSharingManager;
import org.briarproject.briar.api.introduction.IntroductionManager; import org.briarproject.briar.api.introduction.IntroductionManager;
import org.briarproject.briar.api.messaging.ConversationManager;
import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.MessagingManager;
import org.briarproject.briar.api.messaging.PrivateMessage; import org.briarproject.briar.api.messaging.PrivateMessage;
import org.briarproject.briar.api.messaging.PrivateMessageFactory; import org.briarproject.briar.api.messaging.PrivateMessageFactory;
import org.briarproject.briar.api.messaging.PrivateMessageHeader; import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.messaging.PrivateResponse;
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
import java.util.ArrayList; import java.util.ArrayList;
@@ -95,8 +95,6 @@ import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.PromptSt
import static android.support.v4.view.ViewCompat.setTransitionName; import static android.support.v4.view.ViewCompat.setTransitionName;
import static android.support.v7.util.SortedList.INVALID_POSITION; import static android.support.v7.util.SortedList.INVALID_POSITION;
import static android.widget.Toast.LENGTH_SHORT; import static android.widget.Toast.LENGTH_SHORT;
import static java.util.Collections.emptyList;
import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
@@ -106,7 +104,6 @@ import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_INTRO
import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE; import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE;
import static org.briarproject.briar.android.util.UiUtils.getAvatarTransitionName; import static org.briarproject.briar.android.util.UiUtils.getAvatarTransitionName;
import static org.briarproject.briar.android.util.UiUtils.getBulbTransitionName; import static org.briarproject.briar.android.util.UiUtils.getBulbTransitionName;
import static org.briarproject.briar.android.util.UiUtils.observeOnce;
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH;
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_DISMISSED; import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_DISMISSED;
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_FINISHED; import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_FINISHED;
@@ -165,53 +162,46 @@ public class ConversationActivity extends BriarActivity
volatile BlogSharingManager blogSharingManager; volatile BlogSharingManager blogSharingManager;
@Inject @Inject
volatile GroupInvitationManager groupInvitationManager; volatile GroupInvitationManager groupInvitationManager;
@Inject
ViewModelProvider.Factory viewModelFactory;
private volatile ContactId contactId; private volatile ContactId contactId;
@Nullable @Nullable
private volatile GroupId messagingGroupId; private volatile GroupId messagingGroupId;
private final Observer<String> contactNameObserver = name -> { @SuppressWarnings("ConstantConditions")
requireNonNull(name);
loadMessages();
};
@Override @Override
public void onCreate(@Nullable Bundle state) { public void onCreate(@Nullable Bundle state) {
setSceneTransitionAnimation(); setSceneTransitionAnimation();
super.onCreate(state); super.onCreate(state);
viewModel =
ViewModelProviders.of(this).get(ConversationViewModel.class);
Intent i = getIntent(); Intent i = getIntent();
int id = i.getIntExtra(CONTACT_ID, -1); int id = i.getIntExtra(CONTACT_ID, -1);
if (id == -1) throw new IllegalStateException(); if (id == -1) throw new IllegalStateException();
contactId = new ContactId(id); contactId = new ContactId(id);
viewModel = ViewModelProviders.of(this, viewModelFactory)
.get(ConversationViewModel.class);
viewModel.setContactId(contactId);
setContentView(R.layout.activity_conversation); setContentView(R.layout.activity_conversation);
// Custom Toolbar // Custom Toolbar
toolbar = requireNonNull(setUpCustomToolbar(true)); toolbar = setUpCustomToolbar(true);
toolbarAvatar = toolbar.findViewById(R.id.contactAvatar); toolbarAvatar = toolbar.findViewById(R.id.contactAvatar);
toolbarStatus = toolbar.findViewById(R.id.contactStatus); toolbarStatus = toolbar.findViewById(R.id.contactStatus);
toolbarTitle = toolbar.findViewById(R.id.contactName); toolbarTitle = toolbar.findViewById(R.id.contactName);
observeOnce(viewModel.getContactAuthorId(), this, authorId -> { viewModel.getContactAuthorId().observe(this, authorId -> {
requireNonNull(authorId);
toolbarAvatar.setImageDrawable( toolbarAvatar.setImageDrawable(
new IdenticonDrawable(authorId.getBytes())); new IdenticonDrawable(authorId.getBytes()));
// we only need this once
viewModel.getContactAuthorId().removeObservers(this);
}); });
viewModel.getContactDisplayName().observe(this, contactName -> { viewModel.getContactDisplayName().observe(this, contactName -> {
requireNonNull(contactName);
toolbarTitle.setText(contactName); toolbarTitle.setText(contactName);
}); });
viewModel.isContactDeleted().observe(this, deleted -> { viewModel.isContactDeleted().observe(this, deleted -> {
requireNonNull(deleted); if (deleted != null && deleted) finish();
if (deleted) finish();
}); });
viewModel.loadContact(contactId);
setTransitionName(toolbarAvatar, getAvatarTransitionName(contactId)); setTransitionName(toolbarAvatar, getAvatarTransitionName(contactId));
setTransitionName(toolbarStatus, getBulbTransitionName(contactId)); setTransitionName(toolbarStatus, getBulbTransitionName(contactId));
@@ -252,7 +242,19 @@ public class ConversationActivity extends BriarActivity
notificationManager.blockContactNotification(contactId); notificationManager.blockContactNotification(contactId);
notificationManager.clearContactNotification(contactId); notificationManager.clearContactNotification(contactId);
displayContactOnlineStatus(); displayContactOnlineStatus();
viewModel.getContactDisplayName().observe(this, contactNameObserver); LiveData<String> contactName = viewModel.getContactDisplayName();
if (contactName.getValue() == null) {
// wait for contact name to be initialized
contactName.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String cName) {
if (cName != null) {
loadMessages();
contactName.removeObserver(this);
}
}
});
} else loadMessages();
list.startPeriodicUpdate(); list.startPeriodicUpdate();
} }
@@ -261,7 +263,6 @@ public class ConversationActivity extends BriarActivity
super.onStop(); super.onStop();
eventBus.removeListener(this); eventBus.removeListener(this);
notificationManager.unblockContactNotification(contactId); notificationManager.unblockContactNotification(contactId);
viewModel.getContactDisplayName().removeObserver(contactNameObserver);
list.stopPeriodicUpdate(); list.stopPeriodicUpdate();
} }
@@ -273,8 +274,6 @@ public class ConversationActivity extends BriarActivity
enableIntroductionActionIfAvailable( enableIntroductionActionIfAvailable(
menu.findItem(R.id.action_introduction)); menu.findItem(R.id.action_introduction));
enableAliasActionIfAvailable(
menu.findItem(R.id.action_set_alias));
return super.onCreateOptionsMenu(menu); return super.onCreateOptionsMenu(menu);
} }
@@ -293,7 +292,7 @@ public class ConversationActivity extends BriarActivity
startActivityForResult(intent, REQUEST_INTRODUCTION); startActivityForResult(intent, REQUEST_INTRODUCTION);
return true; return true;
case R.id.action_set_alias: case R.id.action_set_alias:
AliasDialogFragment.newInstance().show( AliasDialogFragment.newInstance(contactId).show(
getSupportFragmentManager(), AliasDialogFragment.TAG); getSupportFragmentManager(), AliasDialogFragment.TAG);
return true; return true;
case R.id.action_social_remove_person: case R.id.action_social_remove_person:
@@ -327,7 +326,7 @@ public class ConversationActivity extends BriarActivity
runOnDbThread(() -> { runOnDbThread(() -> {
try { try {
long start = now(); long start = now();
Collection<ConversationMessageHeader> headers = Collection<PrivateMessageHeader> headers =
conversationManager.getMessageHeaders(contactId); conversationManager.getMessageHeaders(contactId);
logDuration(LOG, "Loading messages", start); logDuration(LOG, "Loading messages", start);
displayMessages(revision, headers); displayMessages(revision, headers);
@@ -340,7 +339,7 @@ public class ConversationActivity extends BriarActivity
} }
private void displayMessages(int revision, private void displayMessages(int revision,
Collection<ConversationMessageHeader> headers) { Collection<PrivateMessageHeader> headers) {
runOnUiThreadUnlessDestroyed(() -> { runOnUiThreadUnlessDestroyed(() -> {
if (revision == adapter.getRevision()) { if (revision == adapter.getRevision()) {
adapter.incrementRevision(); adapter.incrementRevision();
@@ -364,10 +363,9 @@ public class ConversationActivity extends BriarActivity
*/ */
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
private List<ConversationItem> createItems( private List<ConversationItem> createItems(
Collection<ConversationMessageHeader> headers) { Collection<PrivateMessageHeader> headers) {
List<ConversationItem> items = new ArrayList<>(headers.size()); List<ConversationItem> items = new ArrayList<>(headers.size());
for (ConversationMessageHeader h : headers) for (PrivateMessageHeader h : headers) items.add(h.accept(visitor));
items.add(h.accept(visitor));
return items; return items;
} }
@@ -387,8 +385,8 @@ public class ConversationActivity extends BriarActivity
private void displayMessageText(MessageId m, String text) { private void displayMessageText(MessageId m, String text) {
runOnUiThreadUnlessDestroyed(() -> { runOnUiThreadUnlessDestroyed(() -> {
textCache.put(m, text); textCache.put(m, text);
SparseArray<ConversationMessageItem> messages = SparseArray<ConversationItem> messages =
adapter.getMessageItems(); adapter.getPrivateMessages();
for (int i = 0; i < messages.size(); i++) { for (int i = 0; i < messages.size(); i++) {
ConversationItem item = messages.valueAt(i); ConversationItem item = messages.valueAt(i);
if (item.getId().equals(m)) { if (item.getId().equals(m)) {
@@ -409,12 +407,11 @@ public class ConversationActivity extends BriarActivity
LOG.info("Contact removed"); LOG.info("Contact removed");
finishOnUiThread(); finishOnUiThread();
} }
} else if (e instanceof ConversationMessageReceivedEvent) { } else if (e instanceof PrivateMessageReceivedEvent) {
ConversationMessageReceivedEvent p = PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
(ConversationMessageReceivedEvent) e;
if (p.getContactId().equals(contactId)) { if (p.getContactId().equals(contactId)) {
LOG.info("Message received, adding"); LOG.info("Message received, adding");
onNewConversationMessage(p.getMessageHeader()); onNewPrivateMessage(p.getMessageHeader());
} }
} else if (e instanceof MessagesSentEvent) { } else if (e instanceof MessagesSentEvent) {
MessagesSentEvent m = (MessagesSentEvent) e; MessagesSentEvent m = (MessagesSentEvent) e;
@@ -452,16 +449,29 @@ public class ConversationActivity extends BriarActivity
}); });
} }
private void onNewConversationMessage(ConversationMessageHeader h) { private void onNewPrivateMessage(PrivateMessageHeader h) {
runOnUiThreadUnlessDestroyed(() -> { runOnUiThreadUnlessDestroyed(() -> {
if (h instanceof ConversationRequest || if (h instanceof PrivateRequest || h instanceof PrivateResponse) {
h instanceof ConversationResponse) { String cName = viewModel.getContactDisplayName().getValue();
// contact name might not have been loaded if (cName == null) {
observeOnce(viewModel.getContactDisplayName(), this, // Wait for the contact name to be loaded
name -> addConversationItem(h.accept(visitor))); viewModel.getContactDisplayName()
.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String cName) {
if (cName != null) {
addConversationItem(h.accept(visitor));
viewModel.getContactDisplayName()
.removeObserver(this);
}
}
});
} else {
addConversationItem(h.accept(visitor));
}
} else { } else {
// visitor also loads message text (if existing)
addConversationItem(h.accept(visitor)); addConversationItem(h.accept(visitor));
loadMessageText(h.getId());
} }
}); });
} }
@@ -471,9 +481,10 @@ public class ConversationActivity extends BriarActivity
runOnUiThreadUnlessDestroyed(() -> { runOnUiThreadUnlessDestroyed(() -> {
adapter.incrementRevision(); adapter.incrementRevision();
Set<MessageId> messages = new HashSet<>(messageIds); Set<MessageId> messages = new HashSet<>(messageIds);
SparseArray<ConversationItem> list = adapter.getOutgoingMessages(); SparseArray<ConversationOutItem> list =
adapter.getOutgoingMessages();
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
ConversationItem item = list.valueAt(i); ConversationOutItem item = list.valueAt(i);
if (messages.contains(item.getId())) { if (messages.contains(item.getId())) {
item.setSent(sent); item.setSent(sent);
item.setSeen(seen); item.setSeen(seen);
@@ -518,7 +529,7 @@ public class ConversationActivity extends BriarActivity
try { try {
//noinspection ConstantConditions init in loadGroupId() //noinspection ConstantConditions init in loadGroupId()
storeMessage(privateMessageFactory.createPrivateMessage( storeMessage(privateMessageFactory.createPrivateMessage(
messagingGroupId, timestamp, text, emptyList()), text); messagingGroupId, timestamp, text), text);
} catch (FormatException e) { } catch (FormatException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -534,8 +545,7 @@ public class ConversationActivity extends BriarActivity
Message message = m.getMessage(); Message message = m.getMessage();
PrivateMessageHeader h = new PrivateMessageHeader( PrivateMessageHeader h = new PrivateMessageHeader(
message.getId(), message.getGroupId(), message.getId(), message.getGroupId(),
message.getTimestamp(), true, false, false, false, message.getTimestamp(), true, false, false, false);
true, emptyList());
textCache.put(message.getId(), text); textCache.put(message.getId(), text);
addConversationItem(h.accept(visitor)); addConversationItem(h.accept(visitor));
} catch (DbException e) { } catch (DbException e) {
@@ -596,10 +606,6 @@ public class ConversationActivity extends BriarActivity
}); });
} }
private void enableAliasActionIfAvailable(MenuItem item) {
observeOnce(viewModel.getContact(), this, c -> item.setEnabled(true));
}
private void enableIntroductionAction(MenuItem item) { private void enableIntroductionAction(MenuItem item) {
runOnUiThreadUnlessDestroyed(() -> item.setEnabled(true)); runOnUiThreadUnlessDestroyed(() -> item.setEnabled(true));
} }

View File

@@ -1,7 +1,8 @@
package org.briarproject.briar.android.conversation; package org.briarproject.briar.android.contact;
import android.content.Context; import android.content.Context;
import android.support.annotation.LayoutRes; import android.support.annotation.LayoutRes;
import android.support.annotation.UiThread;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -13,14 +14,12 @@ import org.briarproject.briar.android.util.BriarAdapter;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@NotNullByDefault
class ConversationAdapter class ConversationAdapter
extends BriarAdapter<ConversationItem, ConversationItemViewHolder> { extends BriarAdapter<ConversationItem, ConversationItemViewHolder> {
private ConversationListener listener; private ConversationListener listener;
ConversationAdapter(Context ctx, ConversationAdapter(Context ctx, ConversationListener conversationListener) {
ConversationListener conversationListener) {
super(ctx, ConversationItem.class); super(ctx, ConversationItem.class);
listener = conversationListener; listener = conversationListener;
} }
@@ -39,15 +38,15 @@ class ConversationAdapter
type, viewGroup, false); type, viewGroup, false);
switch (type) { switch (type) {
case R.layout.list_item_conversation_msg_in: case R.layout.list_item_conversation_msg_in:
return new ConversationMessageViewHolder(v, true); return new ConversationItemViewHolder(v);
case R.layout.list_item_conversation_msg_out: case R.layout.list_item_conversation_msg_out:
return new ConversationMessageViewHolder(v, false); return new ConversationMessageOutViewHolder(v);
case R.layout.list_item_conversation_notice_in: case R.layout.list_item_conversation_notice_in:
return new ConversationNoticeViewHolder(v, true); return new ConversationNoticeInViewHolder(v);
case R.layout.list_item_conversation_notice_out: case R.layout.list_item_conversation_notice_out:
return new ConversationNoticeViewHolder(v, false); return new ConversationNoticeOutViewHolder(v);
case R.layout.list_item_conversation_request: case R.layout.list_item_conversation_request:
return new ConversationRequestViewHolder(v, true); return new ConversationRequestViewHolder(v);
default: default:
throw new IllegalArgumentException("Unknown ConversationItem"); throw new IllegalArgumentException("Unknown ConversationItem");
} }
@@ -56,13 +55,22 @@ class ConversationAdapter
@Override @Override
public void onBindViewHolder(ConversationItemViewHolder ui, int position) { public void onBindViewHolder(ConversationItemViewHolder ui, int position) {
ConversationItem item = items.get(position); ConversationItem item = items.get(position);
ui.bind(item, listener); if (item instanceof ConversationRequestItem) {
((ConversationRequestViewHolder) ui).bind(item, listener);
} else {
ui.bind(item);
}
listener.onItemVisible(item); listener.onItemVisible(item);
} }
@Override @Override
public int compare(ConversationItem c1, ConversationItem c2) { public int compare(ConversationItem c1,
return Long.compare(c1.getTime(), c2.getTime()); ConversationItem c2) {
long time1 = c1.getTime();
long time2 = c2.getTime();
if (time1 < time2) return -1;
if (time1 > time2) return 1;
return 0;
} }
@Override @Override
@@ -86,28 +94,54 @@ class ConversationAdapter
} }
} }
SparseArray<ConversationItem> getOutgoingMessages() { SparseArray<ConversationItem> getIncomingMessages() {
SparseArray<ConversationItem> messages = new SparseArray<>(); SparseArray<ConversationItem> messages = new SparseArray<>();
for (int i = 0; i < items.size(); i++) { for (int i = 0; i < items.size(); i++) {
ConversationItem item = items.get(i); ConversationItem item = items.get(i);
if (!item.isIncoming()) { if (item.isIncoming()) {
messages.put(i, item); messages.put(i, item);
} }
} }
return messages; return messages;
} }
SparseArray<ConversationMessageItem> getMessageItems() { SparseArray<ConversationOutItem> getOutgoingMessages() {
SparseArray<ConversationMessageItem> messages = new SparseArray<>(); SparseArray<ConversationOutItem> messages = new SparseArray<>();
for (int i = 0; i < items.size(); i++) { for (int i = 0; i < items.size(); i++) {
ConversationItem item = items.get(i); ConversationItem item = items.get(i);
if (item instanceof ConversationMessageItem) { if (item instanceof ConversationOutItem) {
messages.put(i, (ConversationMessageItem) item); messages.put(i, (ConversationOutItem) item);
} }
} }
return messages; return messages;
} }
SparseArray<ConversationItem> getPrivateMessages() {
SparseArray<ConversationItem> messages = new SparseArray<>();
for (int i = 0; i < items.size(); i++) {
ConversationItem item = items.get(i);
if (item instanceof ConversationMessageInItem) {
messages.put(i, item);
} else if (item instanceof ConversationMessageOutItem) {
messages.put(i, item);
}
}
return messages;
}
@UiThread
@NotNullByDefault
interface ConversationListener {
void onItemVisible(ConversationItem item);
void respondToRequest(ConversationRequestItem item, boolean accept);
void openRequestedShareable(ConversationRequestItem item);
}
} }

View File

@@ -0,0 +1,61 @@
package org.briarproject.briar.android.contact;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
abstract class ConversationItem {
@Nullable
protected String text;
private final MessageId id;
private final GroupId groupId;
private final long time;
private boolean read;
ConversationItem(MessageId id, GroupId groupId, @Nullable String text,
long time, boolean read) {
this.id = id;
this.groupId = groupId;
this.text = text;
this.time = time;
this.read = read;
}
MessageId getId() {
return id;
}
GroupId getGroupId() {
return groupId;
}
void setText(String text) {
this.text = text;
}
@Nullable
public String getText() {
return text;
}
long getTime() {
return time;
}
public boolean isRead() {
return read;
}
abstract public boolean isIncoming();
@LayoutRes
abstract public int getLayout();
}

View File

@@ -0,0 +1,42 @@
package org.briarproject.briar.android.contact;
import android.support.annotation.CallSuper;
import android.support.annotation.UiThread;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.R;
import org.briarproject.briar.android.util.UiUtils;
@UiThread
@NotNullByDefault
class ConversationItemViewHolder extends ViewHolder {
protected final ViewGroup layout;
private final TextView text;
private final TextView time;
ConversationItemViewHolder(View v) {
super(v);
layout = v.findViewById(R.id.layout);
text = v.findViewById(R.id.text);
time = v.findViewById(R.id.time);
}
@CallSuper
void bind(ConversationItem item) {
if (item.getText() == null) {
text.setText("\u2026");
} else {
text.setText(StringUtils.trim(item.getText()));
}
long timestamp = item.getTime();
time.setText(UiUtils.formatDate(time.getContext(), timestamp));
}
}

View File

@@ -0,0 +1,30 @@
package org.briarproject.briar.android.contact;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
class ConversationMessageInItem extends ConversationItem {
ConversationMessageInItem(PrivateMessageHeader h) {
super(h.getId(), h.getGroupId(), null, h.getTimestamp(), h.isRead());
}
@Override
public boolean isIncoming() {
return true;
}
@LayoutRes
@Override
public int getLayout() {
return R.layout.list_item_conversation_msg_in;
}
}

View File

@@ -0,0 +1,26 @@
package org.briarproject.briar.android.contact;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
class ConversationMessageOutItem extends ConversationOutItem {
ConversationMessageOutItem(PrivateMessageHeader h) {
super(h.getId(), h.getGroupId(), null, h.getTimestamp(), h.isSent(),
h.isSeen());
}
@LayoutRes
@Override
public int getLayout() {
return R.layout.list_item_conversation_msg_out;
}
}

View File

@@ -0,0 +1,16 @@
package org.briarproject.briar.android.contact;
import android.view.View;
class ConversationMessageOutViewHolder extends ConversationOutItemViewHolder {
ConversationMessageOutViewHolder(View v) {
super(v);
}
@Override
protected boolean hasDarkBackground() {
return true;
}
}

View File

@@ -0,0 +1,47 @@
package org.briarproject.briar.android.contact;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R;
import org.briarproject.briar.api.messaging.PrivateResponse;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
class ConversationNoticeInItem extends ConversationItem {
@Nullable
private final String msgText;
ConversationNoticeInItem(MessageId id, GroupId groupId, String text,
@Nullable String msgText, long time, boolean read) {
super(id, groupId, text, time, read);
this.msgText = msgText;
}
ConversationNoticeInItem(String text, PrivateResponse r) {
super(r.getId(), r.getGroupId(), text, r.getTimestamp(), r.isRead());
this.msgText = null;
}
@Nullable
String getMsgText() {
return msgText;
}
@Override
public boolean isIncoming() {
return true;
}
@LayoutRes
@Override
public int getLayout() {
return R.layout.list_item_conversation_notice_in;
}
}

View File

@@ -0,0 +1,43 @@
package org.briarproject.briar.android.contact;
import android.support.annotation.UiThread;
import android.view.View;
import android.widget.TextView;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.R;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
@UiThread
@NotNullByDefault
class ConversationNoticeInViewHolder extends ConversationItemViewHolder {
private final TextView msgText;
ConversationNoticeInViewHolder(View v) {
super(v);
msgText = v.findViewById(R.id.msgText);
}
@Override
void bind(ConversationItem conversationItem) {
super.bind(conversationItem);
ConversationNoticeInItem item =
(ConversationNoticeInItem) conversationItem;
String text = item.getMsgText();
if (StringUtils.isNullOrEmpty(text)) {
msgText.setVisibility(GONE);
layout.setBackgroundResource(R.drawable.notice_in);
} else {
msgText.setVisibility(VISIBLE);
msgText.setText(StringUtils.trim(text));
layout.setBackgroundResource(R.drawable.notice_in_bottom);
}
}
}

View File

@@ -0,0 +1,42 @@
package org.briarproject.briar.android.contact;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.messaging.PrivateResponse;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
class ConversationNoticeOutItem extends ConversationOutItem {
@Nullable
private final String msgText;
ConversationNoticeOutItem(String text, PrivateRequest r) {
super(r.getId(), r.getGroupId(), text, r.getTimestamp(), r.isSent(),
r.isSeen());
this.msgText = r.getText();
}
ConversationNoticeOutItem(String text, PrivateResponse r) {
super(r.getId(), r.getGroupId(), text, r.getTimestamp(), r.isSent(),
r.isSeen());
this.msgText = null;
}
@Nullable
String getMsgText() {
return msgText;
}
@LayoutRes
@Override
public int getLayout() {
return R.layout.list_item_conversation_notice_out;
}
}

View File

@@ -0,0 +1,48 @@
package org.briarproject.briar.android.contact;
import android.support.annotation.UiThread;
import android.view.View;
import android.widget.TextView;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.R;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
@UiThread
@NotNullByDefault
class ConversationNoticeOutViewHolder extends ConversationOutItemViewHolder {
private final TextView msgText;
ConversationNoticeOutViewHolder(View v) {
super(v);
msgText = v.findViewById(R.id.msgText);
}
@Override
void bind(ConversationItem conversationItem) {
super.bind(conversationItem);
ConversationNoticeOutItem item =
(ConversationNoticeOutItem) conversationItem;
String text = item.getMsgText();
if (StringUtils.isNullOrEmpty(text)) {
msgText.setVisibility(GONE);
layout.setBackgroundResource(R.drawable.notice_out);
} else {
msgText.setVisibility(VISIBLE);
msgText.setText(StringUtils.trim(text));
layout.setBackgroundResource(R.drawable.notice_out_bottom);
}
}
@Override
protected boolean hasDarkBackground() {
return false;
}
}

View File

@@ -0,0 +1,45 @@
package org.briarproject.briar.android.contact;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
abstract class ConversationOutItem extends ConversationItem {
private boolean sent, seen;
ConversationOutItem(MessageId id, GroupId groupId, @Nullable String text,
long time, boolean sent, boolean seen) {
super(id, groupId, text, time, true);
this.sent = sent;
this.seen = seen;
}
boolean isSent() {
return sent;
}
void setSent(boolean sent) {
this.sent = sent;
}
boolean isSeen() {
return seen;
}
void setSeen(boolean seen) {
this.seen = seen;
}
@Override
public boolean isIncoming() {
return false;
}
}

View File

@@ -0,0 +1,44 @@
package org.briarproject.briar.android.contact;
import android.support.annotation.UiThread;
import android.view.View;
import android.widget.ImageView;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
@UiThread
@NotNullByDefault
abstract class ConversationOutItemViewHolder
extends ConversationItemViewHolder {
private final ImageView status;
ConversationOutItemViewHolder(View v) {
super(v);
status = v.findViewById(R.id.status);
}
@Override
void bind(ConversationItem conversationItem) {
super.bind(conversationItem);
ConversationOutItem item = (ConversationOutItem) conversationItem;
int res;
if (item.isSeen()) {
if (hasDarkBackground()) res = R.drawable.message_delivered_white;
else res = R.drawable.message_delivered;
} else if (item.isSent()) {
if (hasDarkBackground()) res = R.drawable.message_sent_white;
else res = R.drawable.message_sent;
} else {
if (hasDarkBackground()) res = R.drawable.message_stored_white;
else res = R.drawable.message_stored;
}
status.setImageResource(res);
}
protected abstract boolean hasDarkBackground();
}

View File

@@ -1,11 +1,12 @@
package org.briarproject.briar.android.conversation; package org.briarproject.briar.android.contact;
import android.support.annotation.LayoutRes; import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.briar.R;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.conversation.ConversationRequest; import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.sharing.InvitationRequest; import org.briarproject.briar.api.sharing.InvitationRequest;
import org.briarproject.briar.api.sharing.Shareable; import org.briarproject.briar.api.sharing.Shareable;
@@ -14,7 +15,7 @@ import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
class ConversationRequestItem extends ConversationNoticeItem { class ConversationRequestItem extends ConversationNoticeInItem {
enum RequestType {INTRODUCTION, FORUM, BLOG, GROUP} enum RequestType {INTRODUCTION, FORUM, BLOG, GROUP}
@@ -25,9 +26,9 @@ class ConversationRequestItem extends ConversationNoticeItem {
private final boolean canBeOpened; private final boolean canBeOpened;
private boolean answered; private boolean answered;
ConversationRequestItem(@LayoutRes int layoutRes, String text, ConversationRequestItem(String text, RequestType type, PrivateRequest r) {
RequestType type, ConversationRequest r) { super(r.getId(), r.getGroupId(), text, r.getText(),
super(layoutRes, text, r); r.getTimestamp(), r.isRead());
this.requestType = type; this.requestType = type;
this.sessionId = r.getSessionId(); this.sessionId = r.getSessionId();
this.answered = r.wasAnswered(); this.answered = r.wasAnswered();
@@ -49,7 +50,7 @@ class ConversationRequestItem extends ConversationNoticeItem {
} }
@Nullable @Nullable
GroupId getRequestedGroupId() { public GroupId getRequestedGroupId() {
return requestedGroupId; return requestedGroupId;
} }
@@ -61,8 +62,13 @@ class ConversationRequestItem extends ConversationNoticeItem {
this.answered = true; this.answered = true;
} }
boolean canBeOpened() { public boolean canBeOpened() {
return canBeOpened; return canBeOpened;
} }
@LayoutRes
@Override
public int getLayout() {
return R.layout.list_item_conversation_request;
}
} }

View File

@@ -1,4 +1,4 @@
package org.briarproject.briar.android.conversation; package org.briarproject.briar.android.contact;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
import android.view.View; import android.view.View;
@@ -6,35 +6,38 @@ import android.widget.Button;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.contact.ConversationAdapter.ConversationListener;
import static android.view.View.GONE; import static android.view.View.GONE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
@UiThread @UiThread
@NotNullByDefault @NotNullByDefault
class ConversationRequestViewHolder extends ConversationNoticeViewHolder { class ConversationRequestViewHolder extends ConversationNoticeInViewHolder {
private final Button acceptButton; private final Button acceptButton;
private final Button declineButton; private final Button declineButton;
ConversationRequestViewHolder(View v, boolean isIncoming) { ConversationRequestViewHolder(View v) {
super(v, isIncoming); super(v);
acceptButton = v.findViewById(R.id.acceptButton); acceptButton = v.findViewById(R.id.acceptButton);
declineButton = v.findViewById(R.id.declineButton); declineButton = v.findViewById(R.id.declineButton);
} }
@Override void bind(ConversationItem conversationItem,
void bind(ConversationItem item, ConversationListener listener) { ConversationListener listener) {
ConversationRequestItem request = (ConversationRequestItem) item; super.bind(conversationItem);
super.bind(request, listener);
if (request.wasAnswered() && request.canBeOpened()) { ConversationRequestItem item =
(ConversationRequestItem) conversationItem;
if (item.wasAnswered() && item.canBeOpened()) {
acceptButton.setVisibility(VISIBLE); acceptButton.setVisibility(VISIBLE);
acceptButton.setText(R.string.open); acceptButton.setText(R.string.open);
acceptButton.setOnClickListener( acceptButton.setOnClickListener(
v -> listener.openRequestedShareable(request)); v -> listener.openRequestedShareable(item));
declineButton.setVisibility(GONE); declineButton.setVisibility(GONE);
} else if (request.wasAnswered()) { } else if (item.wasAnswered()) {
acceptButton.setVisibility(GONE); acceptButton.setVisibility(GONE);
declineButton.setVisibility(GONE); declineButton.setVisibility(GONE);
} else { } else {
@@ -43,13 +46,13 @@ class ConversationRequestViewHolder extends ConversationNoticeViewHolder {
acceptButton.setOnClickListener(v -> { acceptButton.setOnClickListener(v -> {
acceptButton.setEnabled(false); acceptButton.setEnabled(false);
declineButton.setEnabled(false); declineButton.setEnabled(false);
listener.respondToRequest(request, true); listener.respondToRequest(item, true);
}); });
declineButton.setVisibility(VISIBLE); declineButton.setVisibility(VISIBLE);
declineButton.setOnClickListener(v -> { declineButton.setOnClickListener(v -> {
acceptButton.setEnabled(false); acceptButton.setEnabled(false);
declineButton.setEnabled(false); declineButton.setEnabled(false);
listener.respondToRequest(request, false); listener.respondToRequest(item, false);
}); });
} }
} }

View File

@@ -1,11 +1,11 @@
package org.briarproject.briar.android.conversation; package org.briarproject.briar.android.contact;
import android.app.Application; import android.app.Application;
import android.arch.lifecycle.AndroidViewModel; import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData; import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData; import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.Transformations; import android.arch.lifecycle.Transformations;
import android.support.annotation.Nullable; import android.support.annotation.NonNull;
import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
@@ -14,7 +14,8 @@ import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchContactException; import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.android.AndroidComponent;
import org.briarproject.briar.android.BriarApplication;
import org.briarproject.briar.android.util.UiUtils; import org.briarproject.briar.android.util.UiUtils;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -22,25 +23,22 @@ import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@NotNullByDefault
public class ConversationViewModel extends AndroidViewModel { public class ConversationViewModel extends AndroidViewModel {
private static Logger LOG = private static Logger LOG =
getLogger(ConversationViewModel.class.getName()); Logger.getLogger(ConversationViewModel.class.getName());
@Inject
@DatabaseExecutor @DatabaseExecutor
private final Executor dbExecutor; Executor dbExecutor;
private final ContactManager contactManager; @Inject
ContactManager contactManager;
@Nullable
private ContactId contactId = null;
private final MutableLiveData<Contact> contact = new MutableLiveData<>(); private final MutableLiveData<Contact> contact = new MutableLiveData<>();
private final LiveData<AuthorId> contactAuthorId = private final LiveData<AuthorId> contactAuthorId =
Transformations.map(contact, c -> c.getAuthor().getId()); Transformations.map(contact, c -> c.getAuthor().getId());
@@ -49,32 +47,19 @@ public class ConversationViewModel extends AndroidViewModel {
private final MutableLiveData<Boolean> contactDeleted = private final MutableLiveData<Boolean> contactDeleted =
new MutableLiveData<>(); new MutableLiveData<>();
@Inject public ConversationViewModel(@NonNull Application application) {
ConversationViewModel(Application application,
@DatabaseExecutor Executor dbExecutor,
ContactManager contactManager) {
super(application); super(application);
this.dbExecutor = dbExecutor; AndroidComponent component =
this.contactManager = contactManager; ((BriarApplication) application).getApplicationComponent();
component.inject(this);
contactDeleted.setValue(false); contactDeleted.setValue(false);
} }
void setContactId(ContactId contactId) { void loadContact(ContactId contactId) {
if (this.contactId == null) {
this.contactId = contactId;
loadContact();
} else if (!contactId.equals(this.contactId)) {
throw new IllegalStateException();
}
}
private void loadContact() {
dbExecutor.execute(() -> { dbExecutor.execute(() -> {
try { try {
long start = now(); long start = now();
Contact c = contact.postValue(contactManager.getContact(contactId));
contactManager.getContact(requireNonNull(contactId));
contact.postValue(c);
logDuration(LOG, "Loading contact", start); logDuration(LOG, "Loading contact", start);
} catch (NoSuchContactException e) { } catch (NoSuchContactException e) {
contactDeleted.postValue(true); contactDeleted.postValue(true);
@@ -84,12 +69,12 @@ public class ConversationViewModel extends AndroidViewModel {
}); });
} }
void setContactAlias(String alias) { void setContactAlias(ContactId contactId, String alias) {
dbExecutor.execute(() -> { dbExecutor.execute(() -> {
try { try {
contactManager.setContactAlias(requireNonNull(contactId), contactManager.setContactAlias(contactId,
alias.isEmpty() ? null : alias); alias.isEmpty() ? null : alias);
loadContact(); loadContact(contactId);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
} }

View File

@@ -1,4 +1,4 @@
package org.briarproject.briar.android.conversation; package org.briarproject.briar.android.contact;
import android.arch.lifecycle.LiveData; import android.arch.lifecycle.LiveData;
import android.content.Context; import android.content.Context;
@@ -14,22 +14,21 @@ import org.briarproject.briar.api.forum.ForumInvitationResponse;
import org.briarproject.briar.api.introduction.IntroductionRequest; import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.IntroductionResponse; import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.messaging.PrivateMessageHeader; import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.conversation.ConversationMessageVisitor; import org.briarproject.briar.api.messaging.PrivateMessageVisitor;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static org.briarproject.briar.android.conversation.ConversationRequestItem.RequestType.BLOG; import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.BLOG;
import static org.briarproject.briar.android.conversation.ConversationRequestItem.RequestType.FORUM; import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.FORUM;
import static org.briarproject.briar.android.conversation.ConversationRequestItem.RequestType.GROUP; import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.GROUP;
import static org.briarproject.briar.android.conversation.ConversationRequestItem.RequestType.INTRODUCTION; import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.INTRODUCTION;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName; import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
@UiThread @UiThread
@NotNullByDefault @NotNullByDefault
class ConversationVisitor implements class ConversationVisitor implements PrivateMessageVisitor<ConversationItem> {
ConversationMessageVisitor<ConversationItem> {
private final Context ctx; private final Context ctx;
private final TextCache textCache; private final TextCache textCache;
@@ -45,17 +44,10 @@ class ConversationVisitor implements
@Override @Override
public ConversationItem visitPrivateMessageHeader(PrivateMessageHeader h) { public ConversationItem visitPrivateMessageHeader(PrivateMessageHeader h) {
ConversationItem item; ConversationItem item;
if (h.isLocal()) { if (h.isLocal()) item = new ConversationMessageOutItem(h);
item = new ConversationMessageItem( else item = new ConversationMessageInItem(h);
R.layout.list_item_conversation_msg_out, h); String text = textCache.getText(h.getId());
} else { if (text != null) item.setText(text);
item = new ConversationMessageItem(
R.layout.list_item_conversation_msg_in, h);
}
if (h.hasText()) {
String text = textCache.getText(h.getId());
if (text != null) item.setText(text);
}
return item; return item;
} }
@@ -65,14 +57,12 @@ class ConversationVisitor implements
if (r.isLocal()) { if (r.isLocal()) {
String text = ctx.getString(R.string.blogs_sharing_invitation_sent, String text = ctx.getString(R.string.blogs_sharing_invitation_sent,
r.getName(), contactName.getValue()); r.getName(), contactName.getValue());
return new ConversationNoticeItem( return new ConversationNoticeOutItem(text, r);
R.layout.list_item_conversation_notice_out, text, r);
} else { } else {
String text = ctx.getString( String text = ctx.getString(
R.string.blogs_sharing_invitation_received, R.string.blogs_sharing_invitation_received,
contactName.getValue(), r.getName()); contactName.getValue(), r.getName());
return new ConversationRequestItem( return new ConversationRequestItem(text, BLOG, r);
R.layout.list_item_conversation_request, text, BLOG, r);
} }
} }
@@ -90,8 +80,7 @@ class ConversationVisitor implements
R.string.blogs_sharing_response_declined_sent, R.string.blogs_sharing_response_declined_sent,
contactName.getValue()); contactName.getValue());
} }
return new ConversationNoticeItem( return new ConversationNoticeOutItem(text, r);
R.layout.list_item_conversation_notice_out, text, r);
} else { } else {
String text; String text;
if (r.wasAccepted()) { if (r.wasAccepted()) {
@@ -103,8 +92,7 @@ class ConversationVisitor implements
R.string.blogs_sharing_response_declined_received, R.string.blogs_sharing_response_declined_received,
contactName.getValue()); contactName.getValue());
} }
return new ConversationNoticeItem( return new ConversationNoticeInItem(text, r);
R.layout.list_item_conversation_notice_in, text, r);
} }
} }
@@ -114,14 +102,12 @@ class ConversationVisitor implements
if (r.isLocal()) { if (r.isLocal()) {
String text = ctx.getString(R.string.forum_invitation_sent, String text = ctx.getString(R.string.forum_invitation_sent,
r.getName(), contactName.getValue()); r.getName(), contactName.getValue());
return new ConversationNoticeItem( return new ConversationNoticeOutItem(text, r);
R.layout.list_item_conversation_notice_out, text, r);
} else { } else {
String text = ctx.getString( String text = ctx.getString(
R.string.forum_invitation_received, R.string.forum_invitation_received,
contactName.getValue(), r.getName()); contactName.getValue(), r.getName());
return new ConversationRequestItem( return new ConversationRequestItem(text, FORUM, r);
R.layout.list_item_conversation_request, text, FORUM, r);
} }
} }
@@ -139,8 +125,7 @@ class ConversationVisitor implements
R.string.forum_invitation_response_declined_sent, R.string.forum_invitation_response_declined_sent,
contactName.getValue()); contactName.getValue());
} }
return new ConversationNoticeItem( return new ConversationNoticeOutItem(text, r);
R.layout.list_item_conversation_notice_out, text, r);
} else { } else {
String text; String text;
if (r.wasAccepted()) { if (r.wasAccepted()) {
@@ -152,8 +137,7 @@ class ConversationVisitor implements
R.string.forum_invitation_response_declined_received, R.string.forum_invitation_response_declined_received,
contactName.getValue()); contactName.getValue());
} }
return new ConversationNoticeItem( return new ConversationNoticeInItem(text, r);
R.layout.list_item_conversation_notice_in, text, r);
} }
} }
@@ -164,14 +148,12 @@ class ConversationVisitor implements
String text = ctx.getString( String text = ctx.getString(
R.string.groups_invitations_invitation_sent, R.string.groups_invitations_invitation_sent,
contactName.getValue(), r.getName()); contactName.getValue(), r.getName());
return new ConversationNoticeItem( return new ConversationNoticeOutItem(text, r);
R.layout.list_item_conversation_notice_out, text, r);
} else { } else {
String text = ctx.getString( String text = ctx.getString(
R.string.groups_invitations_invitation_received, R.string.groups_invitations_invitation_received,
contactName.getValue(), r.getName()); contactName.getValue(), r.getName());
return new ConversationRequestItem( return new ConversationRequestItem(text, GROUP, r);
R.layout.list_item_conversation_request, text, GROUP, r);
} }
} }
@@ -189,8 +171,7 @@ class ConversationVisitor implements
R.string.groups_invitations_response_declined_sent, R.string.groups_invitations_response_declined_sent,
contactName.getValue()); contactName.getValue());
} }
return new ConversationNoticeItem( return new ConversationNoticeOutItem(text, r);
R.layout.list_item_conversation_notice_out, text, r);
} else { } else {
String text; String text;
if (r.wasAccepted()) { if (r.wasAccepted()) {
@@ -202,8 +183,7 @@ class ConversationVisitor implements
R.string.groups_invitations_response_declined_received, R.string.groups_invitations_response_declined_received,
contactName.getValue()); contactName.getValue());
} }
return new ConversationNoticeItem( return new ConversationNoticeInItem(text, r);
R.layout.list_item_conversation_notice_in, text, r);
} }
} }
@@ -213,14 +193,11 @@ class ConversationVisitor implements
if (r.isLocal()) { if (r.isLocal()) {
String text = ctx.getString(R.string.introduction_request_sent, String text = ctx.getString(R.string.introduction_request_sent,
contactName.getValue(), name); contactName.getValue(), name);
return new ConversationNoticeItem( return new ConversationNoticeOutItem(text, r);
R.layout.list_item_conversation_notice_out, text, r);
} else { } else {
String text = ctx.getString(R.string.introduction_request_received, String text = ctx.getString(R.string.introduction_request_received,
contactName.getValue(), name); contactName.getValue(), name);
return new ConversationRequestItem( return new ConversationRequestItem(text, INTRODUCTION, r);
R.layout.list_item_conversation_request, text, INTRODUCTION,
r);
} }
} }
@@ -243,8 +220,7 @@ class ConversationVisitor implements
R.string.introduction_response_declined_sent, R.string.introduction_response_declined_sent,
introducedAuthor); introducedAuthor);
} }
return new ConversationNoticeItem( return new ConversationNoticeOutItem(text, r);
R.layout.list_item_conversation_notice_out, text, r);
} else { } else {
String text; String text;
if (r.wasAccepted()) { if (r.wasAccepted()) {
@@ -263,8 +239,7 @@ class ConversationVisitor implements
contactName.getValue(), contactName.getValue(),
introducedAuthor); introducedAuthor);
} }
return new ConversationNoticeItem( return new ConversationNoticeInItem(text, r);
R.layout.list_item_conversation_notice_in, text, r);
} }
} }

View File

@@ -1,104 +0,0 @@
package org.briarproject.briar.android.conversation;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
abstract class ConversationItem {
@LayoutRes
private final int layoutRes;
@Nullable
protected String text;
private final MessageId id;
private final GroupId groupId;
private final long time;
private final boolean isIncoming;
private boolean read, sent, seen;
ConversationItem(@LayoutRes int layoutRes, ConversationMessageHeader h) {
this.layoutRes = layoutRes;
this.text = null;
this.id = h.getId();
this.groupId = h.getGroupId();
this.time = h.getTimestamp();
this.read = h.isRead();
this.sent = h.isSent();
this.seen = h.isSeen();
this.isIncoming = !h.isLocal();
}
@LayoutRes
int getLayout() {
return layoutRes;
}
MessageId getId() {
return id;
}
GroupId getGroupId() {
return groupId;
}
void setText(String text) {
this.text = text;
}
@Nullable
String getText() {
return text;
}
long getTime() {
return time;
}
/**
* Only useful for incoming messages.
*/
boolean isRead() {
return read;
}
/**
* Only useful for outgoing messages.
*/
boolean isSent() {
return sent;
}
/**
* Only useful for outgoing messages.
*/
void setSent(boolean sent) {
this.sent = sent;
}
/**
* Only useful for outgoing messages.
*/
boolean isSeen() {
return seen;
}
/**
* Only useful for outgoing messages.
*/
void setSeen(boolean seen) {
this.seen = seen;
}
boolean isIncoming() {
return isIncoming;
}
}

View File

@@ -1,51 +0,0 @@
package org.briarproject.briar.android.conversation;
import android.support.annotation.CallSuper;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
import static org.briarproject.bramble.util.StringUtils.trim;
import static org.briarproject.briar.android.util.UiUtils.formatDate;
@UiThread
@NotNullByDefault
abstract class ConversationItemViewHolder extends ViewHolder {
protected final ViewGroup layout;
@Nullable
private final OutItemViewHolder outViewHolder;
private final TextView text;
private final TextView time;
ConversationItemViewHolder(View v, boolean isIncoming) {
super(v);
this.outViewHolder = isIncoming ? null : new OutItemViewHolder(v);
layout = v.findViewById(R.id.layout);
text = v.findViewById(R.id.text);
time = v.findViewById(R.id.time);
}
@CallSuper
void bind(ConversationItem item, ConversationListener listener) {
if (item.getText() != null) {
text.setText(trim(item.getText()));
}
long timestamp = item.getTime();
time.setText(formatDate(time.getContext(), timestamp));
if (outViewHolder != null) outViewHolder.bind(item);
}
boolean isIncoming() {
return outViewHolder == null;
}
}

View File

@@ -1,17 +0,0 @@
package org.briarproject.briar.android.conversation;
import android.support.annotation.UiThread;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@UiThread
@NotNullByDefault
interface ConversationListener {
void onItemVisible(ConversationItem item);
void respondToRequest(ConversationRequestItem item, boolean accept);
void openRequestedShareable(ConversationRequestItem item);
}

View File

@@ -1,28 +0,0 @@
package org.briarproject.briar.android.conversation;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.messaging.AttachmentHeader;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
class ConversationMessageItem extends ConversationItem {
private final List<AttachmentHeader> attachments;
ConversationMessageItem(@LayoutRes int layoutRes, PrivateMessageHeader h) {
super(layoutRes, h);
this.attachments = h.getAttachmentHeaders();
}
List<AttachmentHeader> getAttachments() {
return attachments;
}
}

View File

@@ -1,18 +0,0 @@
package org.briarproject.briar.android.conversation;
import android.support.annotation.UiThread;
import android.view.View;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@UiThread
@NotNullByDefault
class ConversationMessageViewHolder extends ConversationItemViewHolder {
// image support will be added here (#1242)
ConversationMessageViewHolder(View v, boolean isIncoming) {
super(v, isIncoming);
}
}

Some files were not shown because too many files have changed in this diff Show More