Package com.trechner.ksync4j

Source Code of com.trechner.ksync4j.AbstractSyncServer

package com.trechner.ksync4j;

import com.trechner.ksync4j.type.Syncable;
import com.trechner.ksync4j.type.SyncType;
import com.trechner.ksync4j.type.ChangeType;

import java.util.Map;
import java.util.HashMap;
import java.util.Collection;

/**
* Abstract sync server.
* <p/>
* Override it to adapt to your environment.
* <p/>
* Copyright (c) 2008 T-Rechner Ltd.
*
* @author Karl Tiller <karl@t-rechner.com>
* @see com.trechner.ksync4j.type.SyncType
*/
public abstract class AbstractSyncServer {

    /**
     * Sync changes between server and client.
     *
     * @param syncType Synchronization type.
     * @throws Exception Throws exception.
     * @see com.trechner.ksync4j.type.SyncType
     */
    public void sync(int syncType) throws Exception {
        Map<String, Syncable> clientChanges = new HashMap<String, Syncable>();
        Collection<Syncable> syncables = receiveSyncablesFromClient();
        for (Syncable syncable : syncables) {
            clientChanges.put(syncable.getGuid(), syncable);
        }

        Map<String, Syncable> database = new HashMap<String, Syncable>();
        syncables = getSyncablesFromDatabase();
        for (Syncable syncable : syncables) {
            database.put(syncable.getGuid(), syncable);
        }

        switch (syncType) {
            case SyncType.TWO_WAY:
                syncTwoWay(database, clientChanges);
                break;
            case SyncType.SLOW:
                syncSlow(database, clientChanges);
                break;
            case SyncType.ONE_WAY_FROM_CLIENT:
                syncOneWayFromClient(database, clientChanges);
                break;
            case SyncType.REFRESH_FROM_CLIENT:
                syncRefreshFromClient(database, clientChanges);
                break;
            case SyncType.ONE_WAY_FROM_SERVER:
                syncOneWayFromServer(database, clientChanges);
                break;
            case SyncType.REFRESH_FROM_SERVER:
                syncRefreshFromServer(database, clientChanges);
                break;
        }
    }

    /**
     * Must returns all syncables from database.
     *
     * @return Collection
     */
    public abstract Collection<Syncable> getSyncablesFromDatabase();

    /**
     * Must clear all syncables from database.
     */
    public abstract void clearDatabase();

    /**
     * Must save all syncables to a database.
     *
     * @param syncables Syncables
     * @see com.trechner.ksync4j.type.Syncable
     */
    public abstract void saveSyncablesToDatabase(Collection<Syncable> syncables);

    /**
     * Must return all syncables that were received from client.
     *
     * @return Collection
     * @see com.trechner.ksync4j.type.Syncable
     */
    public abstract Collection<Syncable> receiveSyncablesFromClient();

    /**
     * Must send all syncables to client.
     *
     * @param syncables Collection
     * @see com.trechner.ksync4j.type.Syncable
     */
    public abstract void sendSyncablesToClient(Collection<Syncable> syncables);

    private void syncTwoWay(Map<String, Syncable> database, Map<String, Syncable> clientChanges) throws Exception {
        Map<String, Syncable> resultingDatabase = new HashMap<String, Syncable>();
        Map<String, Syncable> resultingClientChanges = new HashMap<String, Syncable>();
        resolveConflicts(database, clientChanges, resultingDatabase, resultingClientChanges, false);
        sendSyncablesToClient(resultingClientChanges.values());
        saveSyncablesToDatabase(resultingDatabase.values());
    }

    private void syncSlow(Map<String, Syncable> database, Map<String, Syncable> clientChanges) throws Exception {
        Map<String, Syncable> resultingDatabase = new HashMap<String, Syncable>();
        Map<String, Syncable> resultingClientChanges = new HashMap<String, Syncable>();
        resolveConflicts(database, clientChanges, resultingDatabase, resultingClientChanges, true);
        sendSyncablesToClient(resultingClientChanges.values());
        saveSyncablesToDatabase(resultingDatabase.values());
    }

    private void syncOneWayFromClient(Map<String, Syncable> database, Map<String, Syncable> clientChanges) throws Exception {
        Map<String, Syncable> resultingDatabase = new HashMap<String, Syncable>();
        Map<String, Syncable> resultingClientChanges = new HashMap<String, Syncable>();
        resolveConflicts(database, clientChanges, resultingDatabase, resultingClientChanges, false);
        saveSyncablesToDatabase(resultingDatabase.values());
    }

    private void syncRefreshFromClient(Map<String, Syncable> database, Map<String, Syncable> clientChanges) throws Exception {
        Map<String, Syncable> resultingClientChanges = new HashMap<String, Syncable>();
        for (Syncable syncable : clientChanges.values()) {
            Syncable copy = syncable.getClass().newInstance();
            copy.copy(syncable);
            copy.setChangeType(ChangeType.NONE);
            resultingClientChanges.put(copy.getGuid(), copy);
        }
        clearDatabase();
        saveSyncablesToDatabase(resultingClientChanges.values());
    }

    private void syncOneWayFromServer(Map<String, Syncable> database, Map<String, Syncable> clientChanges) throws Exception {
        Map<String, Syncable> resultingDatabase = new HashMap<String, Syncable>();
        Map<String, Syncable> resultingClientChanges = new HashMap<String, Syncable>();
        resolveConflicts(database, clientChanges, resultingDatabase, resultingClientChanges, false);
        sendSyncablesToClient(resultingClientChanges.values());
    }

    private void syncRefreshFromServer(Map<String, Syncable> database, Map<String, Syncable> clientChanges) throws Exception {
        Map<String, Syncable> resultingClientChanges = new HashMap<String, Syncable>();
        for (Syncable syncable : database.values()) {
            Syncable copy = syncable.getClass().newInstance();
            copy.copy(syncable);
            copy.setChangeType(ChangeType.ADDED);
            resultingClientChanges.put(copy.getGuid(), copy);
        }
        sendSyncablesToClient(resultingClientChanges.values());
    }

    private void resolveConflicts(Map<String, Syncable> database, Map<String, Syncable> clientChanges, Map<String, Syncable> resultingDatabase, Map<String, Syncable> resultingClientChanges, boolean merge) throws Exception {
        // Determine what to write to database.
        for (Syncable syncable : database.values()) {
            Syncable copy = syncable.getClass().newInstance();
            copy.copy(syncable);
            copy.setChangeType(ChangeType.NONE);
            resultingDatabase.put(copy.getGuid(), copy);
        }
        for (String guid : clientChanges.keySet()) {
            Syncable clientSyncable = clientChanges.get(guid);
            Syncable databaseSyncable = database.get(guid);
            switch (clientSyncable.getChangeType()) {
                case ChangeType.NONE: {
                    if (merge) {
                        if (databaseSyncable == null) {
                            Syncable copy = clientSyncable.getClass().newInstance();
                            copy.copy(clientSyncable);
                            copy.setChangeType(ChangeType.NONE);
                            resultingDatabase.put(guid, copy);
                        }
                    }
                    break;
                }
                case ChangeType.ADDED: {
                    Syncable copy = clientSyncable.getClass().newInstance();
                    copy.copy(clientSyncable);
                    copy.setChangeType(ChangeType.NONE);
                    resultingDatabase.put(guid, copy);
                    break;
                }
                case ChangeType.EDITED: {
                    Syncable copy = clientSyncable.getClass().newInstance();
                    copy.copy(clientSyncable);
                    copy.setChangeType(ChangeType.NONE);
                    resultingDatabase.put(guid, copy);
                    break;
                }
                case ChangeType.DELETED: {
                    // Remove from database. Conflict. Client and server: DELETED/NONE, DELETED/DELETED (remove)
                    if (databaseSyncable == null || databaseSyncable.getChangeType() == ChangeType.NONE || databaseSyncable.getChangeType() == ChangeType.DELETED) {
                        resultingDatabase.remove(guid);
                    }
                    break;
                }
                default: {
                    break;
                }
            }
        }
        // Determine what to write to client.
        for (String guid : database.keySet()) {
            Syncable databaseSyncable = database.get(guid);
            Syncable clientSyncable = clientChanges.get(guid);
            switch (databaseSyncable.getChangeType()) {
                case ChangeType.NONE: {
                    if (merge) {
                        if (clientSyncable == null) {
                            Syncable copy = databaseSyncable.getClass().newInstance();
                            copy.copy(databaseSyncable);
                            copy.setChangeType(ChangeType.ADDED);
                            resultingClientChanges.put(guid, copy);
                        }
                    }
                    break;
                }
                case ChangeType.ADDED: {
                    // Send editions to client. Conflict. Client and server: NONE/ADDED, DELETED/ADDED (send)
                    if (clientSyncable == null || clientSyncable.getChangeType() == ChangeType.NONE || clientSyncable.getChangeType() == ChangeType.DELETED) {
                        Syncable copy = databaseSyncable.getClass().newInstance();
                        copy.copy(databaseSyncable);
                        resultingClientChanges.put(guid, copy);
                    }
                    break;
                }
                case ChangeType.EDITED: {
                    // Send editions to client. Conflict. Client and server: NONE/EDITED, DELETED/EDITED (send)
                    if (clientSyncable == null || clientSyncable.getChangeType() == ChangeType.NONE || clientSyncable.getChangeType() == ChangeType.DELETED) {
                        Syncable copy = databaseSyncable.getClass().newInstance();
                        copy.copy(databaseSyncable);
                        resultingClientChanges.put(guid, copy);
                    }
                    break;
                }
                case ChangeType.DELETED: {
                    // Send editions to client. Conflict. Client and server: NONE/DELETED, DELETED/DELETED (send)
                    if (clientSyncable == null || clientSyncable.getChangeType() == ChangeType.NONE || clientSyncable.getChangeType() == ChangeType.DELETED) {
                        Syncable copy = databaseSyncable.getClass().newInstance();
                        copy.copy(databaseSyncable);
                        resultingClientChanges.put(guid, copy);
                        resultingDatabase.remove(guid);
                    }
                    break;
                }
                default: {
                    break;
                }
            }
        }
    }
}
TOP

Related Classes of com.trechner.ksync4j.AbstractSyncServer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.