Implemented ReplayOutstandingEntries

pull/14/head
Sam Bosley 13 years ago
parent a4405481f7
commit d45e6c575e

@ -14,6 +14,7 @@ import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.astrid.actfm.sync.messages.BriefMe; import com.todoroo.astrid.actfm.sync.messages.BriefMe;
import com.todoroo.astrid.actfm.sync.messages.ClientToServerMessage; import com.todoroo.astrid.actfm.sync.messages.ClientToServerMessage;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
import com.todoroo.astrid.actfm.sync.messages.ReplayOutstandingEntries; import com.todoroo.astrid.actfm.sync.messages.ReplayOutstandingEntries;
import com.todoroo.astrid.actfm.sync.messages.ServerToClientMessage; import com.todoroo.astrid.actfm.sync.messages.ServerToClientMessage;
import com.todoroo.astrid.core.PluginServices; import com.todoroo.astrid.core.PluginServices;
@ -189,8 +190,8 @@ public class ActFmSyncThread {
// Reapplies changes still in the outstanding tables to the local database // Reapplies changes still in the outstanding tables to the local database
// Called after a batch has finished processing // Called after a batch has finished processing
private void replayOutstandingChanges() { private void replayOutstandingChanges() {
new ReplayOutstandingEntries<Task, TaskOutstanding>(Task.class, taskDao, taskOutstandingDao).execute(); new ReplayOutstandingEntries<Task, TaskOutstanding>(Task.class, NameMaps.TABLE_ID_TASKS, taskDao, taskOutstandingDao).execute();
new ReplayOutstandingEntries<TagData, TagOutstanding>(TagData.class, tagDataDao, tagOutstandingDao).execute(); new ReplayOutstandingEntries<TagData, TagOutstanding>(TagData.class, NameMaps.TABLE_ID_TAGS, tagDataDao, tagOutstandingDao).execute();
} }
private boolean timeForBackgroundSync() { private boolean timeForBackgroundSync() {

@ -21,9 +21,9 @@ public class AcknowledgeChange extends ServerToClientMessage {
public AcknowledgeChange(JSONObject json) { public AcknowledgeChange(JSONObject json) {
super(json); super(json);
String table = json.optString("table"); //$NON-NLS-1$ String table = json.optString("table"); //$NON-NLS-1$
if (NameMaps.SERVER_TABLE_TASKS.equals(table)) if (NameMaps.TABLE_ID_TASKS.equals(table))
dao = PluginServices.getTaskOutstandingDao(); dao = PluginServices.getTaskOutstandingDao();
else if (NameMaps.SERVER_TABLE_TAGS.equals(table)) else if (NameMaps.TABLE_ID_TAGS.equals(table))
dao = PluginServices.getTagOutstandingDao(); dao = PluginServices.getTagOutstandingDao();
else else
dao = null; dao = null;

@ -19,16 +19,17 @@ public class NameMaps {
private static final Map<Table, String> TABLE_LOCAL_TO_SERVER; private static final Map<Table, String> TABLE_LOCAL_TO_SERVER;
private static final Map<String, Table> TABLE_SERVER_TO_LOCAL; private static final Map<String, Table> TABLE_SERVER_TO_LOCAL;
public static final String SERVER_TABLE_TASKS = "tasks"; // Universal table identifiers
public static final String SERVER_TABLE_TAGS = "tags"; public static final String TABLE_ID_TASKS = "tasks";
public static final String SERVER_TABLE_USERS = "users"; public static final String TABLE_ID_TAGS = "tags";
public static final String TABLE_ID_USERS = "users";
static { static {
// Hardcoded local tables mapped to corresponding server names // Hardcoded local tables mapped to corresponding server names
TABLE_LOCAL_TO_SERVER = new HashMap<Table, String>(); TABLE_LOCAL_TO_SERVER = new HashMap<Table, String>();
TABLE_LOCAL_TO_SERVER.put(Task.TABLE, SERVER_TABLE_TASKS); TABLE_LOCAL_TO_SERVER.put(Task.TABLE, TABLE_ID_TASKS);
TABLE_LOCAL_TO_SERVER.put(TagData.TABLE, SERVER_TABLE_TAGS); TABLE_LOCAL_TO_SERVER.put(TagData.TABLE, TABLE_ID_TAGS);
TABLE_LOCAL_TO_SERVER.put(User.TABLE, SERVER_TABLE_USERS); TABLE_LOCAL_TO_SERVER.put(User.TABLE, TABLE_ID_USERS);
// Reverse the mapping to construct the server to local map // Reverse the mapping to construct the server to local map
TABLE_SERVER_TO_LOCAL = AndroidUtilities.reverseMap(TABLE_LOCAL_TO_SERVER); TABLE_SERVER_TO_LOCAL = AndroidUtilities.reverseMap(TABLE_LOCAL_TO_SERVER);
@ -112,9 +113,9 @@ public class NameMaps {
private static <A, B> B mapColumnName(String table, String col, Map<A, B> taskMap, Map<A, B> tagMap) { private static <A, B> B mapColumnName(String table, String col, Map<A, B> taskMap, Map<A, B> tagMap) {
Map<A, B> map = null; Map<A, B> map = null;
if (SERVER_TABLE_TASKS.equals(table)) if (TABLE_ID_TASKS.equals(table))
map = taskMap; map = taskMap;
else if (SERVER_TABLE_TAGS.equals(table)) else if (TABLE_ID_TAGS.equals(table))
map = tagMap; map = tagMap;
if (map == null) if (map == null)

@ -1,5 +1,9 @@
package com.todoroo.astrid.actfm.sync.messages; package com.todoroo.astrid.actfm.sync.messages;
import android.util.Log;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.PropertyVisitor;
import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.sql.Order; import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.sql.Query;
@ -8,17 +12,23 @@ import com.todoroo.astrid.dao.OutstandingEntryDao;
import com.todoroo.astrid.dao.RemoteModelDao; import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.data.OutstandingEntry; import com.todoroo.astrid.data.OutstandingEntry;
import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.SyncFlags;
@SuppressWarnings("nls")
public class ReplayOutstandingEntries<T extends RemoteModel, OE extends OutstandingEntry<T>> { public class ReplayOutstandingEntries<T extends RemoteModel, OE extends OutstandingEntry<T>> {
private static final String ERROR_TAG = "actfm-replay-outstanding";
private final Class<T> modelClass; private final Class<T> modelClass;
private final Class<OE> outstandingClass; private final Class<OE> outstandingClass;
private final String table;
private final RemoteModelDao<T> dao; private final RemoteModelDao<T> dao;
private final OutstandingEntryDao<OE> outstandingDao; private final OutstandingEntryDao<OE> outstandingDao;
public ReplayOutstandingEntries(Class<T> modelClass, RemoteModelDao<T> dao, OutstandingEntryDao<OE> outstandingDao) { public ReplayOutstandingEntries(Class<T> modelClass, String table, RemoteModelDao<T> dao, OutstandingEntryDao<OE> outstandingDao) {
this.modelClass = modelClass; this.modelClass = modelClass;
this.outstandingClass = DaoReflectionHelpers.getOutstandingClass(modelClass); this.outstandingClass = DaoReflectionHelpers.getOutstandingClass(modelClass);
this.table = table;
this.dao = dao; this.dao = dao;
this.outstandingDao = outstandingDao; this.outstandingDao = outstandingDao;
} }
@ -27,10 +37,91 @@ public class ReplayOutstandingEntries<T extends RemoteModel, OE extends Outstand
TodorooCursor<OE> outstanding = outstandingDao.query(Query.select(DaoReflectionHelpers.getModelProperties(outstandingClass)) TodorooCursor<OE> outstanding = outstandingDao.query(Query.select(DaoReflectionHelpers.getModelProperties(outstandingClass))
.orderBy(Order.asc(OutstandingEntry.ENTITY_ID_PROPERTY), Order.asc(OutstandingEntry.CREATED_AT_PROPERTY))); .orderBy(Order.asc(OutstandingEntry.ENTITY_ID_PROPERTY), Order.asc(OutstandingEntry.CREATED_AT_PROPERTY)));
try { try {
// Do and apply OE instance = outstandingClass.newInstance();
} finally { for (outstanding.moveToFirst(); !outstanding.isAfterLast(); outstanding.moveToNext()) {
outstanding.close(); instance.clear();
instance.readPropertiesFromCursor(outstanding);
processItem(instance.getValue(OutstandingEntry.ENTITY_ID_PROPERTY), instance, outstanding);
}
} catch (InstantiationException e) {
Log.e(ERROR_TAG, "Error instantiating outstanding entry", e);
} catch (IllegalAccessException e) {
Log.e(ERROR_TAG, "Error instantiating outstanding entry", e);
} catch (Exception e) {
Log.e(ERROR_TAG, "Unexpected exception in replay outstanding entries", e);
}
}
private void processItem(long id, OE instance, TodorooCursor<OE> outstanding) {
try {
T model = modelClass.newInstance();
model.setId(id);
OutstandingToModelVisitor<T> visitor = new OutstandingToModelVisitor<T>(model);
for (; !outstanding.isAfterLast(); outstanding.moveToNext()) {
instance.clear();
instance.readPropertiesFromCursor(outstanding);
if (instance.getValue(OutstandingEntry.ENTITY_ID_PROPERTY) != id)
break;
String column = instance.getValue(OutstandingEntry.COLUMN_STRING_PROPERTY);
Property<?> property = NameMaps.localColumnNameToProperty(table, column);
if (property == null)
throw new RuntimeException("No local property found for local column " + column + " in table " + table);
// set values to model
property.accept(visitor, instance);
}
model.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
dao.saveExisting(model);
outstanding.moveToPrevious(); // Move back one to undo the last iteration of the for loop
} catch (InstantiationException e) {
Log.e(ERROR_TAG, "Error instantiating model", e);
} catch (IllegalAccessException e) {
Log.e(ERROR_TAG, "Error instantiating model", e);
}
}
private class OutstandingToModelVisitor<MTYPE extends T> implements PropertyVisitor<Void, OE> {
private final MTYPE model;
public OutstandingToModelVisitor(MTYPE model) {
this.model = model;
}
@Override
public Void visitInteger(Property<Integer> property, OE data) {
Integer i = data.getMergedValues().getAsInteger(OutstandingEntry.VALUE_STRING_PROPERTY.name);
if (i != null)
model.setValue(property, i);
return null;
}
@Override
public Void visitLong(Property<Long> property, OE data) {
Long l = data.getMergedValues().getAsLong(OutstandingEntry.VALUE_STRING_PROPERTY.name);
if (l != null)
model.setValue(property, l);
return null;
}
@Override
public Void visitDouble(Property<Double> property, OE data) {
Double d = data.getMergedValues().getAsDouble(OutstandingEntry.VALUE_STRING_PROPERTY.name);
if (d != null)
model.setValue(property, d);
return null;
} }
@Override
public Void visitString(Property<String> property, OE data) {
String s = data.getValue(OutstandingEntry.VALUE_STRING_PROPERTY);
model.setValue(property, s);
return null;
}
} }
} }

@ -38,9 +38,9 @@ public abstract class ServerToClientMessage {
private static MakeChanges<?> instantiateMakeChanges(JSONObject json) { private static MakeChanges<?> instantiateMakeChanges(JSONObject json) {
String table = json.optString("table"); String table = json.optString("table");
if (NameMaps.SERVER_TABLE_TASKS.equals(table)) if (NameMaps.TABLE_ID_TASKS.equals(table))
return new MakeChanges<Task>(json, PluginServices.getTaskDao()); return new MakeChanges<Task>(json, PluginServices.getTaskDao());
else if (NameMaps.SERVER_TABLE_TAGS.equals(table)) else if (NameMaps.TABLE_ID_TAGS.equals(table))
return new MakeChanges<TagData>(json, PluginServices.getTagDataDao()); return new MakeChanges<TagData>(json, PluginServices.getTagDataDao());
else else
return null; return null;

@ -28,7 +28,7 @@ public class SyncMessageTest extends NewSyncTestCase {
private JSONObject getMakeChanges() throws JSONException { private JSONObject getMakeChanges() throws JSONException {
JSONObject makeChanges = new JSONObject(); JSONObject makeChanges = new JSONObject();
makeChanges.put("type", ServerToClientMessage.TYPE_MAKE_CHANGES); makeChanges.put("type", ServerToClientMessage.TYPE_MAKE_CHANGES);
makeChanges.put("table", NameMaps.SERVER_TABLE_TASKS); makeChanges.put("table", NameMaps.TABLE_ID_TASKS);
JSONObject changes = new JSONObject(); JSONObject changes = new JSONObject();
changes.put("title", MAKE_CHANGES_TITLE); changes.put("title", MAKE_CHANGES_TITLE);
changes.put("importance", Task.IMPORTANCE_DO_OR_DIE); changes.put("importance", Task.IMPORTANCE_DO_OR_DIE);

Loading…
Cancel
Save