Search in sources :

Example 1 with DocumentChangeMessage

use of org.eclipse.ecf.sync.doc.DocumentChangeMessage in project ecf by eclipse.

the class ColaInsertionTransformationStategy method getOperationalTransform.

/**
 * Resolves two conflicting <code>ColaDocumentChangeMessage</code>s by applying an appropriate operational transform.
 *
 * If necessary, modifies <code>localAppliedMsg</code> as well to reflect knowledge of <code>remoteIncomingMsg</code>
 * in case more conflicting/further diverging remote messages arrive.
 *
 * @param remoteIncomingMsg message originating from remote site, generated on same document state as <code>localAppliedMsg</code>
 * @param localAppliedMsg message already applied to local document, generation state corresponds to that of <code>remoteIncomingMsg</code>
 * @param localMsgHighPrio determines insertion preference for same offsets, if true localAppliedMsg comes first
 * @return operational transform of remote message, not conflicting with applied local message
 */
public ColaDocumentChangeMessage getOperationalTransform(ColaDocumentChangeMessage remoteIncomingMsg, ColaDocumentChangeMessage localAppliedMsg, boolean localMsgHighPrio) {
    // $NON-NLS-1$
    Trace.entering(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_ENTERING, this.getClass(), "getOperationalTransform", new Object[] { remoteIncomingMsg, localAppliedMsg, new Boolean(localMsgHighPrio) });
    final ColaDocumentChangeMessage remoteTransformedMsg = remoteIncomingMsg;
    if (localAppliedMsg.isInsertion()) {
        if (remoteTransformedMsg.getOffset() < localAppliedMsg.getOffset()) {
            // coopt(remote(low),local(high)) --> (remote(low),local(low + high))
            localAppliedMsg.setOffset(localAppliedMsg.getOffset() + remoteTransformedMsg.getOffset());
        } else if (remoteTransformedMsg.getOffset() == localAppliedMsg.getOffset()) {
            // coopt(remote(same),local(same))
            if (localMsgHighPrio) {
                // at owner --> (remote(high),local(same))
                remoteTransformedMsg.setOffset(remoteTransformedMsg.getOffset() + localAppliedMsg.getText().length());
            } else {
                // at participant --> (remote(same),local(high))
                localAppliedMsg.setOffset(localAppliedMsg.getOffset() + remoteTransformedMsg.getText().length());
            }
        } else if (remoteTransformedMsg.getOffset() > localAppliedMsg.getOffset()) {
            // 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
                final DocumentChangeMessage deletionFirstMessage = new DocumentChangeMessage(localAppliedMsg.getOffset(), remoteTransformedMsg.getOffset() - localAppliedMsg.getOffset(), localAppliedMsg.getText());
                final ColaDocumentChangeMessage deletionFirstPart = new ColaDocumentChangeMessage(deletionFirstMessage, localAppliedMsg.getLocalOperationsCount(), localAppliedMsg.getRemoteOperationsCount());
                localAppliedMsg.addToSplitUpRepresentation(deletionFirstPart);
                final DocumentChangeMessage deletionSecondMessage = new DocumentChangeMessage(localAppliedMsg.getOffset() + remoteTransformedMsg.getLengthOfInsertedText(), localAppliedMsg.getLengthOfReplacedText() - deletionFirstPart.getLengthOfReplacedText(), localAppliedMsg.getText());
                final ColaDocumentChangeMessage deletionSecondPart = new ColaDocumentChangeMessage(deletionSecondMessage, localAppliedMsg.getLocalOperationsCount(), localAppliedMsg.getRemoteOperationsCount());
                localAppliedMsg.addToSplitUpRepresentation(deletionSecondPart);
                localAppliedMsg.setSplitUp(true);
                remoteTransformedMsg.setOffset(localAppliedMsg.getOffset());
            }
        }
    }
    // $NON-NLS-1$
    Trace.exiting(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_EXITING, this.getClass(), "getOperationalTransform", remoteTransformedMsg);
    return remoteTransformedMsg;
}
Also used : DocumentChangeMessage(org.eclipse.ecf.sync.doc.DocumentChangeMessage)

Example 2 with DocumentChangeMessage

use of org.eclipse.ecf.sync.doc.DocumentChangeMessage in project ecf by eclipse.

the class ColaSynchronizationStrategy method registerLocalChange.

/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategy#registerLocalChange
	 * (org.eclipse.ecf.sync.doc.IModelChange)
	 */
public IModelChangeMessage[] registerLocalChange(IModelChange localChange) {
    List results = new ArrayList();
    Trace.entering(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_ENTERING, this.getClass(), "registerLocalChange", // $NON-NLS-1$
    localChange);
    if (localChange instanceof IDocumentChange) {
        final IDocumentChange docChange = (IDocumentChange) localChange;
        final ColaDocumentChangeMessage colaMsg = new ColaDocumentChangeMessage(new DocumentChangeMessage(docChange.getOffset(), docChange.getLengthOfReplacedText(), docChange.getText()), localOperationsCount, remoteOperationsCount);
        // to results
        if (!colaMsg.isReplacement()) {
            unacknowledgedLocalOperations.add(colaMsg);
            localOperationsCount++;
            results.add(colaMsg);
        } else {
            // It *is a replacement message, so we add both a delete and an
            // insert message
            // First create/add a delete message (text set to "")...
            ColaDocumentChangeMessage delMsg = new ColaDocumentChangeMessage(new DocumentChangeMessage(docChange.getOffset(), docChange.getLengthOfReplacedText(), ""), localOperationsCount, remoteOperationsCount);
            unacknowledgedLocalOperations.add(delMsg);
            localOperationsCount++;
            results.add(delMsg);
            // Then create/add the insert message (length set to 0)
            ColaDocumentChangeMessage insMsg = new ColaDocumentChangeMessage(new DocumentChangeMessage(docChange.getOffset(), 0, docChange.getText()), localOperationsCount, remoteOperationsCount);
            unacknowledgedLocalOperations.add(insMsg);
            localOperationsCount++;
            results.add(insMsg);
        }
        Trace.exiting(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_EXITING, this.getClass(), "registerLocalChange", // $NON-NLS-1$
        colaMsg);
    }
    return (IModelChangeMessage[]) results.toArray(new IModelChangeMessage[] {});
}
Also used : IDocumentChange(org.eclipse.ecf.sync.doc.IDocumentChange) DocumentChangeMessage(org.eclipse.ecf.sync.doc.DocumentChangeMessage)

Example 3 with DocumentChangeMessage

use of org.eclipse.ecf.sync.doc.DocumentChangeMessage in project ecf by eclipse.

the class ColaSynchronizationStrategy method transformRemoteChange.

/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategy#
	 * transformRemoteChange(org.eclipse.ecf.sync.doc.IModelChangeMessage)
	 */
public IModelChange[] transformRemoteChange(IModelChange remoteChange) {
    if (!(remoteChange instanceof DocumentChangeMessage))
        return new IDocumentChange[0];
    final DocumentChangeMessage m = (DocumentChangeMessage) remoteChange;
    final List l = this.transformIncomingMessage(m);
    return (IDocumentChange[]) l.toArray(new IDocumentChange[] {});
}
Also used : IDocumentChange(org.eclipse.ecf.sync.doc.IDocumentChange) DocumentChangeMessage(org.eclipse.ecf.sync.doc.DocumentChangeMessage)

Example 4 with DocumentChangeMessage

use of org.eclipse.ecf.sync.doc.DocumentChangeMessage in project ecf by eclipse.

the class Initiator method run.

public void run() {
    for (int i = 0; i < 10; i++) {
        String text = fDocument.get();
        String newText = ">";
        text = text.concat(newText);
        fDocument.set(text);
        IModelChange change = new DocumentChangeMessage(i + 150, newText.length(), newText);
        IModelChangeMessage[] changes = initiator.registerLocalChange(change);
        getReceiverQueue().put(changes);
    }
}
Also used : IModelChange(org.eclipse.ecf.sync.IModelChange) IModelChangeMessage(org.eclipse.ecf.sync.IModelChangeMessage) DocumentChangeMessage(org.eclipse.ecf.sync.doc.DocumentChangeMessage)

Example 5 with DocumentChangeMessage

use of org.eclipse.ecf.sync.doc.DocumentChangeMessage in project ecf by eclipse.

the class ColaDeletionTransformationStrategy method getOperationalTransform.

public ColaDocumentChangeMessage getOperationalTransform(ColaDocumentChangeMessage remoteIncomingMsg, ColaDocumentChangeMessage localAppliedMsg, boolean localMsgHighPrio) {
    // $NON-NLS-1$
    Trace.entering(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_ENTERING, this.getClass(), "getOperationalTransform", new Object[] { remoteIncomingMsg, localAppliedMsg, new Boolean(localMsgHighPrio) });
    final ColaDocumentChangeMessage remoteTransformedMsg = remoteIncomingMsg;
    if (localAppliedMsg.isDeletion()) {
        final int noOpLength = 0;
        if (remoteTransformedMsg.getOffset() < localAppliedMsg.getOffset()) {
            if ((remoteTransformedMsg.getOffset() + remoteTransformedMsg.getLengthOfReplacedText()) < localAppliedMsg.getOffset()) {
                // no overlap - remote OK as is, local needs modification
                localAppliedMsg.setOffset(localAppliedMsg.getOffset() - remoteTransformedMsg.getLengthOfReplacedText());
            } else if ((remoteTransformedMsg.getOffset() + remoteTransformedMsg.getLengthOfReplacedText()) < (localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfReplacedText())) {
                // remote del at lower index reaches into locally applied del, local del reaches further out
                // --> shorten remote del appropriately, move and shorten local del left
                remoteTransformedMsg.setLengthOfReplacedText((remoteTransformedMsg.getOffset() + remoteTransformedMsg.getLengthOfReplacedText()) - localAppliedMsg.getOffset());
                localAppliedMsg.setLengthOfReplacedText((remoteTransformedMsg.getOffset() + remoteTransformedMsg.getLengthOfReplacedText()) - localAppliedMsg.getOffset());
                // TODO verify!
                localAppliedMsg.setOffset(remoteTransformedMsg.getOffset());
            } else if ((remoteTransformedMsg.getOffset() + remoteTransformedMsg.getLengthOfReplacedText()) >= (localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfReplacedText())) {
                // remote del at lower index, remote del fully extends over local del
                // --> shorten remote by local.lengthOfReplacedText, make local no-op
                remoteTransformedMsg.setLengthOfReplacedText(remoteTransformedMsg.getLengthOfReplacedText() - localAppliedMsg.getLengthOfReplacedText());
                // TODO verify whether this is equivalent to setting no-op, otherwise declare a noop boolean field for ColaDeletions
                localAppliedMsg.setOffset(remoteTransformedMsg.getOffset());
                localAppliedMsg.setLengthOfReplacedText(noOpLength);
            }
        } else if (remoteTransformedMsg.getOffset() == localAppliedMsg.getOffset()) {
            if ((remoteTransformedMsg.getOffset() + remoteTransformedMsg.getLengthOfReplacedText()) < (localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfReplacedText())) {
                // start indices are equal, remote is shorter --> make remote no-op
                remoteTransformedMsg.setLengthOfReplacedText(noOpLength);
                // --> shorten localOp to only delete non-overlapping region
                localAppliedMsg.setLengthOfReplacedText(localAppliedMsg.getLengthOfReplacedText() - remoteTransformedMsg.getLengthOfReplacedText());
            } else if ((remoteTransformedMsg.getOffset() + remoteTransformedMsg.getLengthOfReplacedText()) == (localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfReplacedText())) {
                // same endIndex, i.e. same deletion
                // --> make remote op be no-op
                remoteTransformedMsg.setLengthOfReplacedText(noOpLength);
                // --> make local op appear as no-op
                localAppliedMsg.setLengthOfReplacedText(noOpLength);
            } else if ((remoteTransformedMsg.getOffset() + remoteTransformedMsg.getLengthOfReplacedText()) > (localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfReplacedText())) {
                // remote del extends over local del
                // -->shorten remote del by length of local del, index/offset does not need to be updated
                remoteTransformedMsg.setLengthOfReplacedText(remoteTransformedMsg.getLengthOfReplacedText() - localAppliedMsg.getLengthOfReplacedText());
                // -->make local del appear as no-op
                localAppliedMsg.setLengthOfReplacedText(noOpLength);
            }
        } else if (remoteTransformedMsg.getOffset() > localAppliedMsg.getOffset()) {
            if (remoteTransformedMsg.getOffset() > (localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfReplacedText())) {
                // move remote deletion left by length of local deletion
                remoteTransformedMsg.setOffset(remoteTransformedMsg.getOffset() - localAppliedMsg.getLengthOfReplacedText());
            } else if ((remoteTransformedMsg.getOffset() + remoteTransformedMsg.getLengthOfReplacedText()) < (localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfReplacedText())) {
                // remote is fully contained in/overlapping with local del
                // --> remote is no-op
                remoteTransformedMsg.setLengthOfReplacedText(noOpLength);
                // -->local needs to be shortened by length of remote
                localAppliedMsg.setLengthOfReplacedText(localAppliedMsg.getLengthOfReplacedText() - remoteTransformedMsg.getLengthOfReplacedText());
            } else if (remoteTransformedMsg.getOffset() < (localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfReplacedText())) {
                // remote del starts within local del, but extends further
                // -->shorten remote by overlap and move left to index of local del
                remoteTransformedMsg.setLengthOfReplacedText(remoteTransformedMsg.getLengthOfReplacedText() - (localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfReplacedText()) - remoteTransformedMsg.getOffset());
                remoteTransformedMsg.setOffset(localAppliedMsg.getOffset());
                // -->shorten local applied message
                localAppliedMsg.setLengthOfReplacedText(localAppliedMsg.getLengthOfReplacedText() - (localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfReplacedText()) - remoteTransformedMsg.getOffset());
            }
        }
    } 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()) {
                // TODO optimize away, "if" just here for clarity, "else" would be enough
                // remote deletion reaches into local insertion and potentially over it
                // remote deletion needs to be split apart
                final DocumentChangeMessage deletionFirstMsg = new DocumentChangeMessage(remoteTransformedMsg.getOffset(), localAppliedMsg.getOffset() - remoteTransformedMsg.getOffset(), remoteTransformedMsg.getText());
                final ColaDocumentChangeMessage deletionFirstPart = new ColaDocumentChangeMessage(deletionFirstMsg, remoteTransformedMsg.getLocalOperationsCount(), remoteTransformedMsg.getRemoteOperationsCount());
                remoteTransformedMsg.addToSplitUpRepresentation(deletionFirstPart);
                final DocumentChangeMessage deletionSecondMsg = new DocumentChangeMessage(localAppliedMsg.getOffset() + localAppliedMsg.getLengthOfInsertedText(), remoteTransformedMsg.getLengthOfReplacedText() - deletionFirstPart.getLengthOfReplacedText(), remoteTransformedMsg.getText());
                final ColaDocumentChangeMessage deletionSecondPart = new ColaDocumentChangeMessage(deletionSecondMsg, remoteTransformedMsg.getLocalOperationsCount(), remoteTransformedMsg.getRemoteOperationsCount());
                remoteTransformedMsg.addToSplitUpRepresentation(deletionSecondPart);
                remoteTransformedMsg.setSplitUp(true);
                // local insertion needs to be moved left by overlap
                localAppliedMsg.setOffset(remoteTransformedMsg.getOffset());
            }
        } else if (remoteTransformedMsg.getOffset() >= localAppliedMsg.getOffset()) {
            // remote del needs to be moved right by full length of insertion
            remoteTransformedMsg.setOffset(remoteTransformedMsg.getOffset() + localAppliedMsg.getLengthOfInsertedText());
        }
    }
    // $NON-NLS-1$
    Trace.exiting(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_EXITING, this.getClass(), "getOperationalTransform", null);
    return remoteTransformedMsg;
}
Also used : DocumentChangeMessage(org.eclipse.ecf.sync.doc.DocumentChangeMessage)

Aggregations

DocumentChangeMessage (org.eclipse.ecf.sync.doc.DocumentChangeMessage)5 IDocumentChange (org.eclipse.ecf.sync.doc.IDocumentChange)2 IModelChange (org.eclipse.ecf.sync.IModelChange)1 IModelChangeMessage (org.eclipse.ecf.sync.IModelChangeMessage)1