Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorslewis2008-06-12 04:48:33 +0000
committerslewis2008-06-12 04:48:33 +0000
commit23288f5a4c654ec841cab11b5a17eff9deca4c5b (patch)
tree00a6de5bc6a39b8f31aa415aac1b30516b3b201e
parentad7e97c8fab8d7e44334da9d194d4726bd73ab9d (diff)
downloadorg.eclipse.ecf-23288f5a4c654ec841cab11b5a17eff9deca4c5b.tar.gz
org.eclipse.ecf-23288f5a4c654ec841cab11b5a17eff9deca4c5b.tar.xz
org.eclipse.ecf-23288f5a4c654ec841cab11b5a17eff9deca4c5b.zip
Checkins from Mustafa Isik to address https://bugs.eclipse.org/bugs/show_bug.cgi?id=207530
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/.options16
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/about.html2
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/plugin.properties18
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/plugin.xml14
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/DocShare.java186
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/IdentityMapping.java7
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/SynchronizationStrategy.java2
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaDeletion.java101
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaInsertion.java86
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaReplacement.java29
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaSynchronizer.java97
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaUpdateMessage.java63
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/TransformationStrategy.java9
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/menu/DocShareRosterMenuContributionItem.java49
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/messages/UpdateMessage.java31
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/Activator.java12
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/DocshareDebugOptions.java23
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/ECFStart.java47
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/Messages.java3
-rw-r--r--framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/messages.properties13
20 files changed, 529 insertions, 279 deletions
diff --git a/framework/bundles/org.eclipse.ecf.docshare/.options b/framework/bundles/org.eclipse.ecf.docshare/.options
new file mode 100644
index 000000000..e96177b5a
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.docshare/.options
@@ -0,0 +1,16 @@
+# Debugging options for the org.eclipse.ecf.docshare plug-in
+
+# Turn on general debugging for the org.eclipse.ecf.docshare plug-in
+org.eclipse.ecf.docshare/debug=true
+org.eclipse.ecf.docshare/debug/filter = *
+org.eclipse.ecf.docshare/debug/flag = true
+
+# Trace when exceptions are caught
+org.eclipse.ecf.docshare/debug/exceptions/catching=false
+# Trace when exceptions are thrown
+org.eclipse.ecf.docshare/debug/exceptions/throwing=false
+
+# Trace when methods are entered
+org.eclipse.ecf.docshare/debug/methods/entering=false
+# Trace when methods are exited
+org.eclipse.ecf.docshare/debug/methods/exiting=false
diff --git a/framework/bundles/org.eclipse.ecf.docshare/about.html b/framework/bundles/org.eclipse.ecf.docshare/about.html
index 4c79781a5..6a60a262f 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/about.html
+++ b/framework/bundles/org.eclipse.ecf.docshare/about.html
@@ -8,7 +8,7 @@
<body lang="EN-US">
<h2>About This Content</h2>
-<p>June 25, 2008</p>
+<p>June 29, 2007</p>
<h3>License</h3>
<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
diff --git a/framework/bundles/org.eclipse.ecf.docshare/plugin.properties b/framework/bundles/org.eclipse.ecf.docshare/plugin.properties
index 6ff3fa21d..918864ace 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/plugin.properties
+++ b/framework/bundles/org.eclipse.ecf.docshare/plugin.properties
@@ -1,10 +1,10 @@
-############################################################################
-# Copyright (c) 2007 Composent Inc., IBM Corp. and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Eclipse Public License v1.0
-# which accompanies this distribution, and is available at
-# http://www.eclipse.org/legal/epl-v10.html
-#
-############################################################################
+/****************************************************************************
+* Copyright (c) 2007 Composent Inc., IBM Corp. and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*
+*****************************************************************************/
plugin.provider = Eclipse.org
-plugin.name = ECF DocShare Plugin
+plugin.name = ECF DocShare Plugin \ No newline at end of file
diff --git a/framework/bundles/org.eclipse.ecf.docshare/plugin.xml b/framework/bundles/org.eclipse.ecf.docshare/plugin.xml
index e55d1d234..c5cacf536 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/plugin.xml
+++ b/framework/bundles/org.eclipse.ecf.docshare/plugin.xml
@@ -13,7 +13,7 @@
locationURI="popup:#CompilationUnitEditorContext">
<dynamic
class="org.eclipse.ecf.docshare.menu.DocShareRosterMenuContributionItem"
- id="org.eclipse.ecf.docshare.compilationuniteditorcontribution">
+ id="org.eclipse.ecf.editorshare.dynamic1">
</dynamic>
</menuContribution>
</extension>
@@ -24,20 +24,10 @@
locationURI="popup:#TextEditorContext">
<dynamic
class="org.eclipse.ecf.docshare.menu.DocShareRosterMenuContributionItem"
- id="org.eclipse.ecf.docshare.texteditorcontribution">
+ id="org.eclipse.ecf.editorshare.dynamic2">
</dynamic>
</menuContribution>
</extension>
- <extension
- point="org.eclipse.ui.menus">
- <menuContribution
- locationURI="popup:org.eclipse.wst.sse.ui.StructuredTextEditor.EditorContext?after=additions">
- <dynamic
- class="org.eclipse.ecf.docshare.menu.DocShareRosterMenuContributionItem"
- id="org.eclipse.ecf.editorshare.structuredtexteditorcontribution">
- </dynamic>
- </menuContribution>
- </extension>
</plugin>
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/DocShare.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/DocShare.java
index f615471c3..b21f7e26d 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/DocShare.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/DocShare.java
@@ -19,16 +19,15 @@ import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.Assert;
import org.eclipse.ecf.core.identity.ID;
import org.eclipse.ecf.core.util.ECFException;
+import org.eclipse.ecf.core.util.Trace;
import org.eclipse.ecf.datashare.AbstractShare;
import org.eclipse.ecf.datashare.IChannelContainerAdapter;
import org.eclipse.ecf.datashare.events.IChannelDisconnectEvent;
+import org.eclipse.ecf.docshare.cola.ColaSynchronizer;
import org.eclipse.ecf.docshare.messages.*;
-import org.eclipse.ecf.internal.docshare.Activator;
-import org.eclipse.ecf.internal.docshare.Messages;
+import org.eclipse.ecf.internal.docshare.*;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.*;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.widgets.Control;
@@ -42,7 +41,7 @@ import org.eclipse.ui.texteditor.ITextEditor;
* Represents a document sharing session between two participants.
*/
/**
- *
+ *
*/
public class DocShare extends AbstractShare {
@@ -51,7 +50,7 @@ public class DocShare extends AbstractShare {
*/
ID initiatorID;
/**
- * The ID of the receiver.
+ * The ID of the receiver.
*/
ID receiverID;
/**
@@ -63,26 +62,36 @@ public class DocShare extends AbstractShare {
*/
ITextEditor editor;
/**
- * Content that we have received via start message, before user has responded
- * to question about whether or not to display in editor. Should be null
- * at all other times.
+ * Content that we have received via start message, before user has
+ * responded to question about whether or not to display in editor. Should
+ * be null at all other times.
*/
String startContent = null;
/**
- * Object to use as lock for changing connected state of this docshare instance
+ * Object to use as lock for changing connected state of this docshare
+ * instance
*/
Object stateLock = new Object();
/**
- * The document listener is the listener for changes to the *local* copy of the
- * IDocument. This listener is responsible for sending document update messages when
- * notified.
+ * Strategy for maintaining consistency among session participants'
+ * documents.
+ */
+ // TODO provide for a user-interactive selection mechanism
+ SynchronizationStrategy sync;
+
+ /**
+ * The document listener is the listener for changes to the *local* copy of
+ * the IDocument. This listener is responsible for sending document update
+ * messages when notified.
*/
IDocumentListener documentListener = new IDocumentListener() {
+
public void documentAboutToBeChanged(DocumentEvent event) {
// nothing to do
}
+ // handling of LOCAL OPERATION application
public void documentChanged(DocumentEvent event) {
// If the channel is gone, then no reason to handle this.
if (getChannel() == null || !Activator.getDefault().isListenerActive()) {
@@ -90,20 +99,26 @@ public class DocShare extends AbstractShare {
}
// If the listener is not active, ignore input
if (!Activator.getDefault().isListenerActive()) {
- //The local editor is being updated by an remote peer, so we do not
- //wish to echo this change.
+ // The local editor is being updated by a remote peer, so we do
+ // not
+ // wish to echo this change.
return;
}
- // Otherwise end update message
- sendUpdateMessage(event);
+ Trace.trace(Activator.PLUGIN_ID, NLS.bind("{0}.documentChanged[{1}]", DocShare.this, event)); //$NON-NLS-1$
+ UpdateMessage msg = new UpdateMessage(event.getOffset(), event.getLength(), event.getText());
+ UpdateMessage colaMsg = sync.registerOutgoingMessage(msg);
+ sendUpdateMsg(colaMsg);
}
};
/**
* Create a document sharing session instance.
*
- * @param adapter the {@link IChannelContainerAdapter} to use to create this document sharing session.
- * @throws ECFException if the channel cannot be created.
+ * @param adapter
+ * the {@link IChannelContainerAdapter} to use to create this
+ * document sharing session.
+ * @throws ECFException
+ * if the channel cannot be created.
*/
public DocShare(IChannelContainerAdapter adapter) throws ECFException {
super(adapter);
@@ -148,17 +163,23 @@ public class DocShare extends AbstractShare {
}
/**
- * Start sharing an editor's contents between two participants. This will send a request to start sharing
- * with the target identified by the <code>toID</code> parameter. The remote receiver will be displayed a
- * message dialog, and given the option to start editor sharing, or not.
+ * Start sharing an editor's contents between two participants. This will
+ * send a request to start sharing with the target identified by the
+ * <code>toID</code> parameter. The remote receiver will be displayed a
+ * message dialog, and given the option to start editor sharing, or not.
*
- * @param our the ID associated with the initiator. Must not be <code>null</code>.
- * @param fromName a name to present to the receiver. If <code>null, our.getName() will be used.
+ * @param our
+ * the ID associated with the initiator. Must not be
+ * <code>null</code>.
+ * @param fromName
+ * a name to present to the receiver. If
+ * <code>null, our.getName() will be used.
* @param toID the ID of the intended receiver. Must not be <code>null</code>.
* @param fileName the file name of the file to be shared (with suffix type extension). Must not be <code>null</code>.
* @param editorPart the text editor currently showing the contents of this editor. Must not be <code>null</code>.
*/
public void startShare(final ID our, final String fromName, final ID toID, final String fileName, final ITextEditor editorPart) {
+ Trace.entering(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_ENTERING, DocShare.class, "startShare", new Object[] {our, fromName, toID, fileName, editorPart}); //$NON-NLS-1$
Assert.isNotNull(our);
final String fName = (fromName == null) ? our.getName() : fromName;
Assert.isNotNull(toID);
@@ -179,53 +200,32 @@ public class DocShare extends AbstractShare {
}
}
});
+ Trace.exiting(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_ENTERING, DocShare.class, "startShare"); //$NON-NLS-1$
}
/**
- * Stop editor sharing. Message only sent if we are currently engaged in an editor sharing session
- * ({@link #isSharing()} returns <code>true</code>.
+ * Stop editor sharing. Message only sent if we are currently engaged in an
+ * editor sharing session ({@link #isSharing()} returns <code>true</code>.
*/
public void stopShare() {
+ Trace.entering(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_ENTERING, this.getClass(), "stopShare"); //$NON-NLS-1$
if (isSharing()) {
// send stop message to other
sendStopMessage();
}
localStopShare();
- }
-
- public void sendSelection() {
- ITextEditor textEditor = getTextEditor();
- if (textEditor != null) {
- ISelectionProvider selectionProvider = textEditor.getSelectionProvider();
- ISelection selection = selectionProvider.getSelection();
- if (selection instanceof ITextSelection) {
- ITextSelection textSelection = (ITextSelection) selection;
- try {
- send(getOtherID(), new SelectionMessage(textSelection.getOffset(), textSelection.getLength(), textSelection.getStartLine(), textSelection.getEndLine()));
- } catch (Exception e) {
- logError(Messages.DocShare_SELECTION_SEND_ERROR_TITLE, e);
- showErrorToUser(Messages.DocShare_SELECTION_SEND_ERROR_TITLE, Messages.DocShare_SELECTION_SEND_ERROR_MESSAGE);
- }
- }
- }
- }
-
- protected void handleSelectionMessage(final SelectionMessage selectionMessage) {
- Display.getDefault().syncExec(new Runnable() {
- public void run() {
- ITextEditor textEditor = getTextEditor();
- if (textEditor != null)
- textEditor.selectAndReveal(selectionMessage.getOffset(), selectionMessage.getLength());
- }
- });
+ Trace.exiting(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_EXITING, this.getClass(), "stopShare"); //$NON-NLS-1$
}
void send(ID toID, Message message) throws Exception {
super.sendMessage(toID, message.serialize());
}
- /* (non-Javadoc)
- * @see org.eclipse.ecf.datashare.AbstractShare#handleMessage(org.eclipse.ecf.core.identity.ID, byte[])
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ecf.datashare.AbstractShare#handleMessage(org.eclipse.ecf.core.identity.ID,
+ * byte[])
*/
protected void handleMessage(ID fromContainerID, byte[] data) {
try {
@@ -237,8 +237,6 @@ public class DocShare extends AbstractShare {
handleUpdateMessage((UpdateMessage) message);
} else if (message instanceof StopMessage) {
handleStopMessage((StopMessage) message);
- } else if (message instanceof SelectionMessage) {
- handleSelectionMessage((SelectionMessage) message);
} else {
throw new InvalidObjectException(NLS.bind(Messages.DocShare_EXCEPTION_INVALID_MESSAGE, message.getClass().getName()));
}
@@ -248,9 +246,12 @@ public class DocShare extends AbstractShare {
}
/**
- * This method called by the {@link #handleMessage(ID, byte[])} method if the type of the message received is a start message (sent
- * by remote party via {@link #startShare(ID, String, ID, String, ITextEditor)}.
- * @param message the UpdateMessage received.
+ * This method called by the {@link #handleMessage(ID, byte[])} method if
+ * the type of the message received is a start message (sent by remote party
+ * via {@link #startShare(ID, String, ID, String, ITextEditor)}.
+ *
+ * @param message
+ * the UpdateMessage received.
*/
protected void handleStartMessage(final StartMessage message) {
final ID senderID = message.getSenderID();
@@ -271,7 +272,8 @@ public class DocShare extends AbstractShare {
// And we're done
return;
}
- // Otherwise set start content to the message-provided documentContent
+ // Otherwise set start content to the message-provided
+ // documentContent
startContent = documentContent;
}
// Then open UI and show text editor if appropriate
@@ -308,20 +310,19 @@ public class DocShare extends AbstractShare {
}
/**
- * This method called by the {@link #handleMessage(ID, byte[])} method if the type of the message received is an update message.
- * @param message the UpdateMessage received.
+ * This method called by the {@link #handleMessage(ID, byte[])} method if
+ * the type of the message received is an update message.
+ *
+ * @param remoteMsg
+ * the UpdateMessage received.
*/
- protected void handleUpdateMessage(final UpdateMessage message) {
- final int offset = message.getOffset();
- Assert.isTrue(offset > -1);
- final int length = message.getLength();
- Assert.isTrue(length > -1);
- final String text = message.getText();
- Assert.isTrue(text != null);
+ protected void handleUpdateMessage(final UpdateMessage remoteMsg) {
synchronized (stateLock) {
- // If we're waiting on user to start then change the startContent directly
+ // If we're waiting on user to start then change the
+ // startContent
+ // directly
if (startContent != null) {
- modifyStartContent(offset, length, text);
+ modifyStartContent(remoteMsg.getOffset(), remoteMsg.getLength(), remoteMsg.getText());
// And we're done
return;
}
@@ -330,11 +331,22 @@ public class DocShare extends AbstractShare {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
try {
+ Trace.entering(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_ENTERING, this.getClass(), "handleUpdateMessage", remoteMsg); //$NON-NLS-1$
final IDocument document = getDocumentFromEditor();
+
if (document != null) {
- // We setup editor to not take input while we are changing document
+ // transparent concurrency/sync'ing algorithm delegation
+ // 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);
+
+ // if (localState.equalsIgnoreCase(remoteState)) {
+ // We setup editor to not take input while we are
+ // changing document
setEditorToRefuseInput();
- document.replace(offset, length, text);
+
+ document.replace(msgForLocalApplication.getOffset(), msgForLocalApplication.getLength(), msgForLocalApplication.getText());
}
} catch (final Exception e) {
logError(Messages.DocShare_EXCEPTION_RECEIVING_MESSAGE_TITLE, e);
@@ -342,6 +354,7 @@ public class DocShare extends AbstractShare {
} finally {
// Have editor accept input
setEditorToAcceptInput();
+ Trace.exiting(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_EXITING, this.getClass(), "handleUpdateMessage"); //$NON-NLS-1$
}
}
});
@@ -391,7 +404,9 @@ public class DocShare extends AbstractShare {
return fileStore;
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see org.eclipse.ecf.datashare.AbstractShare#dispose()
*/
public synchronized void dispose() {
@@ -408,6 +423,7 @@ public class DocShare extends AbstractShare {
}
void logError(String exceptionString, Throwable e) {
+ Trace.catching(Activator.PLUGIN_ID, DocshareDebugOptions.EXCEPTIONS_CATCHING, this.getClass(), exceptionString, e);
Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, exceptionString, e));
}
@@ -461,6 +477,11 @@ public class DocShare extends AbstractShare {
if (doc != null)
doc.addDocumentListener(documentListener);
}
+ // used to have the ColaSynchronizer.getInstanceFor(...) call here ...
+ // TODO needs to be moved to a more appropriate spot, where ColaSynch'er
+ // does not blow up
+ // sync = IdentityMapping.getInstance();
+ sync = ColaSynchronizer.getInstanceFor(this);
}
void localStopShare() {
@@ -474,12 +495,16 @@ public class DocShare extends AbstractShare {
doc.removeDocumentListener(documentListener);
this.editor = null;
}
+ // clean up if necessary
+ // TODO abstract this to work for SynchronizationStrategy
+ ColaSynchronizer.cleanUpFor(this);
+ sync = null;
}
- void sendUpdateMessage(DocumentEvent event) {
+ void sendUpdateMsg(UpdateMessage msg) {
if (isSharing()) {
try {
- send(getOtherID(), new UpdateMessage(event.getOffset(), event.getLength(), event.getText()));
+ send(getOtherID(), msg);
} catch (final Exception e) {
logError(Messages.DocShare_EXCEPTION_SEND_MESSAGE, e);
}
@@ -500,4 +525,11 @@ public class DocShare extends AbstractShare {
}
}
+ public String toString() {
+ StringBuffer buf = new StringBuffer("DocShare["); //$NON-NLS-1$
+ buf.append("ourID=").append(ourID).append(";initiatorID=").append(initiatorID).append(";receiverID=").append(receiverID); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ buf.append(";strategy=").append(sync).append("]"); //$NON-NLS-1$ //$NON-NLS-2$
+ return buf.toString();
+ }
+
}
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/IdentityMapping.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/IdentityMapping.java
index e8f643456..771a2e4d8 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/IdentityMapping.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/IdentityMapping.java
@@ -6,7 +6,7 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Mustafa K. Isik - conflict resolution via operational transformations
+ * Mustafa K. Isik - initial API and implementation
*****************************************************************************/
package org.eclipse.ecf.docshare;
@@ -32,4 +32,9 @@ public class IdentityMapping implements SynchronizationStrategy {
return remoteMsg;
}
+ public String toString() {
+ StringBuffer buf = new StringBuffer("IdentityMapping[]"); //$NON-NLS-1$
+ return buf.toString();
+ }
+
}
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/SynchronizationStrategy.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/SynchronizationStrategy.java
index 4cd9b20fe..4252af871 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/SynchronizationStrategy.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/SynchronizationStrategy.java
@@ -6,7 +6,7 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Mustafa K. Isik - conflict resolution via operational transformations
+ * Mustafa K. Isik - initial API and implementation
*****************************************************************************/
package org.eclipse.ecf.docshare;
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 d8e3df9a6..bd331b880 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
@@ -6,21 +6,108 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Mustafa K. Isik - conflict resolution via operational transformations
+ * Mustafa K. Isik - initial API and implementation
*****************************************************************************/
package org.eclipse.ecf.docshare.cola;
+import org.eclipse.ecf.core.util.Trace;
+import org.eclipse.ecf.internal.docshare.Activator;
+import org.eclipse.ecf.internal.docshare.DocshareDebugOptions;
+
public class ColaDeletion implements TransformationStrategy {
- public ColaUpdateMessage getForOwner(ColaUpdateMessage toBeTransformed, ColaUpdateMessage alreadyApplied) {
- // TODO Auto-generated method stub
- return null;
+ private static final long serialVersionUID = -7430435392915553959L;
+ private static ColaDeletion INSTANCE;
+
+ private ColaDeletion() {
+ // default constructor is private to enforce singleton property via
+ // static factory method
}
- public ColaUpdateMessage getForParticipant(ColaUpdateMessage toBeTransformed, ColaUpdateMessage alreadyApplied) {
- // TODO Auto-generated method stub
- return null;
+ public static TransformationStrategy getInstance() {
+ if (INSTANCE == null) {
+ INSTANCE = new ColaDeletion();
+ }
+ return INSTANCE;
}
+ public ColaUpdateMessage getOperationalTransform(ColaUpdateMessage remoteIncomingMsg, ColaUpdateMessage localAppliedMsg, boolean localMsgHighPrio) {
+
+ Trace.entering(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_ENTERING, this.getClass(), "getOperationalTransform", new Object[] {remoteIncomingMsg, localAppliedMsg, new Boolean(localMsgHighPrio)}); //$NON-NLS-1$
+
+ // this transformation handles an incoming remote deletion that has to
+ // be transformed against a locally operation
+ ColaUpdateMessage remoteTransformedMsg = remoteIncomingMsg;
+
+ 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());
+ }
+
+ }
+ // no need to do anything if there is no overlap for del-op at
+ // lower index vs. local del-op
+ }
+ }
+
+ remoteTransformedMsg.remoteOperationsCount += 1;
+ localAppliedMsg.remoteOperationsCount += 1;
+
+ Trace.exiting(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_EXITING, this.getClass(), "getOperationalTransform", null); //$NON-NLS-1$
+
+ return null;
+ }
}
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 a5c135072..5dedd0e80 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
@@ -6,26 +6,88 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Mustafa K. Isik - conflict resolution via operational transformations
+ * Mustafa K. Isik - initial API and implementation
*****************************************************************************/
package org.eclipse.ecf.docshare.cola;
+import org.eclipse.ecf.core.util.Trace;
+import org.eclipse.ecf.internal.docshare.Activator;
+import org.eclipse.ecf.internal.docshare.DocshareDebugOptions;
+
public class ColaInsertion implements TransformationStrategy {
- public ColaUpdateMessage getForOwner(ColaUpdateMessage toBeTransformed, ColaUpdateMessage alreadyApplied) {
- // i.e. this strategy belongs to an operation/msg coming from a
- // participant-->lesser prio
- // remote is to be properly transformed
- if (toBeTransformed.getOffset() > alreadyApplied.getOffset() && toBeTransformed.getOffset() < (alreadyApplied.getOffset() + alreadyApplied.getText().length())) {
- // the modification
- }
- return null;
+ private static final long serialVersionUID = 5192625383622519749L;
+ private static ColaInsertion INSTANCE;
+
+ private ColaInsertion() {
+ // default constructor is private to enforce singleton property via
+ // static factory method
}
- public ColaUpdateMessage getForParticipant(ColaUpdateMessage toBeTransformed, ColaUpdateMessage alreadyApplied) {
- // TODO Auto-generated method stub
- return null;
+ public static TransformationStrategy getInstance() {
+ if (INSTANCE == null) {
+ INSTANCE = new ColaInsertion();
+ }
+ return INSTANCE;
}
+ public ColaUpdateMessage getOperationalTransform(ColaUpdateMessage remoteIncomingMsg, ColaUpdateMessage localAppliedMsg, boolean localMsgHighPrio) {
+
+ Trace.entering(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_ENTERING, this.getClass(), "getOperationalTransform", new Object[] {remoteIncomingMsg, localAppliedMsg, new Boolean(localMsgHighPrio)}); //$NON-NLS-1$
+
+ ColaUpdateMessage remoteTransformedMsg = remoteIncomingMsg;
+
+ if (localAppliedMsg.isInsertion()) {
+ // check for full on collision - this is comparable to equal
+ // insertion
+ // pos. with single chars
+ if ((remoteTransformedMsg.getOffset() >= localAppliedMsg.getOffset()) && (remoteTransformedMsg.getOffset() < (localAppliedMsg.getOffset() + localAppliedMsg.getText().length()))) {
+ // determine what to modify and how
+
+ if (localMsgHighPrio) {
+
+ int localMsgEndIndex = localAppliedMsg.getOffset() + localAppliedMsg.getText().length();
+ remoteTransformedMsg.setOffset(localMsgEndIndex);
+
+ } else {
+ // localMsg if of lesser prio
+ // update both operations accordingly
+
+ remoteTransformedMsg.setOffset(localAppliedMsg.getOffset());
+
+ // TODO is this necessary? I think so ...
+ /*
+ * appliedLocalMsg.setOffset(appliedLocalMsg.getOffset() +
+ * transformedRemote.getText().length());
+ */
+ }
+
+ } else if (remoteTransformedMsg.getOffset() < localAppliedMsg.getOffset()) {
+
+ /*
+ * appliedLocalMsg.setOffset(appliedLocalMsg.getOffset() +
+ * transformedRemote.getText().length());
+ */
+
+ } else if (remoteTransformedMsg.getOffset() > localAppliedMsg.getOffset()) {
+
+ remoteTransformedMsg.setOffset(remoteTransformedMsg.getOffset() + localAppliedMsg.getText().length());
+ }
+ } else if (localAppliedMsg.isDeletion()) {
+ // TODO determine which cases are interesting to a remote insertion
+ // when running into a local, already applied deletion:
+ // the following seems to be the only case of relevance here
+ if (localAppliedMsg.getOffset() < remoteTransformedMsg.getOffset()) {
+ // move remote insertion to the left
+ remoteTransformedMsg.setOffset(remoteTransformedMsg.getOffset() - localAppliedMsg.getLength());
+ }
+ }
+
+ remoteTransformedMsg.remoteOperationsCount += 1;
+ localAppliedMsg.remoteOperationsCount += 1;
+
+ Trace.exiting(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_EXITING, this.getClass(), "getOperationalTransform", remoteTransformedMsg); //$NON-NLS-1$
+ return remoteTransformedMsg;
+ }
}
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaReplacement.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaReplacement.java
index fe5c47a1e..13f48de2f 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaReplacement.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/ColaReplacement.java
@@ -6,20 +6,39 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Mustafa K. Isik - conflict resolution via operational transformations
+ * Mustafa K. Isik - initial API and implementation
*****************************************************************************/
package org.eclipse.ecf.docshare.cola;
+import org.eclipse.ecf.core.util.Trace;
+import org.eclipse.ecf.internal.docshare.Activator;
+import org.eclipse.ecf.internal.docshare.DocshareDebugOptions;
+
public class ColaReplacement implements TransformationStrategy {
- public ColaUpdateMessage getForOwner(ColaUpdateMessage toBeTransformed, ColaUpdateMessage alreadyApplied) {
- // TODO Auto-generated method stub
- return null;
+ private static final long serialVersionUID = -7295023855308474804L;
+ private static ColaReplacement INSTANCE;
+
+ private ColaReplacement() {
+ // default constructor is private to enforce singleton property via
+ // static factory method
}
- public ColaUpdateMessage getForParticipant(ColaUpdateMessage toBeTransformed, ColaUpdateMessage alreadyApplied) {
+ public static TransformationStrategy getInstance() {
+ if (INSTANCE == null) {
+ INSTANCE = new ColaReplacement();
+ }
+ return INSTANCE;
+ }
+
+ public ColaUpdateMessage getOperationalTransform(ColaUpdateMessage remoteMsg, ColaUpdateMessage appliedLocalMsg, boolean localMsgHighPrio) {
+ Trace.entering(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_ENTERING, this.getClass(), "getOperationalTransform", new Object[] {remoteMsg, appliedLocalMsg, new Boolean(localMsgHighPrio)}); //$NON-NLS-1$
+
// TODO Auto-generated method stub
+
+ Trace.exiting(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_EXITING, this.getClass(), "getOperationalTransform", null); //$NON-NLS-1$
+
return null;
}
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 29ab8963c..bf3239860 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
@@ -6,99 +6,122 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Mustafa K. Isik - conflict resolution via operational transformations
+ * Mustafa K. Isik - initial API and implementation
*****************************************************************************/
package org.eclipse.ecf.docshare.cola;
import java.util.*;
-import org.eclipse.ecf.core.identity.ID;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.ecf.core.util.Trace;
+import org.eclipse.ecf.docshare.DocShare;
import org.eclipse.ecf.docshare.SynchronizationStrategy;
import org.eclipse.ecf.docshare.messages.UpdateMessage;
import org.eclipse.ecf.internal.docshare.Activator;
+import org.eclipse.ecf.internal.docshare.DocshareDebugOptions;
+import org.eclipse.osgi.util.NLS;
public class ColaSynchronizer implements SynchronizationStrategy {
- private List unacknowledgedLocalOperations;
+ // <ColaUpdateMessage>
+ private final LinkedList unacknowledgedLocalOperations;
private final boolean isInitiator;
- private double localOperationsCount;
- private double remoteOperationsCount;
+ private long localOperationsCount;
+ private long remoteOperationsCount;
+ // <DocShare, ColaSynchronizer>
private static Map sessionStrategies = new HashMap();
- private ColaSynchronizer(ID docshareID) {
- this.isInitiator = Activator.getDefault().getDocShare(docshareID).isInitiator();
+ private ColaSynchronizer(DocShare docshare) {
+ this.isInitiator = docshare.isInitiator();
unacknowledgedLocalOperations = new LinkedList();
localOperationsCount = 0;
remoteOperationsCount = 0;
}
- public static ColaSynchronizer getInstanceFor(ID docshareID) {
- if (sessionStrategies.get(docshareID) == null) {
- sessionStrategies.put(docshareID, new ColaSynchronizer(docshareID));
+ public static ColaSynchronizer getInstanceFor(DocShare docshare) {
+ if (sessionStrategies.get(docshare) == null) {
+ sessionStrategies.put(docshare, new ColaSynchronizer(docshare));
}
- return (ColaSynchronizer) sessionStrategies.get(docshareID);
+ return (ColaSynchronizer) sessionStrategies.get(docshare);
}
- public static void cleanUpFor(ID docshareID) {
- sessionStrategies.remove(docshareID);
+ public static void cleanUpFor(DocShare docshare) {
+ sessionStrategies.remove(docshare);
}
public UpdateMessage registerOutgoingMessage(UpdateMessage localMsg) {
- ColaUpdateMessage colaMsg = new ColaUpdateMessage(localMsg, localOperationsCount, remoteOperationsCount);
+ Trace.entering(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_ENTERING, this.getClass(), "registerOutgoingMessage", localMsg); //$NON-NLS-1$
+ final ColaUpdateMessage colaMsg = new ColaUpdateMessage(localMsg, localOperationsCount, remoteOperationsCount);
unacknowledgedLocalOperations.add(colaMsg);
localOperationsCount++;
+ Trace.exiting(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_EXITING, this.getClass(), "registerOutgoingMessage", colaMsg); //$NON-NLS-1$
return colaMsg;
}
/**
* Handles proper transformation of incoming <code>ColaUpdateMessage</code>s.
* Returned <code>UpdateMessage</code>s can be applied directly to the
- * shared document. The method implements the concurreny algorithm described
+ * shared document. The method implements the concurrency algorithm described
* in <code>http://wiki.eclipse.org/RT_Shared_Editing</code>
+ * @param remoteMsg
+ * @return UpdateMessage
*/
public UpdateMessage 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;
+ remoteOperationsCount++;
// TODO this is where the concurrency algorithm is executed
if (!unacknowledgedLocalOperations.isEmpty()) {
// remove operations from queue that have been implicitly
// acknowledged as received on the remote site by the reception of
// this message
- Iterator queueIterator = unacknowledgedLocalOperations.iterator();
- ColaUpdateMessage localOperation = (ColaUpdateMessage) queueIterator.next();
- while (!unacknowledgedLocalOperations.isEmpty() && transformedRemote.getRemoteOperationsCount() > localOperation.getLocalOperationsCount()) {
- queueIterator.remove();
- if (queueIterator.hasNext()) {
- localOperation = (ColaUpdateMessage) queueIterator.next();
+ for (final Iterator it = unacknowledgedLocalOperations.iterator(); it.hasNext();) {
+ ColaUpdateMessage unackedLocalOp = (ColaUpdateMessage) it.next();
+ if (transformedRemote.getRemoteOperationsCount() > unackedLocalOp.getLocalOperationsCount()) {
+ Trace.trace(Activator.PLUGIN_ID, NLS.bind("transformIncomingMessage.removing {0}", unackedLocalOp)); //$NON-NLS-1$
+ it.remove();
+ } else {
+ // the unackowledgedLocalOperations queue is ordered and
+ // sorted
+ // due to sequential insertion of local ops, thus once a
+ // local op with a higher
+ // or equal local op count (i.e. remote op count from the
+ // remote operation's view)
+ // is reached, we can abandon the check for the remaining
+ // queue items
+ Trace.trace(Activator.PLUGIN_ID, "breaking out of unackedLocalOperations loop"); //$NON-NLS-1$
+ break;// exits for-loop
}
- }// at this point the queue has been freed of operations that
+ }
+ // 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()) {
- Iterator queueModIterator = unacknowledgedLocalOperations.iterator();
- while (queueModIterator.hasNext()) {
+ ColaUpdateMessage localOp = (ColaUpdateMessage) unacknowledgedLocalOperations.getFirst();
+ Assert.isTrue(transformedRemote.getRemoteOperationsCount() == localOp.localOperationsCount);
+ for (final Iterator it = unacknowledgedLocalOperations.iterator(); it.hasNext();) {
// returns new instance
// clarify operation preference, owner/docshare initiator
// consistently comes first
- if (this.isInitiator) {
- transformedRemote = transformedRemote.transformForApplicationAtOwnerAgainst(localOperation);
- } else {
- transformedRemote = transformedRemote.transformForApplicationAtParticipantAgainst(localOperation);
- }
- localOperation = (ColaUpdateMessage) queueModIterator.next();
- }
- // TODO unsure whether this is needed or not, need to test
- // transform against last element in the queue
- if (this.isInitiator) {
- transformedRemote = transformedRemote.transformForApplicationAtOwnerAgainst(localOperation);
- } else {
- transformedRemote = transformedRemote.transformForApplicationAtParticipantAgainst(localOperation);
+
+ transformedRemote = transformedRemote.transformAgainst((ColaUpdateMessage) it.next(), isInitiator);
+
}
}
+
}
+ Trace.exiting(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_EXITING, this.getClass(), "transformIncomingMessage", transformedRemote); //$NON-NLS-1$
return transformedRemote;
+ }
+ public String toString() {
+ StringBuffer buf = new StringBuffer("ColaSynchronizer"); //$NON-NLS-1$
+ return buf.toString();
}
} \ No newline at end of file
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 8bbbcccd8..56ecf3fce 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
@@ -6,12 +6,15 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Mustafa K. Isik - conflict resolution via operational transformations
+ * Mustafa K. Isik - initial API and implementation
*****************************************************************************/
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;
public class ColaUpdateMessage extends UpdateMessage {
@@ -19,30 +22,38 @@ public class ColaUpdateMessage extends UpdateMessage {
// TODO encapsulate in a new ColaOpOriginationState and re-implement equals,
// hashCode, i.e. make comparable
- final double localOperationsCount;
- final double remoteOperationsCount;
+ final long localOperationsCount;
+ long remoteOperationsCount;
final TransformationStrategy trafoStrat;
- public ColaUpdateMessage(UpdateMessage msg, double localOperationsCount, double remoteOperationsCount) {
+ public ColaUpdateMessage(UpdateMessage msg, long localOperationsCount, long remoteOperationsCount) {
super(msg.getOffset(), msg.getLength(), msg.getText());
this.localOperationsCount = localOperationsCount;
this.remoteOperationsCount = remoteOperationsCount;
if (super.getLength() == 0) {
// this is neither a replacement, nor a deletion
- trafoStrat = new ColaInsertion();
+ trafoStrat = ColaInsertion.getInstance();
} else {
if (super.getText().length() == 0) {
// something has been replaced, nothing inserted, must be a
// deletion
- trafoStrat = new ColaDeletion();
+ trafoStrat = ColaDeletion.getInstance();
} else {
// something has been replaced with some new input, has to be a
// replacement op
- trafoStrat = new ColaReplacement();
+ trafoStrat = ColaReplacement.getInstance();
}
}
}
+ public boolean isInsertion() {
+ return (this.trafoStrat instanceof ColaInsertion);
+ }
+
+ public boolean isDeletion() {
+ return (this.trafoStrat instanceof ColaDeletion);
+ }
+
public double getLocalOperationsCount() {
return this.localOperationsCount;
}
@@ -51,37 +62,19 @@ public class ColaUpdateMessage extends UpdateMessage {
return this.remoteOperationsCount;
}
- /**
- * The receiver of this message transforms it for local application.
- *
- * The transformation assumes that this operation is to be transformed
- * against queued document owner operations which have a higher modification
- * priority. that is when in direct index conflict are applied to lower
- * index positions. This <code>ColaUpdateMessage</code> is transformed to
- * be applied to the next appropriate higher document index position.
- *
- * @param msg
- * queued up operation of local editing site
- * @return message suitable to be transformed against next queued up
- * operation
- */
- public ColaUpdateMessage transformForApplicationAtOwnerAgainst(ColaUpdateMessage msg) {
- // case this is the operation of lesser insertion priority
- ColaUpdateMessage transformedMsg = trafoStrat.getForOwner(this, msg);
- return transformedMsg;
- }
-
- public ColaUpdateMessage transformForApplicationAtParticipantAgainst(ColaUpdateMessage msg) {
- // case this is the operation of higher insertion priority
- ColaUpdateMessage transformedMsg = trafoStrat.getForParticipant(this, msg);
+ public ColaUpdateMessage transformAgainst(ColaUpdateMessage localMsg, boolean localMsgHighPrio) {
+ Trace.entering(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_ENTERING, this.getClass(), "transformAgainst", localMsg); //$NON-NLS-1$
+ ColaUpdateMessage transformedMsg = trafoStrat.getOperationalTransform(this, localMsg, localMsgHighPrio);
+ Trace.entering(Activator.PLUGIN_ID, DocshareDebugOptions.METHODS_EXITING, this.getClass(), "transformAgainst", transformedMsg); //$NON-NLS-1$
return transformedMsg;
}
public String toString() {
- StringBuffer sb = new StringBuffer(super.toString());
- sb.append(";").append("originationCount.local=").append(this.localOperationsCount).append(";"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
- sb.append("originationCount.remote=").append(this.remoteOperationsCount); //$NON-NLS-1$
- return sb.toString();
+ StringBuffer buf = new StringBuffer("ColaUpdateMessage["); //$NON-NLS-1$
+ buf.append("text=").append(getText()).append(";offset=").append(getOffset()); //$NON-NLS-1$ //$NON-NLS-2$
+ buf.append(";length=").append(getLength()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$
+ buf.append(";operationsCount[local=").append(getLocalOperationsCount()); //$NON-NLS-1$
+ buf.append(";remote=").append(getRemoteOperationsCount()).append("]]"); //$NON-NLS-1$//$NON-NLS-2$
+ return buf.toString();
}
-
}
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/TransformationStrategy.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/TransformationStrategy.java
index 966f014b1..90b5affec 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/TransformationStrategy.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/cola/TransformationStrategy.java
@@ -6,14 +6,15 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Mustafa K. Isik - conflict resolution via operational transformations
+ * Mustafa K. Isik - initial API and implementation
*****************************************************************************/
package org.eclipse.ecf.docshare.cola;
-public interface TransformationStrategy {
+import java.io.Serializable;
- ColaUpdateMessage getForOwner(ColaUpdateMessage toBeTransformed, ColaUpdateMessage alreadyApplied);
+public interface TransformationStrategy extends Serializable {
- ColaUpdateMessage getForParticipant(ColaUpdateMessage toBeTransformed, ColaUpdateMessage alreadyApplied);
+ ColaUpdateMessage getOperationalTransform(ColaUpdateMessage remoteIncomingMsg,
+ ColaUpdateMessage localAppliedMsg, boolean localMsgHighPrio);
}
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/menu/DocShareRosterMenuContributionItem.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/menu/DocShareRosterMenuContributionItem.java
index 53fe54d39..066b7cee2 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/menu/DocShareRosterMenuContributionItem.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/menu/DocShareRosterMenuContributionItem.java
@@ -1,17 +1,8 @@
-/****************************************************************************
- * Copyright (c) 2008 Composent, Inc. and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Composent, Inc. - initial API and implementation
- *****************************************************************************/
-
package org.eclipse.ecf.docshare.menu;
-import java.util.*;
+import java.util.Iterator;
+import java.util.List;
+
import org.eclipse.ecf.core.IContainer;
import org.eclipse.ecf.core.identity.ID;
import org.eclipse.ecf.docshare.DocShare;
@@ -22,9 +13,18 @@ import org.eclipse.ecf.presence.roster.IRoster;
import org.eclipse.ecf.presence.roster.IRosterEntry;
import org.eclipse.ecf.presence.ui.menu.AbstractRosterMenuContributionItem;
import org.eclipse.ecf.presence.ui.menu.AbstractRosterMenuHandler;
-import org.eclipse.jface.action.*;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
import org.eclipse.osgi.util.NLS;
-import org.eclipse.ui.*;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.ITextEditor;
public class DocShareRosterMenuContributionItem extends AbstractRosterMenuContributionItem {
@@ -75,7 +75,7 @@ public class DocShareRosterMenuContributionItem extends AbstractRosterMenuContri
final IPresenceContainerAdapter pca = (IPresenceContainerAdapter) i.next();
final DocShare docShare = getDocShareForPresenceContainerAdapter(pca);
if (docShare != null && docShare.isSharing() && docShare.getTextEditor().equals(editorPart)) {
- return getMenuContributionsDuringShare(docShare);
+ return getMenuContributionForStopShare(pca.getRosterManager().getRoster(), docShare, docShare.getOtherID());
}
}
return super.getContributionItems();
@@ -102,26 +102,15 @@ public class DocShareRosterMenuContributionItem extends AbstractRosterMenuContri
return new IContributionItem[] {menuManager};
}
- protected IContributionItem[] getMenuContributionsDuringShare(final DocShare docShare) {
- List items = new ArrayList();
- if (docShare.isInitiator()) {
- items.add(new Separator());
- }
- final IAction sendSelection = new Action() {
- public void run() {
- docShare.sendSelection();
- }
- };
- sendSelection.setText(NLS.bind(Messages.DocShareRosterMenuContributionItem_SELECTION_SEND_EDITOR_MENU_TEXT, trimIDNameForMenu(docShare.getOtherID())));
- items.add(new ActionContributionItem(sendSelection));
+ protected IContributionItem[] getMenuContributionForStopShare(IRoster roster, final DocShare docShare, final ID otherID) {
final IAction stopEditorShare = new Action() {
public void run() {
docShare.stopShare();
}
};
- stopEditorShare.setText(NLS.bind(Messages.DocShareRosterMenuContributionItem_STOP_SHARE_EDITOR_MENU_TEXT, trimIDNameForMenu(docShare.getOtherID())));
- items.add(new ActionContributionItem(stopEditorShare));
- return (IContributionItem[]) items.toArray(new IContributionItem[] {});
+ stopEditorShare.setText(NLS.bind(Messages.DocShareRosterMenuContributionItem_STOP_SHARE_EDITOR_MENU_TEXT, trimIDNameForMenu(otherID)));
+ stopEditorShare.setImageDescriptor(getTopMenuImageDescriptor());
+ return new IContributionItem[] {new Separator(), new ActionContributionItem(stopEditorShare)};
}
protected AbstractRosterMenuHandler createRosterEntryHandler(IRosterEntry rosterEntry) {
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/messages/UpdateMessage.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/messages/UpdateMessage.java
index a2790470c..4fc1772c0 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/messages/UpdateMessage.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/docshare/messages/UpdateMessage.java
@@ -13,13 +13,13 @@
package org.eclipse.ecf.docshare.messages;
/**
- *
+ *
*/
public class UpdateMessage extends Message {
private static final long serialVersionUID = -3195542805471664496L;
- String text;
+ final String text;
int offset;
int length;
@@ -29,15 +29,42 @@ public class UpdateMessage extends Message {
this.text = text;
}
+ /**
+ * Returns the modification index of the operation resembled by this
+ * message.
+ *
+ * @return modification index
+ */
public int getOffset() {
return offset;
}
+ public void setOffset(int updatedOffset) {
+ this.offset = updatedOffset;
+ }
+
+ /**
+ * Returns the length of replaced text.
+ *
+ * @return length of replaced text
+ */
public int getLength() {
return length;
}
+ public void setLength(int length) {
+ this.length = length;
+ }
+
public String getText() {
return text;
}
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer("UpdateMessage["); //$NON-NLS-1$
+ buf.append("text=").append(text).append(";offset=").append(offset); //$NON-NLS-1$ //$NON-NLS-2$
+ buf.append(";length=").append(length).append("]"); //$NON-NLS-1$ //$NON-NLS-2$
+ return buf.toString();
+ }
+
}
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/Activator.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/Activator.java
index bdc6211bb..a39d9daf1 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/Activator.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/Activator.java
@@ -1,17 +1,7 @@
-/****************************************************************************
- * Copyright (c) 2008 Composent, Inc. and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Composent, Inc. - initial API and implementation
- *****************************************************************************/
-
package org.eclipse.ecf.internal.docshare;
import java.util.Hashtable;
+
import org.eclipse.ecf.core.IContainerManager;
import org.eclipse.ecf.core.identity.ID;
import org.eclipse.ecf.core.util.ECFException;
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/DocshareDebugOptions.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/DocshareDebugOptions.java
new file mode 100644
index 000000000..01d366c05
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/DocshareDebugOptions.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Composent, Inc. and others. All rights reserved. This
+ * program and the accompanying materials are made available under the terms of
+ * the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: Composent, Inc. - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ecf.internal.docshare;
+
+public interface DocshareDebugOptions {
+
+ public static final String DEBUG = Activator.PLUGIN_ID + "/debug"; //$NON-NLS-1$
+
+ public static final String EXCEPTIONS_CATCHING = DEBUG + "/exceptions/catching"; //$NON-NLS-1$
+
+ public static final String EXCEPTIONS_THROWING = DEBUG + "/exceptions/throwing"; //$NON-NLS-1$
+
+ public static final String METHODS_ENTERING = DEBUG + "/methods/entering"; //$NON-NLS-1$
+
+ public static final String METHODS_EXITING = DEBUG + "/methods/exiting"; //$NON-NLS-1$
+
+}
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/ECFStart.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/ECFStart.java
index e2fa0850c..f5240650e 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/ECFStart.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/ECFStart.java
@@ -1,5 +1,5 @@
/****************************************************************************
- * Copyright (c) 2008 Composent, Inc. and others.
+ * Copyright (c) 2007 Composent, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -18,27 +18,26 @@ import org.eclipse.ecf.core.identity.ID;
import org.eclipse.ecf.core.start.IECFStart;
import org.eclipse.ecf.core.util.ECFException;
import org.eclipse.ecf.datashare.IChannelContainerAdapter;
-import org.eclipse.ecf.docshare.DocShare;
import org.eclipse.osgi.util.NLS;
public class ECFStart implements IECFStart {
IContainerListener containerListener = new IContainerListener() {
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see org.eclipse.ecf.core.IContainerListener#handleEvent(org.eclipse.ecf.core.events.IContainerEvent)
*/
public void handleEvent(IContainerEvent event) {
- Activator activator = Activator.getDefault();
- if (activator == null)
- return;
- final IContainerManager containerManager = activator.getContainerManager();
+ final IContainerManager containerManager = Activator.getDefault().getContainerManager();
if (containerManager == null)
return;
IContainer container = containerManager.getContainer(event.getLocalContainerID());
if (container == null)
return;
- if (event instanceof IContainerConnectedEvent || event instanceof IContainerDisconnectedEvent || event instanceof IContainerEjectedEvent) {
+ if (event instanceof IContainerConnectedEvent
+ || event instanceof IContainerDisconnectedEvent) {
// connected
IChannelContainerAdapter cca = (IChannelContainerAdapter) container.getAdapter(IChannelContainerAdapter.class);
if (cca == null)
@@ -46,16 +45,17 @@ public class ECFStart implements IECFStart {
ID containerID = container.getID();
if (event instanceof IContainerConnectedEvent) {
try {
- activator.addDocShare(containerID, cca);
+ Activator.getDefault().addDocShare(containerID, cca);
} catch (ECFException e) {
- activator.getLog().log(new Status(IStatus.INFO, Activator.PLUGIN_ID, IStatus.INFO, NLS.bind(Messages.ECFStart_ERROR_DOCUMENT_SHARE_NOT_CREATED, container.getID()), null));
- }
- } else if (event instanceof IContainerDisconnectedEvent || event instanceof IContainerEjectedEvent) {
- // disconnected, so remove docshare for given container, and remove associated channel
- DocShare docShare = Activator.getDefault().removeDocShare(containerID);
- if (docShare != null) {
- docShare.dispose();
+ Activator.getDefault().getLog().log(
+ new Status(IStatus.WARNING, Activator.PLUGIN_ID, IStatus.WARNING,
+ NLS.bind(
+ Messages.ECFStart_ERROR_DOCUMENT_SHARE_NOT_CREATED,
+ container.getID()), null));
}
+ } else if (event instanceof IContainerDisconnectedEvent) {
+ // disconnected
+ Activator.getDefault().removeDocShare(containerID);
}
} else if (event instanceof IContainerDisposeEvent) {
containerManager.removeListener(containerManagerListener);
@@ -67,7 +67,9 @@ public class ECFStart implements IECFStart {
IContainerManagerListener containerManagerListener = new IContainerManagerListener() {
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see org.eclipse.ecf.core.IContainerManagerListener#containerAdded(org.eclipse.ecf.core.IContainer)
*/
public void containerAdded(IContainer container) {
@@ -77,7 +79,9 @@ public class ECFStart implements IECFStart {
container.addListener(containerListener);
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see org.eclipse.ecf.core.IContainerManagerListener#containerRemoved(org.eclipse.ecf.core.IContainer)
*/
public void containerRemoved(IContainer container) {
@@ -85,13 +89,16 @@ public class ECFStart implements IECFStart {
}
};
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see org.eclipse.ecf.core.start.IECFStart#run(org.eclipse.core.runtime.IProgressMonitor)
*/
public IStatus run(IProgressMonitor monitor) {
final IContainerManager containerManager = Activator.getDefault().getContainerManager();
if (containerManager == null)
- return new Status(IStatus.WARNING, Activator.PLUGIN_ID, IStatus.WARNING, Messages.ECFStart_ERROR_CONTAINER_MANAGER_NOT_AVAILABLE, null);
+ return new Status(IStatus.WARNING, Activator.PLUGIN_ID, IStatus.WARNING,
+ Messages.ECFStart_ERROR_CONTAINER_MANAGER_NOT_AVAILABLE, null);
containerManager.addListener(containerManagerListener);
return Status.OK_STATUS;
}
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/Messages.java b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/Messages.java
index 40ea115ee..3c57da218 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/Messages.java
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/Messages.java
@@ -27,9 +27,6 @@ public class Messages extends NLS {
public static String DocShare_EXCEPTION_RECEIVING_MESSAGE_MESSAGE;
public static String DocShare_EXCEPTION_RECEIVING_MESSAGE_TITLE;
public static String DocShare_EXCEPTION_SEND_MESSAGE;
- public static String DocShare_SELECTION_SEND_ERROR_MESSAGE;
- public static String DocShare_SELECTION_SEND_ERROR_TITLE;
- public static String DocShareRosterMenuContributionItem_SELECTION_SEND_EDITOR_MENU_TEXT;
public static String DocShareRosterMenuContributionItem_SHARE_EDITOR_MENU_TEXT;
public static String DocShareRosterMenuContributionItem_STOP_SHARE_EDITOR_MENU_TEXT;
public static String DocShareRosterMenuHandler_ERROR_ALREADY_PARTICIPATING;
diff --git a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/messages.properties b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/messages.properties
index 89908cf67..4376d08c8 100644
--- a/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/messages.properties
+++ b/framework/bundles/org.eclipse.ecf.docshare/src/org/eclipse/ecf/internal/docshare/messages.properties
@@ -1,11 +1,3 @@
-################################################################################
-# Copyright (c) 2008 Composent, Inc., Mustafa Isik and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Eclipse Public License v1.0
-# which accompanies this distribution, and is available at
-# http://www.eclipse.org/legal/epl-v10.html
-#
-################################################################################
DocShare_EDITOR_SHARE_POPUP_MESSAGE=Editor share request from {0} for {1}.\n\nDo you want to accept and open editor?
DocShare_EDITOR_SHARE_POPUP_TITLE=Editor Share
DocShare_ERROR_STARTING_EDITOR_MESSAGE=Error Starting Editor Sharing {0}
@@ -15,11 +7,8 @@ DocShare_EXCEPTION_INVALID_MESSAGE=message is invalid type {0}
DocShare_EXCEPTION_RECEIVING_MESSAGE_MESSAGE=Exception handling start message {0}
DocShare_EXCEPTION_RECEIVING_MESSAGE_TITLE=Exception receiving message
DocShare_EXCEPTION_SEND_MESSAGE=send message error
-DocShare_SELECTION_SEND_ERROR_MESSAGE=The selection send failed. See error log for more information
-DocShare_SELECTION_SEND_ERROR_TITLE=Selection send error
-DocShareRosterMenuContributionItem_SELECTION_SEND_EDITOR_MENU_TEXT=Send Editor Selection to {0}
DocShareRosterMenuContributionItem_SHARE_EDITOR_MENU_TEXT=Share Editor With
-DocShareRosterMenuContributionItem_STOP_SHARE_EDITOR_MENU_TEXT=Stop Editor Sharing with {0}
+DocShareRosterMenuContributionItem_STOP_SHARE_EDITOR_MENU_TEXT=Stop Sharing Editor with {0}
DocShareRosterMenuHandler_ERROR_ALREADY_PARTICIPATING=Already participating in editor sharing
DocShareRosterMenuHandler_ERROR_EDITOR_ALREADY_SHARING=Editor is already sharing
DocShareRosterMenuHandler_ERROR_NO_DOCUMENT_CONTENT=No document content

Back to the top