Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorisikm2008-06-15 19:59:36 +0000
committerisikm2008-06-15 19:59:36 +0000
commit42f103f7e29b1129225ddb84f00af698f07d2c0d (patch)
treedfc9e66b38ef05c294a2482c6b7ca89bcb2609e6
parent91873a69b84cfb925f34347ada22db532928eed2 (diff)
downloadorg.eclipse.ecf-42f103f7e29b1129225ddb84f00af698f07d2c0d.tar.gz
org.eclipse.ecf-42f103f7e29b1129225ddb84f00af698f07d2c0d.tar.xz
org.eclipse.ecf-42f103f7e29b1129225ddb84f00af698f07d2c0d.zip
work-in-progress on handling deletions vs. insertions and vice versa, remote insertion vs. local deletion seems fixed, will require more testing, last remaining item is remote deletion vs. local insertion - integrated mechanism for operations that need to be split in two as a result of an operational transform
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaDeletion.java83
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaInsertion.java30
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaSynchronizer.java15
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaUpdateMessage.java16
4 files changed, 75 insertions, 69 deletions
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaDeletion.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaDeletion.java
index b3fed71d6..6e7377353 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaDeletion.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaDeletion.java
@@ -38,7 +38,7 @@ public class ColaDeletion implements TransformationStrategy {
ColaUpdateMessage remoteTransformedMsg = remoteIncomingMsg;
- if (remoteTransformedMsg.isDeletion()) {
+ if (localAppliedMsg.isDeletion()) {
final int noOpLength = 0;
if (remoteTransformedMsg.getOffset() < localAppliedMsg.getOffset()) {
@@ -110,77 +110,28 @@ public class ColaDeletion implements TransformationStrategy {
localAppliedMsg.setLengthOfReplacedText(localAppliedMsg.getLengthOfReplacedText() - (localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfReplacedText()) - remoteTransformedMsg.getOffset());
}
}
- }
- //--------------------------
-
- /*if (localAppliedMsg.isInsertion()) {
- // something has been inserted at a lower or same index --> move
- // deletion right
- if (localAppliedMsg.getOffset() <= remoteTransformedMsg.getOffset()) {
- remoteTransformedMsg.setOffset(remoteTransformedMsg.getOffset() + localAppliedMsg.getText().length());
- }
- } else if (localAppliedMsg.isDeletion()) {
- if (remoteTransformedMsg.getOffset() > localAppliedMsg.getOffset()) {
- // move to remote deletion to the left
- // check for overlap
- if (remoteTransformedMsg.getOffset() < (localAppliedMsg.getOffset() + localAppliedMsg.getLength())) {
- // partial overlap on the right side of local op
- if ((remoteTransformedMsg.getOffset() + remoteTransformedMsg.getLength()) > (localAppliedMsg.getOffset() + localAppliedMsg.getLength())) {
- // the case that some part of the beginning of the
- // incoming
- // remote del lies within the already executed deletion
- // and extends beyond the already applied del
- // shorten the remote deletion, cut off the redundant
- // part
- // at the beginning of rem del
- remoteTransformedMsg.setLength(remoteTransformedMsg.getLength() - ((localAppliedMsg.getOffset() + localAppliedMsg.getLength()) - remoteTransformedMsg.getOffset()));
- // move shortened remote del offset to correct pos.
- remoteTransformedMsg.setOffset(localAppliedMsg.getOffset());
- } else { // full overlap, remote op fully contained
- // within local op
- // case remote deletion is fully within already applied
- // deletion, i.e. don't do anything
- remoteTransformedMsg.setLength(0); // TODO check
- remoteTransformedMsg.setOffset(0);// TODO check -
- // should resolve
- // nullpointerexc
- // whether this is
- // enough to make
- // this a no-op
- }
- } else { // no overlap
- // deletion is fully after the already applied deletion
- remoteTransformedMsg.setOffset(remoteTransformedMsg.getOffset() - localAppliedMsg.getLength());
- }
- // if incoming deletion is at a lower or equal index
- } else if (remoteTransformedMsg.getOffset() <= localAppliedMsg.getOffset()) {
- // check for overlap
- if ((remoteTransformedMsg.getOffset() + remoteIncomingMsg.getLength()) > localAppliedMsg.getOffset()) {
- // case remote op reaches into or even over the local op
- if ((remoteTransformedMsg.getOffset() + remoteIncomingMsg.getLength()) <= (localAppliedMsg.getOffset() + localAppliedMsg.getLength())) {
- // case remote op does not reach over local op, i.e.
- // shorten remote op by overlap
- remoteTransformedMsg.setLength(remoteTransformedMsg.getLength() - ((remoteIncomingMsg.getOffset() + remoteTransformedMsg.getLength()) - localAppliedMsg.getOffset()));// same
- // as
- // remoteOffset
- // - localOffset
- } else {
- // case remote op reaches over, i.e. cut out length of
- // local del-op
- remoteTransformedMsg.setLength(remoteTransformedMsg.getLength() - localAppliedMsg.getLength());
- }
-
+ } else if (localAppliedMsg.isInsertion()) {
+ if (remoteTransformedMsg.getOffset() < localAppliedMsg.getOffset()) {
+ if ((remoteTransformedMsg.getOffset() + remoteTransformedMsg.getLengthOfReplacedText()) < localAppliedMsg.getOffset()) {
+ //remote remains unchanged, deletion happens fully before local insertion
+ //local insertion needs to be moved left by full length of deletion
+ localAppliedMsg.setOffset(localAppliedMsg.getOffset() - remoteTransformedMsg.getLengthOfReplacedText());
+ } else if ((remoteTransformedMsg.getOffset() + remoteTransformedMsg.getLengthOfReplacedText()) >= localAppliedMsg.getOffset()) {
+ //remote deletion reaches into local insertion and potentially over it
+ //local insertion needs to be moved left by overlap
+ //remote deletion needs to be split apart
+ //TODO needs to be implemented and requires appropriate modification in ColaSynchronizer
+ throw new IllegalArgumentException("NOT IMPLEMENTED OPERATIONAL TRANSFORM");
}
- // no need to do anything if there is no overlap for del-op at
- // lower index vs. local del-op
+ } else if (remoteTransformedMsg.getOffset() >= localAppliedMsg.getOffset()) {
+ //remote del needs to be moved right by full length of insertion
+ remoteTransformedMsg.setOffset(remoteTransformedMsg.getOffset() + localAppliedMsg.getLengthOfInsertedText());
}
}
- remoteTransformedMsg.remoteOperationsCount += 1;
- localAppliedMsg.remoteOperationsCount += 1;*/
-
Trace.exiting(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_EXITING, this.getClass(), "getOperationalTransform", null); //$NON-NLS-1$
return remoteTransformedMsg;
}
+
}
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaInsertion.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaInsertion.java
index 4ecdaac7b..3bc53a055 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaInsertion.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaInsertion.java
@@ -12,6 +12,7 @@
package org.eclipse.ecf.docshare.cola;
import org.eclipse.ecf.core.util.Trace;
+import org.eclipse.ecf.docshare.messages.UpdateMessage;
import org.eclipse.ecf.internal.docshare.Activator;
import org.eclipse.ecf.internal.docshare.DocshareDebugOptions;
@@ -67,6 +68,35 @@ public class ColaInsertion implements TransformationStrategy {
//coopt(remote(high),local(low)) --> (remote(low + high),local(low))
remoteTransformedMsg.setOffset(remoteTransformedMsg.getOffset() + localAppliedMsg.getText().length());
}
+
+ } else if (localAppliedMsg.isDeletion()) {
+
+ if (remoteTransformedMsg.getOffset() <= localAppliedMsg.getOffset()) {
+
+ localAppliedMsg.setOffset(localAppliedMsg.getOffset() + remoteTransformedMsg.getLengthOfInsertedText());
+
+ } else if (remoteTransformedMsg.getOffset() > localAppliedMsg.getOffset()) {
+
+ if (remoteTransformedMsg.getOffset() > (localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfReplacedText())) {
+
+ remoteTransformedMsg.setOffset(remoteTransformedMsg.getOffset() - localAppliedMsg.getLengthOfReplacedText());
+ } else if (remoteTransformedMsg.getOffset() <= (localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfReplacedText())) {
+
+ //TODO test this ^#$%^#$ case
+ UpdateMessage deletionFirstMessage = new UpdateMessage(localAppliedMsg.getOffset(), remoteTransformedMsg.getOffset() - localAppliedMsg.getOffset(), localAppliedMsg.getText());
+ ColaUpdateMessage deletionFirstPart = new ColaUpdateMessage(deletionFirstMessage, localAppliedMsg.getLocalOperationsCount(), localAppliedMsg.getRemoteOperationsCount());
+ localAppliedMsg.addToSplitUpRepresentation(deletionFirstPart);
+
+ UpdateMessage deletionSecondMessage = new UpdateMessage(localAppliedMsg.getOffset() + remoteTransformedMsg.getLengthOfInsertedText(), localAppliedMsg.getLengthOfReplacedText() - deletionFirstPart.getLengthOfReplacedText(), localAppliedMsg.getText());
+ ColaUpdateMessage deletionSecondPart = new ColaUpdateMessage(deletionSecondMessage, localAppliedMsg.getLocalOperationsCount(), localAppliedMsg.getRemoteOperationsCount());
+ localAppliedMsg.addToSplitUpRepresentation(deletionSecondPart);
+
+ localAppliedMsg.setSplitUp(true);
+
+ remoteTransformedMsg.setOffset(localAppliedMsg.getOffset());
+
+ }
+ }
}
Trace.exiting(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_EXITING, this.getClass(), "getOperationalTransform", remoteTransformedMsg); //$NON-NLS-1$
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaSynchronizer.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaSynchronizer.java
index d72ccb625..187681f82 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaSynchronizer.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaSynchronizer.java
@@ -105,13 +105,22 @@ public class ColaSynchronizer implements SynchronizationStrategy {
if (!unacknowledgedLocalOperations.isEmpty()) {
ColaUpdateMessage localOp = (ColaUpdateMessage) unacknowledgedLocalOperations.getFirst();
Assert.isTrue(transformedRemote.getRemoteOperationsCount() == localOp.getLocalOperationsCount());
- for (final Iterator it = unacknowledgedLocalOperations.iterator(); it.hasNext();) {
+ 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);
- transformedRemote = transformedRemote.transformAgainst((ColaUpdateMessage) it.next(), 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());
+ }
+ listIt.next();//jump over both inserted operations that replaced the current unack op
+ }//end split up localop handling
}
}
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaUpdateMessage.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaUpdateMessage.java
index 543c9d4b5..22c9fe45b 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaUpdateMessage.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaUpdateMessage.java
@@ -11,6 +11,8 @@
package org.eclipse.ecf.docshare.cola;
+import java.util.LinkedList;
+import java.util.List;
import org.eclipse.ecf.core.util.Trace;
import org.eclipse.ecf.docshare.messages.UpdateMessage;
import org.eclipse.ecf.internal.docshare.Activator;
@@ -26,12 +28,14 @@ public class ColaUpdateMessage extends UpdateMessage {
private long remoteOperationsCount;
private final TransformationStrategy trafoStrat;
private boolean splitUp;
+ private List splitUpRepresentation;
public ColaUpdateMessage(UpdateMessage msg, long localOperationsCount, long remoteOperationsCount) {
super(msg.getOffset(), msg.getLengthOfReplacedText(), msg.getText());
this.localOperationsCount = localOperationsCount;
this.remoteOperationsCount = remoteOperationsCount;
this.splitUp = false;
+ this.splitUpRepresentation = new LinkedList();
if (super.getLengthOfReplacedText() == 0) {
// this is neither a replacement, nor a deletion
trafoStrat = ColaInsertion.getInstance();
@@ -87,4 +91,16 @@ public class ColaUpdateMessage extends UpdateMessage {
public boolean isSplitUp() {
return splitUp;
}
+
+ public void setSplitUpRepresentation(List splitUpRepresentation) {
+ this.splitUpRepresentation = splitUpRepresentation;
+ }
+
+ public List getSplitUpRepresentation() {
+ return splitUpRepresentation;
+ }
+
+ public void addToSplitUpRepresentation(ColaUpdateMessage splitUpRepresentationPart) {
+ this.splitUpRepresentation.add(splitUpRepresentationPart);
+ }
}

Back to the top