diff options
author | isikm | 2008-06-15 19:59:36 +0000 |
---|---|---|
committer | isikm | 2008-06-15 19:59:36 +0000 |
commit | 42f103f7e29b1129225ddb84f00af698f07d2c0d (patch) | |
tree | dfc9e66b38ef05c294a2482c6b7ca89bcb2609e6 | |
parent | 91873a69b84cfb925f34347ada22db532928eed2 (diff) | |
download | org.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
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); + } } |