Skip to content

Commit 8f3949c

Browse files
committed
Revision 1
1. Interface at IterableTaskStorage which will notify all DB errors to Healthmonitor. This will be used by healthmonitor to keep its flag 'errored' updated. 2. canSchedule and canProcess will now be checked through this flag in healthmonitor 3. Updated existing test methods which were failing because of this changes as it needed healthmonitoring mock in them 4. Made some improvements where healthmonitor was being initialized reperatedly. Still pending: 1. should canProcess and canSchedule be based on just one flag - errored in healthMonitor? 2. Is there a technique to switch back to offline mode? after we set errored flag to true?
1 parent 185e2d0 commit 8f3949c

File tree

8 files changed

+115
-51
lines changed

8 files changed

+115
-51
lines changed
Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,23 @@
11
package com.iterable.iterableapi;
22

3-
import java.util.ArrayList;
4-
5-
public class HealthMonitor implements HealthMonitorHandler{
3+
public class HealthMonitor implements IterableTaskStorage.IterableDatabaseStatusListeners {
64
private static final String TAG = "HealthMonitor";
75

86
private IterableTaskStorage database;
97
private boolean errored = false;
10-
private ArrayList<HealthMonitorHandler> healthMonitorListeners = new ArrayList<>();
8+
119
public HealthMonitor(IterableTaskStorage database) {
1210
this.database = database;
11+
database.addDataBaseListener(this);
1312
}
1413

1514
public boolean canSchedule() {
1615
IterableLogger.d(TAG, "canSchedule");
17-
18-
return database.isDatabaseReady() && database.numberOfTasks() < IterableConstants.MAX_OFFLINE_OPERATION;
19-
//TODO: errored has to be set by DB errors being found during Taskstorage initialization or during other DB operations.
20-
// if (errored) {
21-
// return false;
22-
// }
23-
//
24-
// return database.numberOfTasks() < IterableConstants.MAX_OFFLINE_OPERATION;
16+
return !errored;
2517
}
2618

2719
public boolean canProcess() {
28-
IterableLogger.d(TAG, "canProcess");
20+
IterableLogger.d(TAG, "Health monitor can process: " + !errored);
2921
return !errored;
3022
}
3123

@@ -36,34 +28,35 @@ public void onScheduleError() {
3628

3729
void onNextTaskError() {
3830
IterableLogger.w(TAG, "onNextTaskError");
39-
onError();
31+
onDBError();
4032
}
4133

4234
void onDeleteAllTasksError() {
4335
IterableLogger.w(TAG, "onDeleteAllTasksError");
44-
onError();
36+
onDBError();
4537
}
4638

47-
//TODO: Is it similar to DBError? how should the logic work
48-
private void onError() {
39+
@Override
40+
public void isNotReady() {
41+
IterableLogger.v(TAG, "DB Not ready notified to healthMonitor");
4942
errored = true;
50-
5143
}
5244

53-
synchronized void addHealthMonitorListener(HealthMonitorHandler listener) {
54-
healthMonitorListeners.add(listener);
45+
@Override
46+
public void onDBError() {
47+
IterableLogger.v(TAG, "DB Error notified to healthMonitor");
48+
errored = true;
5549
}
5650

57-
synchronized void removeNetworkListener(HealthMonitorHandler listener) {
58-
healthMonitorListeners.remove(listener);
51+
@Override
52+
public void isClosed() {
53+
IterableLogger.v(TAG, "DB Closed notified to healthMonitor");
54+
errored = true;
5955
}
6056

61-
//TODO: Might have to reconsider changing this
6257
@Override
63-
public void onDBError() {
64-
ArrayList<HealthMonitorHandler> healthMonitorHandlersCopy = new ArrayList<>(healthMonitorListeners);
65-
for (HealthMonitorHandler listener : healthMonitorHandlersCopy) {
66-
listener.onDBError();
67-
}
58+
public void isReady() {
59+
IterableLogger.v(TAG, "DB Ready notified to healthMonitor");
60+
errored = false;
6861
}
6962
}

iterableapi/src/main/java/com/iterable/iterableapi/HealthMonitorHandler.java

Lines changed: 0 additions & 5 deletions
This file was deleted.

iterableapi/src/main/java/com/iterable/iterableapi/IterableApiClient.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ private OfflineRequestProcessor getOfflineProcessor() {
7070
return null;
7171
}
7272

73-
this.healthMonitor = new HealthMonitor(IterableTaskStorage.sharedInstance(authProvider.getContext()));
73+
if (healthMonitor == null) {
74+
this.healthMonitor = new HealthMonitor(IterableTaskStorage.sharedInstance(authProvider.getContext()));
75+
}
7476

7577
if (offlineRequestProcessor == null) {
7678
offlineRequestProcessor = new OfflineRequestProcessor(authProvider.getContext(), healthMonitor);

iterableapi/src/main/java/com/iterable/iterableapi/IterableTaskRunner.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ private void processTasks() {
114114
return;
115115
}
116116

117+
if (!healthMonitor.canProcess()) {
118+
return;
119+
}
117120
while (networkConnectivityManager.isConnected()) {
118-
if (!healthMonitor.canProcess()) {
119-
return;
120-
}
121121

122122
IterableTask task = taskStorage.getNextScheduledTask();
123123

iterableapi/src/main/java/com/iterable/iterableapi/IterableTaskStorage.java

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import java.util.ArrayList;
1616
import java.util.Date;
1717

18-
class IterableTaskStorage implements HealthMonitorHandler {
18+
class IterableTaskStorage {
1919

2020
private static IterableTaskStorage sharedInstance;
2121

@@ -61,11 +61,6 @@ class IterableTaskStorage implements HealthMonitorHandler {
6161
private SQLiteDatabase database;
6262
private IterableDatabaseManager databaseManager;
6363

64-
@Override
65-
public void onDBError() {
66-
67-
}
68-
6964
interface TaskCreatedListener {
7065
void onTaskCreated(IterableTask iterableTask);
7166
}
@@ -154,6 +149,9 @@ public void run() {
154149
for (TaskCreatedListener listener : taskCreatedListeners) {
155150
listener.onTaskCreated(iterableTask);
156151
}
152+
if (numberOfTasks() > IterableConstants.MAX_OFFLINE_OPERATION) {
153+
notifyDBError();
154+
}
157155
}
158156
});
159157

@@ -462,23 +460,86 @@ private boolean updateTaskWithContentValues(String id, ContentValues contentValu
462460
//TODO: This can be reverted back to private if db issues are correctly informed to HealthMonitor. Currenlty Healthmonitor is directly accessing this method which can also be fine,
463461
boolean isDatabaseReady() {
464462
if (database == null) {
463+
notifyDBNotReady();
464+
notifyDBError();
465465
IterableLogger.e(TAG, "Database not initialized");
466466
return false;
467467
}
468468
if (!database.isOpen()) {
469+
notifyDBClosed();
469470
IterableLogger.e(TAG, "Database is closed");
470471
return false;
471472
}
472473
return true;
473474
}
474475

475476
//TODO: This I am thinking of notifier from DB class here to Healthmonitor which will invoke DBerror method in Healthmonitor class. Not sure though.
476-
interface IterableTaskStorageHandler {
477+
public interface IterableDatabaseStatusListeners {
477478
void isNotReady();
478479

479480
void onDBError();
480481

481482
void isClosed();
483+
484+
void isReady();
485+
}
486+
487+
private ArrayList<IterableDatabaseStatusListeners> databaseStatusListeners = new ArrayList<>();
488+
489+
void addDataBaseListener(IterableDatabaseStatusListeners listener) {
490+
if (isDatabaseReady()) {
491+
listener.isReady();
492+
} else {
493+
listener.isNotReady();
494+
}
495+
databaseStatusListeners.add(listener);
496+
}
497+
498+
void removeTaskCreatedListener(IterableDatabaseStatusListeners listener) {
499+
databaseStatusListeners.remove(listener);
500+
}
501+
502+
private void notifyDBClosed() {
503+
new Handler(Looper.getMainLooper()).post(new Runnable() {
504+
@Override
505+
public void run() {
506+
for (IterableDatabaseStatusListeners listener : databaseStatusListeners) {
507+
listener.isClosed();
508+
}
509+
}
510+
});
511+
}
512+
513+
private void notifyDBError() {
514+
new Handler(Looper.getMainLooper()).post(new Runnable() {
515+
@Override
516+
public void run() {
517+
for (IterableDatabaseStatusListeners listener : databaseStatusListeners) {
518+
listener.onDBError();
519+
}
520+
}
521+
});
482522
}
483523

484-
}
524+
private void notifyDBReady() {
525+
new Handler(Looper.getMainLooper()).post(new Runnable() {
526+
@Override
527+
public void run() {
528+
for (IterableDatabaseStatusListeners listener : databaseStatusListeners) {
529+
listener.isReady();
530+
}
531+
}
532+
});
533+
}
534+
535+
private void notifyDBNotReady() {
536+
new Handler(Looper.getMainLooper()).post(new Runnable() {
537+
@Override
538+
public void run() {
539+
for (IterableDatabaseStatusListeners listener : databaseStatusListeners) {
540+
listener.isNotReady();
541+
}
542+
}
543+
});
544+
}
545+
}

iterableapi/src/main/java/com/iterable/iterableapi/OfflineRequestProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@ class OfflineRequestProcessor implements RequestProcessor {
4444
}
4545

4646
@VisibleForTesting
47-
OfflineRequestProcessor(TaskScheduler scheduler, IterableTaskRunner iterableTaskRunner, IterableTaskStorage storage) {
47+
OfflineRequestProcessor(TaskScheduler scheduler, IterableTaskRunner iterableTaskRunner, IterableTaskStorage storage, HealthMonitor healthMonitor) {
4848
taskRunner = iterableTaskRunner;
4949
taskScheduler = scheduler;
5050
taskStorage = storage;
51+
this.healthMonitor = healthMonitor;
5152
}
5253

5354
@Override

iterableapi/src/test/java/com/iterable/iterableapi/IterableTaskRunnerTest.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class IterableTaskRunnerTest {
3333
private IterableTaskRunner taskRunner;
3434
private IterableTaskStorage mockTaskStorage;
3535
private IterableActivityMonitor mockActivityMonitor;
36+
private HealthMonitor mockHealthMonitor;
3637
private IterableNetworkConnectivityManager mockNetworkConnectivityManager;
3738
private MockWebServer server;
3839

@@ -41,7 +42,8 @@ public void setUp() throws Exception {
4142
mockTaskStorage = mock(IterableTaskStorage.class);
4243
mockActivityMonitor = mock(IterableActivityMonitor.class);
4344
mockNetworkConnectivityManager = mock(IterableNetworkConnectivityManager.class);
44-
taskRunner = new IterableTaskRunner(mockTaskStorage, mockActivityMonitor, mockNetworkConnectivityManager);
45+
mockHealthMonitor = mock(HealthMonitor.class);
46+
taskRunner = new IterableTaskRunner(mockTaskStorage, mockActivityMonitor, mockNetworkConnectivityManager, mockHealthMonitor);
4547
server = new MockWebServer();
4648
IterableApi.overrideURLEndpointPath(server.url("").toString());
4749
}
@@ -58,7 +60,8 @@ public void testRunOnTaskCreatedMakesApiRequest() throws Exception {
5860
when(mockTaskStorage.getNextScheduledTask()).thenReturn(task).thenReturn(null);
5961
when(mockActivityMonitor.isInForeground()).thenReturn(true);
6062
when(mockNetworkConnectivityManager.isConnected()).thenReturn(true);
61-
63+
when(mockHealthMonitor.canProcess()).thenReturn(true);
64+
when(mockHealthMonitor.canSchedule()).thenReturn(true);
6265
taskRunner.onTaskCreated(null);
6366
runHandlerTasks(taskRunner);
6467

@@ -76,6 +79,8 @@ public void testRunOnTaskCreatedCallsCompletionListener() throws Exception {
7679
when(mockTaskStorage.getNextScheduledTask()).thenReturn(task).thenReturn(null);
7780
when(mockActivityMonitor.isInForeground()).thenReturn(true);
7881
when(mockNetworkConnectivityManager.isConnected()).thenReturn(true);
82+
when(mockHealthMonitor.canProcess()).thenReturn(true);
83+
when(mockHealthMonitor.canSchedule()).thenReturn(true);
7984
IterableTaskRunner.TaskCompletedListener taskCompletedListener = mock(IterableTaskRunner.TaskCompletedListener.class);
8085
taskRunner.addTaskCompletedListener(taskCompletedListener);
8186
server.enqueue(new MockResponse().setResponseCode(200).setBody("{}"));
@@ -98,11 +103,13 @@ public void testNoRequestsWhenOffline() throws Exception {
98103
when(mockTaskStorage.getNextScheduledTask()).thenReturn(task).thenReturn(null);
99104
when(mockActivityMonitor.isInForeground()).thenReturn(true);
100105
when(mockNetworkConnectivityManager.isConnected()).thenReturn(false);
106+
when(mockHealthMonitor.canProcess()).thenReturn(true);
107+
when(mockHealthMonitor.canSchedule()).thenReturn(true);
101108
IterableTaskRunner.TaskCompletedListener taskCompletedListener = mock(IterableTaskRunner.TaskCompletedListener.class);
102109
taskRunner.addTaskCompletedListener(taskCompletedListener);
103110
server.enqueue(new MockResponse().setResponseCode(200).setBody("{}"));
104111

105-
taskRunner.onTaskCreated(null);
112+
taskRunner.onTaskCreated(mock(IterableTask.class));
106113
runHandlerTasks(taskRunner);
107114

108115
verify(mockNetworkConnectivityManager, times(1)).isConnected();
@@ -145,7 +152,8 @@ public void testIfNetworkCheckedBeforeProcessingTask() throws Exception {
145152
when(mockTaskStorage.getNextScheduledTask()).thenReturn(task).thenReturn(null);
146153
when(mockActivityMonitor.isInForeground()).thenReturn(true);
147154
when(mockNetworkConnectivityManager.isConnected()).thenReturn(true);
148-
155+
when(mockHealthMonitor.canProcess()).thenReturn(true);
156+
when(mockHealthMonitor.canSchedule()).thenReturn(true);
149157
taskRunner.onTaskCreated(null);
150158
runHandlerTasks(taskRunner);
151159

iterableapi/src/test/java/com/iterable/iterableapi/OfflineRequestProcessorTest.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,29 @@
1313
import static org.mockito.Mockito.mock;
1414
import static org.mockito.Mockito.verify;
1515
import static org.mockito.Mockito.verifyNoInteractions;
16+
import static org.mockito.Mockito.when;
1617

1718
@RunWith(TestRunner.class)
1819
public class OfflineRequestProcessorTest extends BaseTest {
1920
private OfflineRequestProcessor offlineRequestProcessor;
2021
private IterableTaskRunner mockTaskRunner;
2122
private TaskScheduler mockTaskScheduler;
2223
private IterableTaskStorage mockTaskStorage;
24+
private HealthMonitor mockHealthMonitor;
2325

2426
@Before
2527
public void setUp() {
2628
mockTaskRunner = mock(IterableTaskRunner.class);
2729
mockTaskScheduler = mock(TaskScheduler.class);
2830
mockTaskStorage = mock(IterableTaskStorage.class);
29-
offlineRequestProcessor = new OfflineRequestProcessor(mockTaskScheduler, mockTaskRunner, mockTaskStorage);
31+
mockHealthMonitor = mock(HealthMonitor.class);
32+
offlineRequestProcessor = new OfflineRequestProcessor(mockTaskScheduler, mockTaskRunner, mockTaskStorage, mockHealthMonitor);
3033
}
3134

3235
@Test
3336
public void testOfflineRequestIsStored() {
3437
IterableApiRequest request = new IterableApiRequest("apiKey", IterableConstants.ENDPOINT_TRACK_INAPP_CLICK, new JSONObject(), "POST", null, null, null);
38+
when(mockHealthMonitor.canSchedule()).thenReturn(true);
3539
offlineRequestProcessor.processPostRequest(request.apiKey, request.resourcePath, request.json, request.authToken, request.successCallback, request.failureCallback);
3640
verify(mockTaskScheduler).scheduleTask(any(IterableApiRequest.class), isNull(IterableHelper.SuccessHandler.class), isNull(IterableHelper.FailureHandler.class));
3741
}

0 commit comments

Comments
 (0)