Skip to content

Commit 75a0c98

Browse files
Merge branch '38-network-state-provider' into 'sync'
#38 Add NetworkStateProvider API. See merge request objectbox/objectbox-java!47
2 parents b89b8da + 6b75d80 commit 75a0c98

File tree

8 files changed

+337
-0
lines changed

8 files changed

+337
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package io.objectbox.sync;
2+
3+
import javax.annotation.Nullable;
4+
5+
/**
6+
* Used by {@link SyncClient} to observe connectivity changes.
7+
* <p>
8+
* Implementations are provided by a {@link io.objectbox.sync.internal.Platform platform}.
9+
*/
10+
public abstract class ConnectivityMonitor {
11+
12+
@Nullable
13+
private SyncClient syncClient;
14+
15+
void setObserver(SyncClient syncClient) {
16+
//noinspection ConstantConditions Annotations do not enforce non-null.
17+
if (syncClient == null) {
18+
throw new IllegalArgumentException("Sync client must not be null");
19+
}
20+
this.syncClient = syncClient;
21+
onObserverSet();
22+
}
23+
24+
void removeObserver() {
25+
this.syncClient = null;
26+
onObserverRemoved();
27+
}
28+
29+
/**
30+
* Called right after the observer was set.
31+
*/
32+
public void onObserverSet() {
33+
}
34+
35+
/**
36+
* Called right after the observer was removed.
37+
*/
38+
public void onObserverRemoved() {
39+
}
40+
41+
/**
42+
* Notifies the observer that a connection is available.
43+
* Implementers should call this once a working network connection is available.
44+
*/
45+
public final void notifyConnectionAvailable() {
46+
SyncClient syncClient = this.syncClient;
47+
if (syncClient != null) {
48+
syncClient.notifyConnectionAvailable();
49+
}
50+
}
51+
52+
}

objectbox-java/src/main/java/io/objectbox/sync/SyncBuilder.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.objectbox.BoxStore;
44
import io.objectbox.annotation.apihint.Experimental;
5+
import io.objectbox.sync.internal.Platform;
56

67
import javax.annotation.Nullable;
78

@@ -13,6 +14,7 @@
1314
@SuppressWarnings({"unused", "WeakerAccess"})
1415
public class SyncBuilder {
1516

17+
final Platform platform;
1618
final BoxStore boxStore;
1719
final String url;
1820
final SyncCredentials credentials;
@@ -64,6 +66,7 @@ public SyncBuilder(BoxStore boxStore, String url, SyncCredentials credentials) {
6466
throw new IllegalStateException(
6567
"This ObjectBox library (JNI) does not include sync. Please update your dependencies.");
6668
}
69+
this.platform = Platform.findPlatform();
6770
this.boxStore = boxStore;
6871
this.url = url;
6972
this.credentials = credentials;

objectbox-java/src/main/java/io/objectbox/sync/SyncClient.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,12 @@ public interface SyncClient extends Closeable {
123123
@Experimental
124124
void requestFullSync();
125125

126+
/**
127+
* Lets the sync client know that a working network connection
128+
* is available.
129+
* <p>
130+
* This can help speed up reconnecting to the sync server.
131+
*/
132+
void notifyConnectionAvailable();
133+
126134
}

objectbox-java/src/main/java/io/objectbox/sync/SyncClientImpl.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public class SyncClientImpl implements SyncClient {
1818

1919
private final String serverUrl;
2020
private final InternalListener internalListener;
21+
@Nullable
22+
private final ConnectivityMonitor connectivityMonitor;
2123

2224
private volatile long handle;
2325
@Nullable
@@ -27,6 +29,7 @@ public class SyncClientImpl implements SyncClient {
2729

2830
SyncClientImpl(SyncBuilder builder) {
2931
this.serverUrl = builder.url;
32+
this.connectivityMonitor = builder.platform.getConnectivityMonitor();
3033

3134
long boxStoreHandle = InternalAccess.getHandle(builder.boxStore);
3235
this.handle = nativeCreate(boxStoreHandle, serverUrl, builder.certificatePath);
@@ -123,6 +126,9 @@ public boolean awaitFirstLogin(long millisToWait) {
123126
public synchronized void start() {
124127
nativeStart(handle);
125128
started = true;
129+
if (connectivityMonitor != null) {
130+
connectivityMonitor.setObserver(this);
131+
}
126132
}
127133

128134
@Override
@@ -132,6 +138,10 @@ public boolean isStarted() {
132138

133139
@Override
134140
public synchronized void stop() {
141+
if (connectivityMonitor != null) {
142+
connectivityMonitor.removeObserver();
143+
}
144+
135145
long handleToStop = this.handle;
136146
if (handleToStop != 0) {
137147
nativeStop(handleToStop);
@@ -141,6 +151,10 @@ public synchronized void stop() {
141151

142152
@Override
143153
public void close() {
154+
if (connectivityMonitor != null) {
155+
connectivityMonitor.removeObserver();
156+
}
157+
144158
long handleToDelete;
145159
synchronized (this) {
146160
handleToDelete = this.handle;
@@ -188,6 +202,11 @@ public void cancelUpdates() {
188202
nativeCancelUpdates(handle);
189203
}
190204

205+
@Override
206+
public void notifyConnectionAvailable() {
207+
nativeTriggerReconnect(handle);
208+
}
209+
191210
private void checkNotNull(Object object, String message) {
192211
//noinspection ConstantConditions Non-null annotation does not enforce, so check for null.
193212
if (object == null) {
@@ -231,6 +250,9 @@ private void checkNotNull(Object object, String message) {
231250
/** (Optional) Pause sync updates. */
232251
private native void nativeCancelUpdates(long handle);
233252

253+
/** Hints to the native client that an active network connection is available. */
254+
private native void nativeTriggerReconnect(long handle);
255+
234256
private class InternalListener implements SyncClientListener {
235257
private final CountDownLatch firstLoginLatch = new CountDownLatch(1);
236258

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package io.objectbox.sync.internal;
2+
3+
import java.lang.reflect.InvocationTargetException;
4+
import java.lang.reflect.Method;
5+
6+
import javax.annotation.Nullable;
7+
8+
import io.objectbox.BoxStore;
9+
import io.objectbox.sync.ConnectivityMonitor;
10+
11+
/**
12+
* Provides access to platform-specific features.
13+
*/
14+
public class Platform {
15+
16+
public static Platform findPlatform() {
17+
// Android
18+
Object contextInstance = BoxStore.context;
19+
if (contextInstance != null) {
20+
Throwable throwable = null;
21+
22+
// Note: do not catch Exception as it will swallow exceptions useful for debugging.
23+
// Also can't catch ReflectiveOperationException, is K+ (19+) on Android.
24+
// noinspection TryWithIdenticalCatches Requires Android K+ (19+).
25+
try {
26+
Class<?> contextClass = Class.forName("android.content.Context");
27+
Class<?> platformClass = Class.forName("io.objectbox.android.internal.AndroidPlatform");
28+
Method create = platformClass.getMethod("create", contextClass);
29+
return (Platform) create.invoke(null, contextInstance);
30+
} catch (NoSuchMethodException e) {
31+
throwable = e;
32+
} catch (IllegalAccessException e) {
33+
throwable = e;
34+
} catch (InvocationTargetException e) {
35+
throwable = e;
36+
} catch (ClassNotFoundException ignored) {
37+
// Android API or library not in classpath.
38+
}
39+
40+
if (throwable != null) {
41+
throw new RuntimeException("AndroidPlatform could not be created.", throwable);
42+
}
43+
}
44+
45+
return new Platform();
46+
}
47+
48+
@Nullable
49+
public ConnectivityMonitor getConnectivityMonitor() {
50+
return null;
51+
}
52+
}

tests/objectbox-java-test/src/test/java/io/objectbox/FunctionalTestSuite.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
import io.objectbox.relation.ToManyStandaloneTest;
2828
import io.objectbox.relation.ToManyTest;
2929
import io.objectbox.relation.ToOneTest;
30+
import io.objectbox.sync.ConnectivityMonitorTest;
31+
import io.objectbox.sync.PlatformTest;
32+
3033
import org.junit.runner.RunWith;
3134
import org.junit.runners.Suite;
3235
import org.junit.runners.Suite.SuiteClasses;
@@ -37,13 +40,15 @@
3740
BoxTest.class,
3841
BoxStoreTest.class,
3942
BoxStoreBuilderTest.class,
43+
ConnectivityMonitorTest.class,
4044
CursorTest.class,
4145
CursorBytesTest.class,
4246
DebugCursorTest.class,
4347
LazyListTest.class,
4448
NonArgConstructorTest.class,
4549
IndexReaderRenewTest.class,
4650
ObjectClassObserverTest.class,
51+
PlatformTest.class,
4752
PropertyQueryTest.class,
4853
QueryFilterComparatorTest.class,
4954
QueryObserverTest.class,

0 commit comments

Comments
 (0)