Android Open Source - DataSync Sync Helper






From Project

Back to project page DataSync.

License

The source code is released under:

Apache License

If you think the Android project DataSync listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.cardiomood.android.sync.ormlite;
// w  w w  . j  a va  2s .c  o  m
import com.cardiomood.android.sync.SyncException;
import com.cardiomood.android.sync.annotations.ParseClass;
import com.cardiomood.android.sync.parse.ParseTools;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.misc.TransactionManager;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;
import com.parse.ParseObject;
import com.parse.ParseQuery;

import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * Created by antondanhsin on 24/10/14.
 */
public class SyncHelper {

    private static final String PARSE_USER_ID_FIELD = "userId";
    private static final String PARSE_UPDATED_AT_FIELD = "updatedAt";
    private static final String PARSE_OBJECT_ID_FIELD = "objectId";
    private static final String PARSE_DELETED_FIELD = "deleted";

    private static final String DB_USER_ID_FIELD = "sync_user_id";
    private static final String DB_UPDATED_AT_FIELD = "sync_timestamp";
    private static final String DB_OBJECT_ID_FIELD = "sync_id";
    private static final String DB_DELETED_FIELD = "is_deleted";

    private Date lastSyncDate = new Date(0);
    private String userId = null;
    private OrmLiteSqliteOpenHelper dbHelper = null;
    private String parseUserIdField = PARSE_USER_ID_FIELD;
    private String localUserIdField = DB_USER_ID_FIELD;


    public SyncHelper(OrmLiteSqliteOpenHelper syncDatabaseHelper) {
        this.dbHelper = syncDatabaseHelper;
    }

    public Date getLastSyncDate() {
        return lastSyncDate;
    }

    public void setLastSyncDate(Date lastSyncDate) {
        this.lastSyncDate = lastSyncDate;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getParseUserIdField() {
        return parseUserIdField;
    }

    public void setParseUserIdField(String parseUserIdField) {
        this.parseUserIdField = parseUserIdField;
    }

    public String getLocalUserIdField() {
        return localUserIdField;
    }

    public void setLocalUserIdField(String localUserIdField) {
        this.localUserIdField = localUserIdField;
    }

    public <E extends SyncEntity> void synObjects(Class<E> entityClass) throws SyncException {
        synObjects(entityClass, false, null);
    }

    public <E extends SyncEntity> void synObjects(Class<E> entityClass, boolean userAware) throws SyncException {
        synObjects(entityClass, userAware, null);
    }

    public <E extends SyncEntity> void synObjects(final Class<E> entityClass, boolean userAware,
                                                  final SyncCallback<E> callback) throws SyncException {
        try {
            final String parseClass = extractParseClass(entityClass);

            // get updated remote objects
            ParseQuery query = ParseQuery.getQuery(parseClass);
            query.whereGreaterThan(PARSE_UPDATED_AT_FIELD, lastSyncDate);
            if (userAware && userId != null)
                query.whereEqualTo(PARSE_USER_ID_FIELD, userId);
            //query.orderByAscending(PARSE_OBJECT_ID_FIELD);
            final List<ParseObject> remoteObjects = ParseTools.findAllParseObjects(query);

            // get updated local objects
            final SyncDAO<E, ?> syncDao = dbHelper.getDao(entityClass);
            QueryBuilder<E, ?> dbQuery = syncDao.queryBuilder();
            //dbQuery.orderBy(DB_OBJECT_ID_FIELD, true);
            Where<E, ?> where = dbQuery.where().gt(DB_UPDATED_AT_FIELD, lastSyncDate);
            if (userAware && userId != null)
                where.and().eq(DB_USER_ID_FIELD, userId);
            final List<E> localObjects = where.query();

            TransactionManager.callInTransaction(dbHelper.getConnectionSource(), new Callable<Void>() {
                @Override
                public Void call() throws Exception {
                    // create local object map
                    Map<String, E> localObjectMap = new HashMap<String, E>(localObjects.size());
                    for (E localObject : localObjects) {
                        localObjectMap.put(localObject.getSyncId(), localObject);
                    }

                    for (ParseObject remoteObject : remoteObjects) {
                        String syncId = remoteObject.getObjectId();
                        E localObject = (E) localObjectMap.get(syncId);

                        if (localObject == null && !remoteObject.getBoolean(PARSE_DELETED_FIELD)) {
                            localObject = findBySyncId(syncDao, syncId);
                            if (localObject == null) {
                                // this object was created on the server but doesn't exist locally
                                localObject = SyncEntity.fromParseObject(remoteObject, entityClass);
                            } else {
                                // the object exists locally but out-of-date
                                SyncEntity.fromParseObject(remoteObject, localObject);
                            }
                            if (callback != null) {
                                callback.onSaveLocally(localObject, remoteObject);
                            }
                            syncDao.createOrUpdate(localObject);
                            continue;
                        }

                        if (localObject != null) {
                            long localTime = (localObject.getSyncDate() == null)
                                    ? 0L : localObject.getSyncDate().getTime();
                            long remoteTime = (remoteObject.getUpdatedAt() == null)
                                    ? 0L : remoteObject.getUpdatedAt().getTime();

                            if (remoteTime > localTime) {
                                // the remote object is newer
                                SyncEntity.fromParseObject(remoteObject, localObject);
                                if (callback != null) {
                                    callback.onSaveLocally(localObject, remoteObject);
                                }
                                syncDao.update(localObject);
                            } else if (remoteTime < localTime) {
                                // the local objects is newer
                                SyncEntity.toParseObject(localObject, remoteObject);
                                if (callback != null) {
                                    callback.onSaveRemotely(localObject, remoteObject);
                                }
                                remoteObject.save();
                            }
                        }
                    }
                    localObjectMap = null;

                    // create remote object map
                    Map<String, ParseObject> remoteObjectMap = new HashMap<String, ParseObject>(remoteObjects.size());
                    for (ParseObject remoteObject : remoteObjects) {
                        remoteObjectMap.put(remoteObject.getObjectId(), remoteObject);
                    }

                    for (E localObject : localObjects) {
                        String syncId = localObject.getSyncId();
                        if (syncId == null) {
                            // a brand new object!
                            ParseObject remoteObject = SyncEntity.toParseObject(localObject);
                            if (callback != null) {
                                callback.onSaveRemotely(localObject, remoteObject);
                            }
                            remoteObject.save();
                            SyncEntity.fromParseObject(remoteObject, localObject);
                            syncDao.update(localObject);
                            continue;
                        }

                        ParseObject remoteObject = remoteObjectMap.get(syncId);
                        if (remoteObject == null && !localObject.isDeleted()) {
                            // object was created locally but doesn't exist or too old on the server
                            // this is weird because syncId is not null

                            // try to get it from server
                            remoteObject = ParseObject.createWithoutData(parseClass, syncId).fetch();
                            SyncEntity.toParseObject(localObject, remoteObject);
                            if (callback != null) {
                                callback.onSaveRemotely(localObject, remoteObject);
                            }
                            remoteObject.save();
                            continue;
                        }

                        if (remoteObject != null) {
                            long localTime = (localObject.getSyncDate() == null)
                                    ? 0L : localObject.getSyncDate().getTime();
                            long remoteTime = (remoteObject.getUpdatedAt() == null)
                                    ? 0L : remoteObject.getUpdatedAt().getTime();


                            if (remoteTime > localTime) {
                                // the remote object is newer
                                SyncEntity.fromParseObject(remoteObject, localObject);
                                if (callback != null) {
                                    callback.onSaveLocally(localObject, remoteObject);
                                }
                                syncDao.update(localObject);
                            } else if (remoteTime < localTime) {
                                // the local objects is newer
                                SyncEntity.toParseObject(localObject, remoteObject);
                                if (callback != null) {
                                    callback.onSaveRemotely(localObject, remoteObject);
                                }
                                remoteObject.save();
                            }
                        }
                    }

                    return null;
                }
            });
        } catch (Exception ex) {
            throw new SyncException("Syncrhonization failed", ex);
        }
    }

    public static <E extends SyncEntity> E findBySyncId(Dao<E, ?> dao, String syncId) throws SQLException {
        return dao.queryForFirst(
                dao.queryBuilder().where().eq(DB_OBJECT_ID_FIELD, syncId).prepare()
        );
    }

    public static String extractParseClass(Class entityClass) {
        ParseClass annotation = (ParseClass) entityClass.getAnnotation(ParseClass.class);
        if (annotation == null) {
            throw new IllegalArgumentException("Class " + entityClass.getName()
                    + " must be annotated with " + ParseClass.class.getName());
        }
        return annotation.name();
    }

    public static interface SyncCallback<E extends SyncEntity> {

        void onSaveLocally(E localObject, ParseObject remoteObject) throws Exception;

        void onSaveRemotely(E localObject, ParseObject remoteObject) throws Exception;

    }

}




Java Source Code List

com.cardiomood.android.sync.SyncException.java
com.cardiomood.android.sync.annotations.ParseClass.java
com.cardiomood.android.sync.annotations.ParseField.java
com.cardiomood.android.sync.ormlite.SyncDAO.java
com.cardiomood.android.sync.ormlite.SyncEntity.java
com.cardiomood.android.sync.ormlite.SyncHelper.java
com.cardiomood.android.sync.parse.ParseTools.java
com.cardiomood.android.sync.parse.ParseValueConverter.java
com.cardiomood.android.sync.parse.SimpleParseValueConverter.java
com.cardiomood.android.sync.tools.ReflectionUtils.java