private <T extends RemoteModel, OE extends OutstandingEntry<T>> void constructChangesHappenedFromOutstandingTable( Class<T> modelClass, RemoteModelDao<T> modelDao, OutstandingEntryDao<OE> oustandingDao) { TodorooCursor<OE> outstanding = oustandingDao.query( Query.select(OutstandingEntry.ENTITY_ID_PROPERTY) .groupBy(OutstandingEntry.ENTITY_ID_PROPERTY)); try { for (outstanding.moveToFirst(); !outstanding.isAfterLast(); outstanding.moveToNext()) { Long id = outstanding.get(OutstandingEntry.ENTITY_ID_PROPERTY); enqueueMessage(new ChangesHappened<T, OE>(id, modelClass, modelDao, oustandingDao), null); } } finally { outstanding.close(); } }
private void sync() { try { int batchSize = 4; List<ClientToServerMessage<?>> messageBatch = new ArrayList<ClientToServerMessage<?>>(); while (true) { synchronized (monitor) { while ((pendingMessages.isEmpty() && !timeForBackgroundSync()) || !actFmPreferenceService.isLoggedIn() || !syncMigration) { try { if ((pendingMessages.isEmpty() || !actFmPreferenceService.isLoggedIn()) && notificationId >= 0) { notificationManager.cancel(notificationId); notificationId = -1; } monitor.wait(); AndroidUtilities.sleepDeep( 500L); // Wait briefly for large database operations to finish (e.g. adding a task // with several tags may trigger a message before all saves are done--fix // this?) if (!syncMigration) { syncMigration = Preferences.getBoolean(AstridNewSyncMigrator.PREF_SYNC_MIGRATION, false); } } catch (InterruptedException e) { // Ignored } } } boolean recordSyncSuccess = true; if (timeForBackgroundSync()) { repopulateQueueFromOutstandingTables(); enqueueMessage( BriefMe.instantiateBriefMeForClass( TaskListMetadata.class, NameMaps.PUSHED_AT_TASK_LIST_METADATA), DEFAULT_REFRESH_RUNNABLE); enqueueMessage( BriefMe.instantiateBriefMeForClass(Task.class, NameMaps.PUSHED_AT_TASKS), DEFAULT_REFRESH_RUNNABLE); enqueueMessage( BriefMe.instantiateBriefMeForClass(TagData.class, NameMaps.PUSHED_AT_TAGS), DEFAULT_REFRESH_RUNNABLE); enqueueMessage( BriefMe.instantiateBriefMeForClass(User.class, NameMaps.PUSHED_AT_USERS), DEFAULT_REFRESH_RUNNABLE); setTimeForBackgroundSync(false); } while (messageBatch.size() < batchSize && !pendingMessages.isEmpty()) { ClientToServerMessage<?> message = pendingMessages.remove(0); if (message != null) { messageBatch.add(message); } } if (!messageBatch.isEmpty() && checkForToken()) { JSONPayloadBuilder payload = new JSONPayloadBuilder(); MultipartEntity entity = new MultipartEntity(); boolean containsChangesHappened = false; for (int i = 0; i < messageBatch.size(); i++) { ClientToServerMessage<?> message = messageBatch.get(i); boolean success = payload.addMessage(message, entity); if (success) { if (message instanceof ChangesHappened) { containsChangesHappened = true; } } else { messageBatch.remove(i); i--; } } if (payload.getMessageCount() == 0) { messageBatch.clear(); continue; } setupNotification(); payload.addJSONObject(getClientVersion()); JSONArray errors = null; try { JSONObject response = actFmInvoker.postSync( payload.closeAndReturnString(), entity, containsChangesHappened, token); // process responses String time = response.optString("time"); JSONArray serverMessagesJson = response.optJSONArray("messages"); if (serverMessagesJson != null) { setWidgetSuppression(true); for (int i = 0; i < serverMessagesJson.length(); i++) { JSONObject serverMessageJson = serverMessagesJson.optJSONObject(i); if (serverMessageJson != null) { ServerToClientMessage serverMessage = ServerToClientMessage.instantiateMessage(serverMessageJson); if (serverMessage != null) { serverMessage.processMessage(time); } else { syncLog( "Index " + i + " unable to instantiate message " + serverMessageJson.toString()); } } } errors = response.optJSONArray("errors"); boolean errorsExist = (errors != null && errors.length() > 0); replayOutstandingChanges(errorsExist); setWidgetSuppression(false); } batchSize = Math.max(12, Math.min(batchSize, messageBatch.size()) * 2); if (recordSyncSuccess) { actFmPreferenceService.setLastError(null, null); actFmPreferenceService.recordSuccessfulSync(); } } catch (IOException e) { Log.e(ERROR_TAG, "IOException", e); batchSize = Math.max(batchSize / 2, 1); } Set<SyncMessageCallback> callbacksExecutedThisLoop = new HashSet<SyncMessageCallback>(); Map<Integer, List<JSONArray>> errorMap = buildErrorMap(errors); for (int i = 0; i < messageBatch.size(); i++) { ClientToServerMessage<?> message = messageBatch.get(i); try { SyncMessageCallback r = pendingCallbacks.remove(message); if (r != null && !callbacksExecutedThisLoop.contains(r)) { List<JSONArray> errorList = errorMap.get(i); if (errorList == null || errorList.isEmpty()) { r.runOnSuccess(); } else { r.runOnErrors(errorList); } callbacksExecutedThisLoop.add(r); } } catch (Exception e) { Log.e(ERROR_TAG, "Unexpected exception executing sync callback", e); } } messageBatch.clear(); } } } catch (Exception e) { // In the worst case, restart thread if something goes wrong Log.e(ERROR_TAG, "Unexpected sync thread exception", e); thread = null; startSyncThread(); } }
protected void enqueueMessage(MTYPE model, ClientToServerMessage<?> message) { actFmSyncThread.enqueueMessage(message, null); }