Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorisikm2008-06-16 07:07:04 -0400
committerisikm2008-06-16 07:07:04 -0400
commit0733a49e068389bc801fd9f59217d9d8025b09ad (patch)
tree4e6c6e827259b82479dbef1b81df932d9b5a9e6e
parentdea49cda91696cb4d07d6e14b9e4663ac5f2333c (diff)
downloadorg.eclipse.ecf-0733a49e068389bc801fd9f59217d9d8025b09ad.tar.gz
org.eclipse.ecf-0733a49e068389bc801fd9f59217d9d8025b09ad.tar.xz
org.eclipse.ecf-0733a49e068389bc801fd9f59217d9d8025b09ad.zip
included last operational transformation mechanism - that is deletions vs. insertions - and required adaptations at various places
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/DocShare.java16
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/IdentityMapping.java8
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/SynchronizationStrategy.java3
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaDeletion.java3
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaSynchronizer.java92
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaUpdateMessage.java5
6 files changed, 88 insertions, 39 deletions
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/DocShare.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/DocShare.java
index 99b9be863..57a75e865 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/DocShare.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/DocShare.java
@@ -12,10 +12,9 @@
package org.eclipse.ecf.internal.provisional.docshare;
-import org.eclipse.ecf.internal.provisional.docshare.cola.ColaSynchronizer;
-import org.eclipse.ecf.internal.provisional.docshare.messages.*;
-
import java.io.*;
+import java.util.Iterator;
+import java.util.List;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.*;
@@ -27,6 +26,8 @@ import org.eclipse.ecf.datashare.AbstractShare;
import org.eclipse.ecf.datashare.IChannelContainerAdapter;
import org.eclipse.ecf.datashare.events.IChannelDisconnectEvent;
import org.eclipse.ecf.internal.docshare.*;
+import org.eclipse.ecf.internal.provisional.docshare.cola.ColaSynchronizer;
+import org.eclipse.ecf.internal.provisional.docshare.messages.*;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.*;
import org.eclipse.osgi.util.NLS;
@@ -340,14 +341,17 @@ public class DocShare extends AbstractShare {
// The idea here is to be transparent with the sync'ing
// strategy.
Trace.trace(Activator.PLUGIN_ID, NLS.bind("{0}.handleUpdateMessage calling transformIncomingMessage", DocShare.this)); //$NON-NLS-1$
- UpdateMessage msgForLocalApplication = sync.transformIncomingMessage(remoteMsg);
+ List messagesForLocalApplication = sync.transformIncomingMessage(remoteMsg);
// if (localState.equalsIgnoreCase(remoteState)) {
// We setup editor to not take input while we are
// changing document
setEditorToRefuseInput();
-
- document.replace(msgForLocalApplication.getOffset(), msgForLocalApplication.getLengthOfReplacedText(), msgForLocalApplication.getText());
+ UpdateMessage currentMsg;
+ for (Iterator it = messagesForLocalApplication.iterator(); it.hasNext();) {
+ currentMsg = (UpdateMessage) it.next();
+ document.replace(currentMsg.getOffset(), currentMsg.getLengthOfReplacedText(), currentMsg.getText());
+ }
}
} catch (final Exception e) {
logError(Messages.DocShare_EXCEPTION_RECEIVING_MESSAGE_TITLE, e);
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/IdentityMapping.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/IdentityMapping.java
index ec2bdc88d..474f7ecfc 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/IdentityMapping.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/IdentityMapping.java
@@ -11,6 +11,8 @@
package org.eclipse.ecf.internal.provisional.docshare;
+import java.util.LinkedList;
+import java.util.List;
import org.eclipse.ecf.internal.provisional.docshare.messages.UpdateMessage;
public class IdentityMapping implements SynchronizationStrategy {
@@ -28,8 +30,10 @@ public class IdentityMapping implements SynchronizationStrategy {
return localMsg;
}
- public UpdateMessage transformIncomingMessage(UpdateMessage remoteMsg) {
- return remoteMsg;
+ public List transformIncomingMessage(UpdateMessage remoteMsg) {
+ List returnList = new LinkedList();
+ returnList.add(remoteMsg);
+ return returnList;
}
public String toString() {
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/SynchronizationStrategy.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/SynchronizationStrategy.java
index ce7c9e45b..37cab5699 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/SynchronizationStrategy.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/SynchronizationStrategy.java
@@ -11,12 +11,13 @@
package org.eclipse.ecf.internal.provisional.docshare;
+import java.util.List;
import org.eclipse.ecf.internal.provisional.docshare.messages.UpdateMessage;
public interface SynchronizationStrategy {
public UpdateMessage registerOutgoingMessage(UpdateMessage localMsg);
- public UpdateMessage transformIncomingMessage(UpdateMessage remoteMsg);
+ public List transformIncomingMessage(UpdateMessage remoteMsg);
}
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaDeletion.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaDeletion.java
index 19bd205b2..adb66215f 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaDeletion.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaDeletion.java
@@ -11,11 +11,10 @@
package org.eclipse.ecf.internal.provisional.docshare.cola;
-import org.eclipse.ecf.internal.provisional.docshare.messages.UpdateMessage;
-
import org.eclipse.ecf.core.util.Trace;
import org.eclipse.ecf.internal.docshare.Activator;
import org.eclipse.ecf.internal.docshare.DocshareDebugOptions;
+import org.eclipse.ecf.internal.provisional.docshare.messages.UpdateMessage;
public class ColaDeletion implements TransformationStrategy {
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaSynchronizer.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaSynchronizer.java
index 0bff09038..3935802c3 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaSynchronizer.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaSynchronizer.java
@@ -11,15 +11,14 @@
package org.eclipse.ecf.internal.provisional.docshare.cola;
-import org.eclipse.ecf.internal.provisional.docshare.DocShare;
-import org.eclipse.ecf.internal.provisional.docshare.SynchronizationStrategy;
-import org.eclipse.ecf.internal.provisional.docshare.messages.UpdateMessage;
-
import java.util.*;
import org.eclipse.core.runtime.Assert;
import org.eclipse.ecf.core.util.Trace;
import org.eclipse.ecf.internal.docshare.Activator;
import org.eclipse.ecf.internal.docshare.DocshareDebugOptions;
+import org.eclipse.ecf.internal.provisional.docshare.DocShare;
+import org.eclipse.ecf.internal.provisional.docshare.SynchronizationStrategy;
+import org.eclipse.ecf.internal.provisional.docshare.messages.UpdateMessage;
import org.eclipse.osgi.util.NLS;
public class ColaSynchronizer implements SynchronizationStrategy {
@@ -66,17 +65,21 @@ public class ColaSynchronizer implements SynchronizationStrategy {
* shared document. The method implements the concurrency algorithm described
* in <code>http://wiki.eclipse.org/RT_Shared_Editing</code>
* @param remoteMsg
- * @return UpdateMessage
+ * @return List contains <code>UpdateMessage</code>s ready for sequential application to document
*/
- public UpdateMessage transformIncomingMessage(final UpdateMessage remoteMsg) {
+ public List transformIncomingMessage(final UpdateMessage remoteMsg) {
if (!(remoteMsg instanceof ColaUpdateMessage)) {
throw new IllegalArgumentException("UpdateMessage is incompatible with Cola SynchronizationStrategy"); //$NON-NLS-1$
}
Trace.entering(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_ENTERING, this.getClass(), "transformIncomingMessage", remoteMsg); //$NON-NLS-1$
ColaUpdateMessage transformedRemote = (ColaUpdateMessage) remoteMsg;
+
+ List transformedRemotes = new LinkedList();
+ transformedRemotes.add(transformedRemote);
+
remoteOperationsCount++;
- // TODO this is where the concurrency algorithm is executed
- if (!unacknowledgedLocalOperations.isEmpty()) {
+ //this is where the concurrency algorithm is executed
+ if (!unacknowledgedLocalOperations.isEmpty()) {//Do not remove this. It is necessary. The following iterator does not suffice.
// remove operations from queue that have been implicitly
// acknowledged as received on the remote site by the reception of
// this message
@@ -98,36 +101,73 @@ public class ColaSynchronizer implements SynchronizationStrategy {
break;// exits for-loop
}
}
+
// at this point the queue has been freed of operations that
// don't require to be transformed against
- // TODO this is where the BUG is - I am not adapting/modifying the
- // queued up operations!!! 2008-06-08
if (!unacknowledgedLocalOperations.isEmpty()) {
ColaUpdateMessage localOp = (ColaUpdateMessage) unacknowledgedLocalOperations.getFirst();
Assert.isTrue(transformedRemote.getRemoteOperationsCount() == localOp.getLocalOperationsCount());
- for (final ListIterator listIt = unacknowledgedLocalOperations.listIterator(); listIt.hasNext();) {
- // returns new instance
- // clarify operation preference, owner/docshare initiator
- // consistently comes first
- localOp = (ColaUpdateMessage) listIt.next();
- transformedRemote = transformedRemote.transformAgainst(localOp, isInitiator);
-
- //TODO check whether or not this collection shuffling does what it is supposed to, i.e. remove current localop in unack list and add split up representation instead
- if (localOp.isSplitUp()) {
- //local operation has been split up during operational transform --> remove current version and add new versions plus jump over those
- listIt.remove();
- for (final Iterator splitUpOpIterator = localOp.getSplitUpRepresentation().iterator(); splitUpOpIterator.hasNext();) {
- listIt.add(splitUpOpIterator.next());
+
+ for (final ListIterator unackOpsListIt = unacknowledgedLocalOperations.listIterator(); unackOpsListIt.hasNext();) {
+ for (final ListIterator trafoRemotesIt = transformedRemotes.listIterator(); trafoRemotesIt.hasNext();) {
+ // returns new instance
+ // clarify operation preference, owner/docshare initiator
+ // consistently comes first
+ localOp = (ColaUpdateMessage) unackOpsListIt.next();
+ transformedRemote = (ColaUpdateMessage) trafoRemotesIt.next();
+ transformedRemote = transformedRemote.transformAgainst(localOp, isInitiator);
+
+ if (transformedRemote.isSplitUp()) {
+ //currently this only happens for a remote deletion that needs to be transformed against a locally applied insertion
+ //attention: before applying a list of deletions to docshare, the indices need to be updated/finalized one last time
+ //since deletions can only be applied sequentially and every deletion is going to change the underlying document and the
+ //respective indices!
+ trafoRemotesIt.remove();
+ for (final Iterator splitUpIterator = transformedRemote.getSplitUpRepresentation().iterator(); splitUpIterator.hasNext();) {
+ trafoRemotesIt.add(splitUpIterator.next());
+ }
+ //according to the ListIterator documentation it seems so as if the following line is unnecessary,
+ //as a call to next() after the last removal and additions will return what it would have returned anyway
+ //trafoRemotesIt.next();//TODO not sure about the need for this - I want to jump over the two inserted ops and reach the end of this iterator
}
- listIt.next();//jump over both inserted operations that replaced the current unack op
- }//end split up localop handling
+
+ //TODO check whether or not this collection shuffling does what it is supposed to, i.e. remove current localop in unack list and add split up representation instead
+ if (localOp.isSplitUp()) {
+ //local operation has been split up during operational transform --> remove current version and add new versions plus jump over those
+ unackOpsListIt.remove();
+ for (final Iterator splitUpOpIterator = localOp.getSplitUpRepresentation().iterator(); splitUpOpIterator.hasNext();) {
+ unackOpsListIt.add(splitUpOpIterator.next());
+ }
+ //according to the ListIterator documentation it seems so as if the following line is unnecessary,
+ //as a call to next() after the last removal and additions will return what it would have returned anyway
+ //unackOpsListIt.next();//TODO check whether or not this does jump over both inserted operations that replaced the current unack op
+ }//end split up localop handling
+ }//transformedRemotes List iteration
}
}
}
Trace.exiting(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_EXITING, this.getClass(), "transformIncomingMessage", transformedRemote); //$NON-NLS-1$
- return transformedRemote;
+
+ //TODO find a cleaner and more OO way of cleaning up the list if it contains multiple deletions:
+ if (transformedRemotes.size() > 1) {
+ ColaUpdateMessage firstOp = (ColaUpdateMessage) transformedRemotes.get(0);
+ if (firstOp.isDeletion()) {
+ //this means all operations in the return list must also be deletions, i.e. modify virtual/optimistic offset for sequential application to document
+ ListIterator deletionFinalizerIt = transformedRemotes.listIterator();
+ ColaUpdateMessage previousDel = (ColaUpdateMessage) deletionFinalizerIt.next();//jump over first del-op does not need modification, we know this is OK because of previous size check;
+ ColaUpdateMessage currentDel;
+
+ for (; deletionFinalizerIt.hasNext();) {
+ currentDel = (ColaUpdateMessage) deletionFinalizerIt.next();
+ currentDel.setOffset(currentDel.getOffset() - previousDel.getLengthOfReplacedText());
+ previousDel = currentDel;
+ }
+ }
+ }
+
+ return transformedRemotes;
}
public String toString() {
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaUpdateMessage.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaUpdateMessage.java
index e02538272..dd0c4add5 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaUpdateMessage.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/provisional/docshare/cola/ColaUpdateMessage.java
@@ -11,13 +11,12 @@
package org.eclipse.ecf.internal.provisional.docshare.cola;
-import org.eclipse.ecf.internal.provisional.docshare.messages.UpdateMessage;
-
import java.util.LinkedList;
import java.util.List;
import org.eclipse.ecf.core.util.Trace;
import org.eclipse.ecf.internal.docshare.Activator;
import org.eclipse.ecf.internal.docshare.DocshareDebugOptions;
+import org.eclipse.ecf.internal.provisional.docshare.messages.UpdateMessage;
public class ColaUpdateMessage extends UpdateMessage {
@@ -49,6 +48,8 @@ public class ColaUpdateMessage extends UpdateMessage {
// something has been replaced with some new input, has to be a
// replacement op
trafoStrat = ColaReplacement.getInstance();
+ //TODO this has not been implemented yet
+ throw new IllegalArgumentException("Replacement Handling not implemented yet! Known Bug.");
}
}
}

Back to the top