phpgroupware-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Phpgroupware-cvs] sync/sync4j/de/probusiness/pbgroupware/sync/PHPGwSyn


From: nomail
Subject: [Phpgroupware-cvs] sync/sync4j/de/probusiness/pbgroupware/sync/PHPGwSyncStrategy.java, 1.2
Date: Wed, 9 Jun 2004 20:35:09 +0200

Update of /sync/sync4j/de/probusiness/pbgroupware/sync
Modified Files:
        Branch: 
          PHPGwSyncStrategy.java

date: 2004/06/09 18:35:09;  author: mkaemmerer;  state: Exp;  lines: +366 -28

Log Message:
- new sourceinfo and  mimetype handling
=====================================================================
Index: sync/sync4j/de/probusiness/pbgroupware/sync/PHPGwSyncStrategy.java
diff -u sync/sync4j/de/probusiness/pbgroupware/sync/PHPGwSyncStrategy.java:1.1 
sync/sync4j/de/probusiness/pbgroupware/sync/PHPGwSyncStrategy.java:1.2
--- sync/sync4j/de/probusiness/pbgroupware/sync/PHPGwSyncStrategy.java:1.1      
Wed Apr 14 17:49:25 2004
+++ sync/sync4j/de/probusiness/pbgroupware/sync/PHPGwSyncStrategy.java  Wed Jun 
 9 18:35:09 2004
@@ -10,6 +10,8 @@
 import java.util.*;
 import java.util.logging.*;
 
+import org.apache.xmlrpc.*;
+
 import sync4j.framework.core.*;
 import sync4j.framework.engine.*;
 import sync4j.framework.engine.source.*;
@@ -26,15 +28,15 @@
 public class PHPGwSyncStrategy extends Sync4jStrategy {
 
        private static interface ConflictAction {
-               public Sync4jOperationStatus handleConflict(
+               public Sync4jOperationStatus[] handleConflict(
                                final SyncOperationImpl op, final Principal 
owner,
                                SyncItem a, SyncItem b,
                                final SyncSource source0, final SyncSource 
source1
                );
        }
        
-       private static final class AWinsCOnflictAction implements 
ConflictAction {
-               public Sync4jOperationStatus handleConflict(final 
SyncOperationImpl op, final Principal owner,
+       private static final class AWinsConflictAction implements 
ConflictAction {
+               public Sync4jOperationStatus[] handleConflict(final 
SyncOperationImpl op, final Principal owner,
                                SyncItem a, SyncItem b,
                                final SyncSource source0, final SyncSource 
source1) {
                        final ModificationCommand cmd = (ModificationCommand) 
a.getPropertyValue(SyncItemHelper.PROPERTY_COMMAND);
@@ -42,17 +44,81 @@
                                a = source1.setSyncItem(owner, b);
                                op.setSyncItemA(a);
                                op.setAOperation(true);
-                               return new Sync4jOperationStatusConflict(op, 
source1, cmd, StatusCode.CONFLICT_RESOLVED_WITH_SERVER_DATA);
+                               return new Sync4jOperationStatus[] {
+                                       new Sync4jOperationStatusConflict(op, 
source1, cmd, StatusCode.CONFLICT_RESOLVED_WITH_SERVER_DATA)
+                               };
                        } catch (SyncException e) {
                                log.severe("Error executing sync operation: " + 
e.getMessage());
                                log.throwing(getClass().getName(), 
"execSyncOperation", e);
-                               return new Sync4jOperationStatusError(op, 
source1, cmd, e);
+                               return new Sync4jOperationStatus[] {
+                                       new Sync4jOperationStatusError(op, 
source1, cmd, e)
+                               };
                        }
                }
        }
        
-       private static final class BWinsCOnflictAction implements 
ConflictAction {
-               public Sync4jOperationStatus handleConflict(
+       private static final class DuplicateConflictAction implements 
ConflictAction {
+               public Sync4jOperationStatus[] handleConflict(final 
SyncOperationImpl op, final Principal owner,
+                               SyncItem a, SyncItem b,
+                               final SyncSource source0, final SyncSource 
source1) {
+                       final ModificationCommand cmd = (ModificationCommand) 
a.getPropertyValue(SyncItemHelper.PROPERTY_COMMAND);
+                       final SyncItem buf = a;
+                       // so for duplicate we first perform the same as if the 
server would win:
+                       final Set stats = new HashSet();
+                       try {
+                               a = source1.setSyncItem(owner, b);
+                               op.setSyncItemA(a);
+                               op.setAOperation(true);
+                               stats.add(
+                                       new Sync4jOperationStatusConflict(op, 
source1, cmd, StatusCode.CONFLICT_RESOLVED_WITH_SERVER_DATA)
+                               );
+                       } catch (SyncException e) {
+                               log.severe("Error executing sync operation: " + 
e.getMessage());
+                               log.throwing(getClass().getName(), 
"execSyncOperation", e);
+                               stats.add(
+                                       new Sync4jOperationStatusError(op, 
source1, cmd, e)
+                               );
+                       }
+                       // then we take the other item, generating a new key 
for it by prepending "duped" to its
+                       // textual representation:
+                       final SyncItemKey oldkey = buf.getKey();
+                       final SyncItem newItem = new SyncItemImpl(source1, 
"duped" + oldkey.getKeyAsString());
+                       final SyncProperty dataprop = new SyncProperty(
+                               SyncItem.PROPERTY_BINARY_CONTENT, 
buf.getPropertyValue(SyncItem.PROPERTY_BINARY_CONTENT)
+                       );
+                       final SyncProperty timeprop = new SyncProperty(
+                               SyncItem.PROPERTY_TIMESTAMP, 
buf.getPropertyValue(SyncItem.PROPERTY_TIMESTAMP)
+                       );
+                       newItem.setProperty(dataprop);
+                       newItem.setProperty(timeprop);
+                       // then we put the new item into both of the sources
+                       // I can only hope, that the state- and 
item-assignement-handling is correct
+                       try {
+                               source0.setSyncItem(owner, newItem);
+                               source1.setSyncItem(owner, newItem);
+                               // INFO changed itemstate-behaviour here
+                               // INFO comment out next three line if still 
not working
+                               // newItem.setState(SyncItemState.SYNCHRONIZED);
+                               newItem.setState(SyncItemState.NEW);
+                               op.setSyncItemB(newItem);
+                               op.setBOperation(true);
+                               stats.add(
+                                       new Sync4jOperationStatusConflict(op, 
source0, cmd, StatusCode.CONFLICT_RESOLVED_WITH_DUPLICATE)
+                               );
+                       }
+                       catch (final SyncException e) {
+                               log.severe("Error executing sync operation: " + 
e.getMessage());
+                               log.throwing(getClass().getName(), 
"execSyncOperation", e);
+                               stats.add(
+                                       new Sync4jOperationStatusError(op, 
source0, cmd, e)
+                               );
+                       }
+                       return (Sync4jOperationStatus[]) stats.toArray(new 
Sync4jOperationStatus[stats.size()]);
+               }
+       }
+       
+       private static final class BWinsConflictAction implements 
ConflictAction {
+               public Sync4jOperationStatus[] handleConflict(
                                final SyncOperationImpl op, final Principal 
owner,
                                SyncItem a, SyncItem b,
                                final SyncSource source0, final SyncSource 
source1) {
@@ -63,75 +129,226 @@
                                b = source0.setSyncItem(owner, a);
                                op.setSyncItemB(b);
                                op.setBOperation(true);
-                               return new Sync4jOperationStatusConflict(op, 
source0, cmd, StatusCode.CONFLICT_RESOLVED_WITH_CLIENT_COMMAND_WINNING);
+                               return new Sync4jOperationStatus[] {
+                                       new Sync4jOperationStatusConflict(op, 
source0, cmd, StatusCode.CONFLICT_RESOLVED_WITH_CLIENT_COMMAND_WINNING)
+                               };
                        } catch (SyncException e) {
                                log.severe("Error executing sync operation: " + 
e.getMessage());
                                log.throwing(getClass().getName(), 
"execSyncOperation", e);
-                               return new Sync4jOperationStatusError(op, 
source0, cmd, e);
+                               return new Sync4jOperationStatus[] {
+                                       new Sync4jOperationStatusError(op, 
source0, cmd, e)
+                               };
                        }
                }
        }
 
+       private static final class DoNothingConflictAction implements 
ConflictAction {
+               public Sync4jOperationStatus[] handleConflict(final 
SyncOperationImpl op, final Principal owner,
+                               SyncItem a, SyncItem b,
+                               final SyncSource source0, final SyncSource 
source1) {
+                       log.finest("starting to do nothing");
+                       if (op.isBOperation()) {
+                               // don't know why to use here the a-command, 
but the original strategy
+                               // does so and so do we now...
+                               //ModificationCommand cmd = 
(ModificationCommand) b.getPropertyValue(SyncItemHelper.PROPERTY_COMMAND);
+                               ModificationCommand cmd = (ModificationCommand) 
a.getPropertyValue(SyncItemHelper.PROPERTY_COMMAND);
+                               return new Sync4jOperationStatus[] {
+                                       new Sync4jOperationStatusOK(op, 
source0, cmd)
+                               };
+                       }
+                       else { // is op.isAOperation
+                               ModificationCommand cmd = (ModificationCommand) 
a.getPropertyValue(SyncItemHelper.PROPERTY_COMMAND);
+                               return new Sync4jOperationStatus[] {
+                                       new Sync4jOperationStatusOK(op, 
source1, cmd)
+                               };
+                       }
+               }
+       }
+       
        private static final Map CONFLICT_ACTIONS;
        static {
                final Map m = new HashMap();
-               m.put("serverwins", new AWinsCOnflictAction());
-               m.put("clientwins", new BWinsCOnflictAction());
+               m.put("serverwins", new AWinsConflictAction());
+               m.put("clientwins", new BWinsConflictAction());
+               m.put("donothing", new DoNothingConflictAction());
+               m.put("duplicate", new DuplicateConflictAction());
                CONFLICT_ACTIONS = Collections.unmodifiableMap(m);
        }
 
        protected static transient Logger log = Sync4jLogger.getLogger();
 
+       public static final String CONTENT_TYPE_KEY_TYPE = "contentType.type";
+       public static final String CONTENT_TYPE_KEY_VERSION = 
"contentType.version";
+
        /**
         * 
         */
        public PHPGwSyncStrategy() {
                super();
-               // TODO Auto-generated constructor stub
        }
 
        /**
         * @param syncSources
         */
-       public PHPGwSyncStrategy(SyncSource[] syncSources) {
+       public PHPGwSyncStrategy(final SyncSource[] syncSources) {
                super(syncSources);
-               // TODO Auto-generated constructor stub
        }
 
        /* (non-Javadoc)
         * @see 
sync4j.server.engine.Sync4jStrategy#execSyncOperation(sync4j.framework.engine.SyncOperationImpl)
         */
-       protected SyncOperationStatus[] execSyncOperation(SyncOperationImpl 
operation) {
-               SyncItem syncItemA = operation.getSyncItemA(); 
-               SyncItem syncItemB = operation.getSyncItemB();
-               final Principal owner = operation.getOwner();
-               final SyncSource[] sources = getSources();
+       protected SyncOperationStatus[] execSyncOperation(final 
SyncOperationImpl operation) {
+               log.fine("start executing sync-op");
                if (operation.getOperation() == SyncOperation.CONFLICT) {
+                       SyncItem syncItemA = operation.getSyncItemA(); 
+                       SyncItem syncItemB = operation.getSyncItemB();
+                       final Principal owner = operation.getOwner();
+                       final SyncSource[] sources = getSources();
+                       log.fine("found conflict; preparing xml-rpc-call");
                        final Vector params = new Vector();
                        params.add(syncItemA.getKey().getKeyAsString());
-                       params.add(syncItemB.getKey().getKeyAsString());
+                       final Object clientData = 
syncItemA.getPropertyValue(SyncItem.PROPERTY_BINARY_CONTENT);
+                       log.finer("found client-item; data is of type (" + 
clientData.getClass().getName() + ")");
+                       if (clientData instanceof String) {
+                               params.add(clientData);
+                       }
+                       else if (clientData instanceof byte[]) {
+                               params.add(new String(Base64.encode((byte[]) 
clientData)));
+                       }
+                       else {
+                               params.add(clientData.toString());
+                       }
+                       
                        Object ret = null;
                        try {
-                               ret = executeXMLRPC(owner, "handleConflict", 
params);
+                               log.fine("executing xml-rpc-call");
+                               ret = executeXMLRPC(owner, sources[1], 
"handleConflict", params);
+                               log.fine("executed xml-rpc-call");
                        }
                        catch (final SyncSourceException e) {
-                               // TODO logging
+                               log.severe("Error executing sync operation: " + 
e.getMessage());
+                               log.throwing(getClass().getName(), 
"execSyncOperation", e);
+                               final ModificationCommand cmd = 
(ModificationCommand) 
syncItemA.getPropertyValue(SyncItemHelper.PROPERTY_COMMAND);
+                               return new SyncOperationStatus[] {
+                                       new 
Sync4jOperationStatusError(operation, sources[1], cmd, e)
+                               };
                        }
                        if (ret != null) {
-                               final ConflictAction action = (ConflictAction) 
CONFLICT_ACTIONS.get(ret);
+                               log.fine("conflict-action returned; dispatch 
handling (" + ret + ")");
+                               final ConflictAction action = (ConflictAction) 
CONFLICT_ACTIONS.get(ret.toString().toLowerCase());
                                if (action != null) {
-                                       return new SyncOperationStatus[] {
-                                               
action.handleConflict(operation, owner, syncItemA, syncItemB, sources[0], 
sources[1])
-                                       };
+                                       log.fine("conflict-action resolved; 
action (" + action.getClass().getName() + ")");
+                                       return action.handleConflict(operation, 
owner, syncItemA, syncItemB, sources[0], sources[1]);
                                }
                        }
                }
                return super.execSyncOperation(operation);
        }
 
-       private final Object executeXMLRPC(final Principal principal, final 
String methodname, final Vector params) throws SyncSourceException {
-               // prepend device_id to parameter-list
+       private static interface AB {
+               public SyncItem getSyncItem(SyncOperation op);
+               public void setSyncItem(SyncOperation op, SyncItem item);
+       }
+       private static final AB AB_AOP = new AB() {
+               public final SyncItem getSyncItem(final SyncOperation op) {
+                       return op.getSyncItemB();
+               }
+               public final void setSyncItem(final SyncOperation op, final 
SyncItem item) {
+                       op.setSyncItemA(item);
+               }
+       };
+       private static final AB AB_BOP = new AB() {
+               public final SyncItem getSyncItem(final SyncOperation op) {
+                       return op.getSyncItemA();
+               }
+               public final void setSyncItem(final SyncOperation op, final 
SyncItem item) {
+                       op.setSyncItemB(item);
+               }
+       };
+
+       private final Collection executeBulkSet(final Collection ops) {
+      // dividing in A- and B-operations and sorting by owner
+      final Map aops = new LinkedHashMap();
+      final Map bops = new LinkedHashMap();
+      for (final Iterator it = ops.iterator(); it.hasNext();) {
+                       final SyncOperation op = (SyncOperation) it.next();
+                       final Principal owner = op.getOwner();
+                       final Map toPut;
+                       if (op.isAOperation()) {
+                               toPut = aops;
+                       }
+                       else {
+                               toPut = bops;
+                       }
+                       Collection ownerops = (Collection) toPut.get(owner);
+                       if (ownerops == null) {
+                               ownerops = new LinkedHashSet();
+                               toPut.put(owner, ownerops);
+                       }
+                       ownerops.add(op);
+               }
+               // preparing
+               final SyncSource[] sources = getSources();
+               final Collection status = new LinkedList();
+               // executing
+               executeBulkSet(aops, sources[1], status, AB_AOP);
+               executeBulkSet(bops, sources[0], status, AB_BOP);
+               return status;
+       }
+       
+       /**
+        * @param operationsMap
+        * @param sources
+        * @param status
+        */
+       private void executeBulkSet(final Map operationsMap, final SyncSource 
source, final Collection status, final AB ab) {
+               // handling A-operations
+               for (final Iterator it = operationsMap.entrySet().iterator(); 
it.hasNext();) {
+                       final Map.Entry entry = (Map.Entry) it.next();
+                       final Principal owner = (Principal) entry.getKey();
+                       final Collection operations = (Collection) 
entry.getValue();
+                       final SyncItem[] bitems = new 
SyncItem[operations.size()];
+                       int i = 0;
+                       for (final Iterator jt = operations.iterator(); 
jt.hasNext(); i++) {
+                               final SyncOperation op = (SyncOperation) 
jt.next();
+                               bitems[i] = ab.getSyncItem(op);
+                       }
+                       SyncItem[] aitems = null;
+                       try {
+                               aitems = source.setSyncItems(owner, bitems);
+                       }
+                       catch (final SyncSourceException e) {
+                               log.severe("Error executing sync operation: " + 
e.getMessage());
+                               log.throwing(getClass().getName(), 
"execSyncOperation", e);
+                               for (final Iterator jt = operations.iterator(); 
jt.hasNext(); i++) {
+                                       final SyncOperation op = 
(SyncOperation) jt.next();
+                                       final SyncItem aitem = aitems[i];
+                                       final ModificationCommand cmd =
+                                               (ModificationCommand) 
aitem.getPropertyValue(SyncItemHelper.PROPERTY_COMMAND);
+                                       status.add(new 
Sync4jOperationStatusError(op, source, cmd, e));
+                               }
+                       }
+                       i = 0;
+                       for (final Iterator jt = operations.iterator(); 
jt.hasNext(); i++) {
+                               final SyncOperation op = (SyncOperation) 
jt.next();
+                               final SyncItem aitem = aitems[i];
+                               final ModificationCommand cmd =
+                                       (ModificationCommand) 
aitem.getPropertyValue(SyncItemHelper.PROPERTY_COMMAND);
+                               ab.setSyncItem(op, aitem);
+                               status.add(new Sync4jOperationStatusOK(op, 
source, cmd));
+                       }
+               }
+       }
+
+//     private final Collection executeBulkDelete(final Collection ops) {
+//             // TODO
+//             return null;
+//     }
+       
+       private final Object executeXMLRPC(final Principal principal, final 
SyncSource source, final String methodname, final Vector params) throws 
SyncSourceException {
+               // prepend device_id and source-name to parameter-list
                params.add(0, ((Sync4jPrincipal) principal).getId());
+               params.add(1, source.getName());
                // prepare ipc-dispatch
                final Vector fparams = new Vector();
                fparams.add("sync." + methodname);
@@ -139,4 +356,125 @@
                return 
PHPGwSyncXMLRPCClient.getInstance().execute("phpgwapi.ipc_manager.execIPC", 
fparams);
        }
 
+       /* (non-Javadoc)
+        * @see 
sync4j.server.engine.Sync4jStrategy#checkSyncOperation(java.security.Principal, 
sync4j.framework.engine.SyncItem, sync4j.framework.engine.SyncItem)
+        */
+       protected SyncOperation checkSyncOperation(final Principal principal, 
final SyncItem syncItemA, final SyncItem syncItemB) {
+               log.fine("intercepting sync-op");
+               SyncOperation op = super.checkSyncOperation(principal, 
syncItemA, syncItemB);
+               log.fine("!!!!!: found sync-op -> " + op);
+               if (op instanceof SyncConflict) {
+                       log.fine("found conflict (" + op + ")");
+                       op = new PHPGwSyncConflict((SyncConflict) op, 
principal);
+                       log.fine("replaced conflict with: <" + op + ">");
+               }
+               return op;
+       }
+
+       private static final void publishSourceInfo(final Principal principal, 
final SyncSource clsource) {
+               final SyncSourceInfo info = clsource.getInfo();
+               final ContentType[] supportedTypes = info.getSupportedTypes();
+               final int len = supportedTypes.length;
+               final Vector xrtypes = new Vector(len);
+               for (int i = 0; i < len; i++) {
+                       final ContentType type = supportedTypes[i];
+                       final Hashtable xrtype = new Hashtable();
+                       xrtype.put(CONTENT_TYPE_KEY_TYPE, type.getType());
+                       xrtype.put(CONTENT_TYPE_KEY_VERSION, type.getVersion());
+                       xrtypes.add(xrtype);
+               }
+               if (xrtypes.isEmpty()) {
+                       final ContentType type = info.getPreferredType();
+                       final Hashtable xrtype = new Hashtable();
+                       xrtype.put(CONTENT_TYPE_KEY_TYPE, type.getType());
+                       xrtype.put(CONTENT_TYPE_KEY_VERSION, type.getVersion());
+                       xrtypes.add(xrtype);
+               }
+               
+               
+               final Vector params = new Vector();
+               // prepend device_id to parameter-list
+               params.add(((Sync4jPrincipal) principal).getId());
+               params.add(xrtypes);
+               // prepare ipc-dispatch
+               final Vector fparams = new Vector();
+               fparams.add("sync.setSourceInfoSupportedTypes");
+               fparams.add(params);
+               try {
+                       
PHPGwSyncXMLRPCClient.getInstance().execute("phpgwapi.ipc_manager.execIPC", 
fparams);
+               }
+               catch (final SyncSourceException e) {
+                       log.throwing(PHPGwSyncStrategy.class.getName(), "error 
publishing SyncSourceInfo.supportedTypes", e);
+               }
+       }
+       
+       /* (non-Javadoc)
+        * @see 
sync4j.framework.engine.SyncStrategy#prepareFastSync(sync4j.framework.engine.source.SyncSource[],
 java.security.Principal, java.sql.Timestamp)
+        */
+       public SyncOperation[] prepareFastSync(final SyncSource[] sources, 
final Principal principal, final java.sql.Timestamp since) throws SyncException 
{
+               publishSourceInfo(principal, sources[0]);
+               return super.prepareFastSync(sources, principal, since);
+       }
+
+       /* (non-Javadoc)
+        * @see 
sync4j.framework.engine.SyncStrategy#prepareSlowSync(sync4j.framework.engine.source.SyncSource[],
 java.security.Principal)
+        */
+       public SyncOperation[] prepareSlowSync(final SyncSource[] sources, 
final Principal principal) throws SyncException {
+               publishSourceInfo(principal, sources[0]);
+               return super.prepareSlowSync(sources, principal);
+       }
+
+       /* (non-Javadoc)
+        * @see 
sync4j.framework.engine.SyncStrategy#sync(sync4j.framework.engine.SyncOperation[])
+        */
+       public SyncOperationStatus[] sync(final SyncOperation[] syncOperations) 
{
+      final Logger log = Logger.getLogger(LOG_NAME);
+               log.info("Synchronizing...");
+               if ((syncOperations == null) || (syncOperations.length == 0)) {
+                       return new SyncOperationStatus[0];
+               }
+      
+               final Collection status = new ArrayList();
+
+               final Collection setOps = new LinkedList();
+//             final Collection delOps = new LinkedList();
+               final Collection miscOps = new LinkedList();
+               final int len = syncOperations.length;
+               for (int i = 0; i < len; i++) {
+                       final SyncOperation operation = syncOperations[i];
+                       final Collection toAdd;
+                       switch (operation.getOperation()) {
+                               case SyncOperation.NEW:
+                               case SyncOperation.UPDATE:
+                                       toAdd = setOps;
+                                       break;
+//                             case SyncOperation.DELETE:
+//                                     toAdd = delOps;
+//                                     break;
+                               default:
+                                       toAdd = miscOps;
+                                       break;
+                       }
+                       toAdd.add(operation);
+               }
+               final SyncOperation[] syncOperations_2 =
+                       (SyncOperation[]) miscOps.toArray(new 
SyncOperation[miscOps.size()]);
+
+               status.addAll(executeBulkSet(setOps));
+//             status.addAll(executeBulkDelete(delOps));
+               
+      for (int i = 0; i < syncOperations_2.length; ++i) {
+                       if (log.isLoggable(Level.FINE)) {
+                               log.fine("Executing " + syncOperations_2[i]);
+                       }
+                       status.addAll(Arrays.asList(
+                               execSyncOperation((SyncOperationImpl) 
syncOperations_2[i])
+                       ));
+               }
+               log.fine("Synchronization completed.");
+               if (log.isLoggable(Level.FINE)) {
+                       log.fine("status: " + status);
+               }
+               return (SyncOperationStatus[]) status.toArray(new 
SyncOperationStatus[status.size()]);
+       }
 }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]