📄 sync4jstrategy.java
字号:
/** * Copyright (C) 2003-2004 Funambol * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package sync4j.server.engine;import java.util.List;import java.util.Arrays;import java.util.Iterator;import java.util.ArrayList;import java.util.Collection;import java.util.logging.*;import java.security.Principal;import java.sql.Timestamp;import sync4j.framework.core.ModificationCommand;import sync4j.framework.core.StatusCode;import sync4j.framework.engine.source.SyncSource;import sync4j.framework.engine.source.SyncSourceException;import sync4j.framework.engine.*;import sync4j.server.engine.SyncItemHelper;import sync4j.server.engine.Sync4jOperationStatusOK;import sync4j.server.engine.Sync4jOperationStatusError;import sync4j.server.engine.Sync4jOperationStatusConflict;import org.apache.commons.collections.ListUtils;/** * This class represents a synchronization process. * * The base concrete implementation of a synchronization strategy. It implements * the <i>ConcreteStrategy</i> partecipant of the Strategy Pattern. * <p> * The synchronization process is implemented in this class as follows: * <p> * Given a set of sources A, B, C, D, etc, the synchronization process takes place * between two sources at a time: A is first synchronzed with B, then AB with * C, then ABC with D and so on. <br> * The synchronization process is divided in three phases: preparation, synchronization, * finalization. These phases correspond to the methdos prepareSync, sync and * endSync; they are call-back methods called sequentially by a driver object, * usually a SyncMethod object. In this way the SyncMethod object has a chance * to communicate with the external world before carry on the process. * For example a SyncMethod object can show to the user the items that are going * to be synchronized, so that the user can let the process carry on or stop it. <br> * prepareSync returns an array of SyncOperation, in which each element represents * a particular synchronization action, ie. create an item in the source A, * delete the item X from the source B, etc. Sometime it is not possible decide * what to do, thus a SyncConflict operation is used. A conflict must be solved * by something external the synchronization process, for instance by a user * action. Below is a table of all possible situations. * <pre> * * | -------- | --- | --- | --- | --- | --- | * | Source A | | | | | | * | / | N | D | U | S | X | N : item new * | Source B | | | | | | D : item deleted * | -------- | --- | --- | --- | --- | --- | U : item updated * | N | O | O | O | O | B | S : item synchronized/unchanged * | -------- | --- | --- | --- | --- | --- | X : item not existing * | D | O | X | O | X | X | O : conflict * | -------- | --- | --- | --- | --- | --- | A : item A replaces item B * | U | O | O | O | B | B | B : item B replaces item A * | -------- | --- | --- | --- | --- | --- | * | S | O | X | A | = | B | * | -------- | --- | --- | --- | --- | --- | * | X | A | X | A | A | X | * | -------- | --- | --- | --- | --- | --- | * * </pre> * * @author Stefano Fornari @ Funambol * * @version $Id: Sync4jStrategy.java,v 1.25 2004/04/13 09:35:29 luigia Exp $ */public class Sync4jStrategy implements SyncStrategy, java.io.Serializable { // --------------------------------------------------------------- Constants public static String LOG_NAME = "sync4j.framework.engine"; private transient static Logger log = Logger.getLogger(LOG_NAME); // -------------------------------------------------------------- Properties /** * The synchronization source */ private transient SyncSource[] sources = null; public SyncSource[] getSources(){ return sources; } public void setSources(SyncSource[] sources){ this.sources = sources; } /** * The process' name */ public String getName(){ return name; } private String name; public void setName(String name){ this.name = name; } // ------------------------------------------------------------ Constructors public Sync4jStrategy() { } public Sync4jStrategy(SyncSource[] syncSources) { sources = syncSources; } // ---------------------------------------------------------- Public methods /** * Preparation for the synchronization. If <i>sources</i> is not null, * the preparation works on the given sources. Otherwise it works on the * sources as they were set in the constructor. * * @param sources the sources to be synchronized * @param principal the entity for which the synchronization is required * * @return an array of SyncOperation, one for each SyncItem that must be * created/updated/deleted or in conflict. * * @see sync4j.framework.engine.SyncStrategy */ public SyncOperation[] prepareSlowSync(SyncSource[] sources , Principal principal) throws SyncException { SyncItem[] allA = null, allB = null; if (sources != null) { this.sources = sources; } List syncOperations = null , Am = new ArrayList(), Bm = new ArrayList(), AmBm = null ; Logger log = Logger.getLogger(LOG_NAME); if (log.isLoggable(Level.INFO)) { log.info("Preparing slow synchronization for " + principal + " ..."); } allA = sources[1].getAllSyncItems(principal); allB = sources[0].getAllSyncItems(principal); // // Because it is a slow sync, items state must be reset to S // EngineHelper.resetState(Arrays.asList(allA)); EngineHelper.resetState(Arrays.asList(allB)); // // If any item from the client has not a corresponding mapping, the // server source must be queried for the item, since the client item // could be the same of an existing server item. In this case, the old // unmapped item is replaced in Map by the newly mapped item. // ArrayList newlyMappedItems = new ArrayList(); fixMappedItems(newlyMappedItems, allA, sources[0], principal, true); Am.addAll(Arrays.asList(allA)); Bm.addAll(Arrays.asList(allB)); AmBm = EngineHelper.intersect(Am, Bm); if (log.isLoggable(Level.FINEST)) { log.finest("Am: " + Am ); log.finest("Bm: " + Bm ); log.finest("AmBm: " + AmBm); } syncOperations = checkSyncOperations(principal, Am, Bm, AmBm, new ArrayList(), new ArrayList()); // // In the case of slow sync, delete operations are not needed // SyncOperation o = null; ArrayList ret = new ArrayList(); Iterator i = syncOperations.iterator(); while (i.hasNext()) { o = (SyncOperation)i.next(); if (o.getOperation() != SyncOperation.DELETE) { ret.add(o); } } if (log.isLoggable(Level.FINEST)) { log.finest("operations: " + ret); } log.info("Preparation completed."); return (SyncOperation[])ret.toArray(new SyncOperationImpl[] {}); } /** * Preparation for faset synchronization. If <i>sources</i> is not null, * the preparation operates on the given sources. Otherwise it works on the * sources as they were set in the constructor. * <p> * Refer to the <a href="http://sync4j.sourceforge.net/web/project/architecture/sync4j-architecture.html"> * architecture document</a> for details about the algoritm applied. * * @param sources the sources to be synchronized * @param principal the entity for which the synchronization is required * * @return an array of SyncOperation, one for each SyncItem that must be * created/updated/deleted or in conflict. * * @see sync4j.framework.engine.SyncStrategy */ public SyncOperation[] prepareFastSync(SyncSource[] sources , Principal principal, Timestamp since ) throws SyncException { if (sources != null) { this.sources = sources; } // --------------------------------------------------------------------- List Am , // items modified in A Bm , // items modified in B AmBm , // Am intersect Bm AAmBm , // items unmodified in A, but modified in B AmBBm ; // items unmodified in B, but modified in A ArrayList syncOperations = null; SyncItem[] newA = null, newB = null, updatedA = null, updatedB = null, deletedA = null, deletedB = null; if (log.isLoggable(Level.INFO)) { log.info( "Preparing fast synchronization for " + principal + " since " + since ); } // --------------------------------------------------------------------- // // NOTE: simplified version - only two sources, the first one of which // is the client // newA = sources[1].getNewSyncItems (principal, since); updatedA = sources[1].getUpdatedSyncItems (principal, since); deletedA = sources[1].getDeletedSyncItems (principal, since); newB = sources[0].getNewSyncItems (principal, since); updatedB = sources[0].getUpdatedSyncItems (principal, since); deletedB = sources[0].getDeletedSyncItems (principal, since); if (log.isLoggable(Level.FINEST)) { log.finest("newA: " + Util.arrayToString(newA)); log.finest("newB: " + Util.arrayToString(newB)); log.finest("updatedA: " + Util.arrayToString(updatedA)); log.finest("updatedB: " + Util.arrayToString(updatedB)); log.finest("deletedA: " + Util.arrayToString(deletedA)); log.finest("deletedB: " + Util.arrayToString(deletedB)); } // // If any item from the client has not a corresponding mapping, the // server source must be queried for the item, since the client item // could be the same of an existing server item. In this case, the old // unmapped item is replaced in Ma by the newly mapped item. // ArrayList newlyMappedItems = new ArrayList(); fixMappedItems(newlyMappedItems, newA, sources[0], principal, false); fixMappedItems(newlyMappedItems, updatedA, sources[0], principal, false); fixMappedItems(newlyMappedItems, deletedA, sources[0], principal, false);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -