Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorslewis2008-10-01 20:12:20 -0400
committerslewis2008-10-01 20:12:20 -0400
commit38a9a76d687e731347eb05acfcbd7fb2e2c45aad (patch)
tree1bdb6409ce6425ce74a70be4db43f8f96ad1be29 /framework/bundles/org.eclipse.ecf.sync
parent503849cd367b1ac79be04900984a9c0c15f30dda (diff)
downloadorg.eclipse.ecf-38a9a76d687e731347eb05acfcbd7fb2e2c45aad.tar.gz
org.eclipse.ecf-38a9a76d687e731347eb05acfcbd7fb2e2c45aad.tar.xz
org.eclipse.ecf-38a9a76d687e731347eb05acfcbd7fb2e2c45aad.zip
Initial checkin of o.e.e.sync plugin in runtime area
Diffstat (limited to 'framework/bundles/org.eclipse.ecf.sync')
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/.classpath7
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/.options16
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/.project34
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/.settings/org.eclipse.jdt.core.prefs7
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/.settings/org.eclipse.pde.core.prefs4
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/META-INF/MANIFEST.MF20
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/about.html28
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/build.properties10
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/plugin.properties12
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/Activator.java63
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/SyncDebugOptions.java23
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaDeletionTransformationStrategy.java148
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaDocumentChangeMessage.java113
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaInsertionTransformationStategy.java105
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaReplacementTransformationStategy.java44
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaSynchronizationStrategy.java220
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaSynchronizationStrategyFactory.java39
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaTransformationStrategy.java19
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/identity/IdentitySynchronizationStrategy.java46
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/identity/IdentitySynchronizationStrategyFactory.java38
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/IServiceConstants.java21
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentChange.java37
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentChangeMessage.java23
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentSynchronizationStrategy.java58
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentSynchronizationStrategyFactory.java39
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/SerializationException.java58
-rw-r--r--framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/messages/DocumentChangeMessage.java109
27 files changed, 1341 insertions, 0 deletions
diff --git a/framework/bundles/org.eclipse.ecf.sync/.classpath b/framework/bundles/org.eclipse.ecf.sync/.classpath
new file mode 100644
index 000000000..2fbb7a23e
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.4"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/framework/bundles/org.eclipse.ecf.sync/.options b/framework/bundles/org.eclipse.ecf.sync/.options
new file mode 100644
index 000000000..2937ca723
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/.options
@@ -0,0 +1,16 @@
+# Debugging options for the org.eclipse.ecf.sync plug-in
+
+# Turn on general debugging for the org.eclipse.ecf.internal.provisional.docshare plug-in
+org.eclipse.ecf.sync/debug=true
+org.eclipse.ecf.sync/debug/filter = *
+org.eclipse.ecf.sync/debug/flag = true
+
+# Trace when exceptions are caught
+org.eclipse.ecf.sync/debug/exceptions/catching=false
+# Trace when exceptions are thrown
+org.eclipse.ecf.sync/debug/exceptions/throwing=false
+
+# Trace when methods are entered
+org.eclipse.ecf.sync/debug/methods/entering=false
+# Trace when methods are exited
+org.eclipse.ecf.sync/debug/methods/exiting=false
diff --git a/framework/bundles/org.eclipse.ecf.sync/.project b/framework/bundles/org.eclipse.ecf.sync/.project
new file mode 100644
index 000000000..b250cebb6
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.ecf.sync.doc</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+ </natures>
+</projectDescription>
diff --git a/framework/bundles/org.eclipse.ecf.sync/.settings/org.eclipse.jdt.core.prefs b/framework/bundles/org.eclipse.ecf.sync/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..4b7e2cfc4
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+#Tue Sep 23 21:41:24 PDT 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.source=1.3
diff --git a/framework/bundles/org.eclipse.ecf.sync/.settings/org.eclipse.pde.core.prefs b/framework/bundles/org.eclipse.ecf.sync/.settings/org.eclipse.pde.core.prefs
new file mode 100644
index 000000000..ae44e6131
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,4 @@
+#Tue Sep 23 21:41:25 PDT 2008
+eclipse.preferences.version=1
+pluginProject.extensions=false
+resolve.requirebundle=false
diff --git a/framework/bundles/org.eclipse.ecf.sync/META-INF/MANIFEST.MF b/framework/bundles/org.eclipse.ecf.sync/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..59f378c40
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/META-INF/MANIFEST.MF
@@ -0,0 +1,20 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %plugin.name
+Bundle-SymbolicName: org.eclipse.ecf.sync
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.eclipse.ecf.internal.sync.Activator
+Bundle-Vendor: %plugin.provider
+Bundle-RequiredExecutionEnvironment: J2SE-1.4
+Import-Package: org.eclipse.core.runtime;version="3.4.0",
+ org.eclipse.ecf.core.identity,
+ org.eclipse.ecf.core.util,
+ org.eclipse.osgi.util;version="1.1.0",
+ org.osgi.framework
+Eclipse-LazyStart: true
+Bundle-ActivationPolicy: lazy
+Bundle-Localization: plugin
+Export-Package: org.eclipse.ecf.internal.sync;x-internal:=true,
+ org.eclipse.ecf.internal.sync.doc.cola;x-internal:=true,
+ org.eclipse.ecf.sync.doc,
+ org.eclipse.ecf.sync.doc.messages
diff --git a/framework/bundles/org.eclipse.ecf.sync/about.html b/framework/bundles/org.eclipse.ecf.sync/about.html
new file mode 100644
index 000000000..6a60a262f
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<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
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/framework/bundles/org.eclipse.ecf.sync/build.properties b/framework/bundles/org.eclipse.ecf.sync/build.properties
new file mode 100644
index 000000000..fad931173
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/build.properties
@@ -0,0 +1,10 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ about.html,\
+ plugin.properties
+src.includes = META-INF/,\
+ about.html,\
+ plugin.properties,\
+ src/
diff --git a/framework/bundles/org.eclipse.ecf.sync/plugin.properties b/framework/bundles/org.eclipse.ecf.sync/plugin.properties
new file mode 100644
index 000000000..636946c9d
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/plugin.properties
@@ -0,0 +1,12 @@
+################################################################################
+# 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
+################################################################################
+plugin.provider = Eclipse.org
+plugin.name = ECF Synchronization API \ No newline at end of file
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/Activator.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/Activator.java
new file mode 100644
index 000000000..3f74dee68
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/Activator.java
@@ -0,0 +1,63 @@
+package org.eclipse.ecf.internal.sync;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+import org.eclipse.ecf.internal.sync.doc.cola.ColaSynchronizationStrategyFactory;
+import org.eclipse.ecf.internal.sync.doc.identity.IdentitySynchronizationStrategyFactory;
+import org.eclipse.ecf.sync.IServiceConstants;
+import org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategyFactory;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class Activator implements BundleActivator {
+
+ public static final String PLUGIN_ID = "org.eclipse.ecf.sync";
+
+ private static Activator bundle;
+ private ServiceRegistration colaServiceRegistration;
+ private ServiceRegistration identityServiceRegistration;
+ private BundleContext context;
+
+ public static Activator getDefault() {
+ return bundle;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext ctxt) throws Exception {
+ bundle = this;
+ this.context = ctxt;
+ // Register identity synchronizer service
+ final Dictionary identityServiceProps = new Properties();
+ identityServiceProps.put(IServiceConstants.SYNCSTRATEGY_TYPE_PROPERTY, IdentitySynchronizationStrategyFactory.SYNCHSTRATEGY_TYPE);
+ identityServiceProps.put(IServiceConstants.SYNCSTRATEGY_PROVIDER_PROPETY, IdentitySynchronizationStrategyFactory.SYNCHSTRATEGY_PROVIDER);
+ identityServiceRegistration = this.context.registerService(IDocumentSynchronizationStrategyFactory.class.getName(), new IdentitySynchronizationStrategyFactory(), identityServiceProps);
+ // Register cola synchronizer service
+ final Dictionary colaServiceProps = new Properties();
+ colaServiceProps.put(IServiceConstants.SYNCSTRATEGY_TYPE_PROPERTY, ColaSynchronizationStrategyFactory.SYNCHSTRATEGY_TYPE);
+ colaServiceProps.put(IServiceConstants.SYNCSTRATEGY_PROVIDER_PROPETY, ColaSynchronizationStrategyFactory.SYNCHSTRATEGY_PROVIDER);
+ colaServiceRegistration = this.context.registerService(IDocumentSynchronizationStrategyFactory.class.getName(), new ColaSynchronizationStrategyFactory(), colaServiceProps);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ if (colaServiceRegistration != null) {
+ colaServiceRegistration.unregister();
+ colaServiceRegistration = null;
+ }
+ if (identityServiceRegistration != null) {
+ identityServiceRegistration.unregister();
+ identityServiceRegistration = null;
+ }
+ this.context = null;
+ bundle = null;
+ }
+
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/SyncDebugOptions.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/SyncDebugOptions.java
new file mode 100644
index 000000000..cb8dc9038
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/SyncDebugOptions.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.sync;
+
+public interface SyncDebugOptions {
+
+ 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.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaDeletionTransformationStrategy.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaDeletionTransformationStrategy.java
new file mode 100644
index 000000000..22eaa757f
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaDeletionTransformationStrategy.java
@@ -0,0 +1,148 @@
+/****************************************************************************
+ * Copyright (c) 2008 Mustafa K. 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
+ *
+ * Contributors:
+ * Mustafa K. Isik - initial API and implementation
+ *****************************************************************************/
+
+package org.eclipse.ecf.internal.sync.doc.cola;
+
+import org.eclipse.ecf.core.util.Trace;
+import org.eclipse.ecf.internal.sync.Activator;
+import org.eclipse.ecf.internal.sync.SyncDebugOptions;
+import org.eclipse.ecf.sync.doc.messages.DocumentChangeMessage;
+
+public class ColaDeletionTransformationStrategy implements ColaTransformationStrategy {
+
+ private static final long serialVersionUID = -7430435392915553959L;
+ private static ColaDeletionTransformationStrategy INSTANCE;
+
+ private ColaDeletionTransformationStrategy() {
+ // default constructor is private to enforce singleton property via
+ // static factory method
+ }
+
+ public static ColaTransformationStrategy getInstance() {
+ if (INSTANCE == null) {
+ INSTANCE = new ColaDeletionTransformationStrategy();
+ }
+ return INSTANCE;
+ }
+
+ public ColaDocumentChangeMessage getOperationalTransform(ColaDocumentChangeMessage remoteIncomingMsg, ColaDocumentChangeMessage localAppliedMsg, boolean localMsgHighPrio) {
+
+ Trace.entering(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_ENTERING, this.getClass(), "getOperationalTransform", new Object[] {remoteIncomingMsg, localAppliedMsg, new Boolean(localMsgHighPrio)}); //$NON-NLS-1$
+
+ 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());
+ localAppliedMsg.setOffset(remoteTransformedMsg.getOffset());//TODO verify!
+
+ } 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());
+ }
+ }
+
+ Trace.exiting(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_EXITING, this.getClass(), "getOperationalTransform", null); //$NON-NLS-1$
+
+ return remoteTransformedMsg;
+ }
+
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaDocumentChangeMessage.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaDocumentChangeMessage.java
new file mode 100644
index 000000000..4ab9c577f
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaDocumentChangeMessage.java
@@ -0,0 +1,113 @@
+/****************************************************************************
+ * Copyright (c) 2008 Mustafa K. 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
+ *
+ * Contributors:
+ * Mustafa K. Isik - initial API and implementation
+ *****************************************************************************/
+
+package org.eclipse.ecf.internal.sync.doc.cola;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.ecf.core.util.Trace;
+import org.eclipse.ecf.internal.sync.Activator;
+import org.eclipse.ecf.internal.sync.SyncDebugOptions;
+import org.eclipse.ecf.sync.doc.messages.DocumentChangeMessage;
+
+public class ColaDocumentChangeMessage extends DocumentChangeMessage {
+
+ private static final long serialVersionUID = 2038025022180647210L;
+
+ // TODO encapsulate in a new ColaOpOriginationState and re-implement equals,
+ // hashCode, i.e. make comparable
+ private final long localOperationsCount;
+ private final long remoteOperationsCount;
+ private final ColaTransformationStrategy trafoStrat;
+ private boolean splitUp;
+ private List splitUpRepresentation;
+
+ public ColaDocumentChangeMessage(DocumentChangeMessage 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 = ColaInsertionTransformationStategy.getInstance();
+ } else {
+ if (super.getText().length() == 0) {
+ // something has been replaced, nothing inserted, must be a
+ // deletion
+ trafoStrat = ColaDeletionTransformationStrategy.getInstance();
+ } else {
+ // something has been replaced with some new input, has to be a
+ // replacement op
+ trafoStrat = ColaReplacementTransformationStategy.getInstance();
+ //TODO this has not been implemented yet
+ //throw new IllegalArgumentException("Replacement Handling not implemented yet! Known Bug.");
+ }
+ }
+ }
+
+ public boolean isInsertion() {
+ return (this.trafoStrat instanceof ColaInsertionTransformationStategy);
+ }
+
+ public boolean isDeletion() {
+ return (this.trafoStrat instanceof ColaDeletionTransformationStrategy);
+ }
+
+ public boolean isReplacement() {
+ return (this.trafoStrat instanceof ColaReplacementTransformationStategy);
+ }
+
+ public long getLocalOperationsCount() {
+ return this.localOperationsCount;
+ }
+
+ public long getRemoteOperationsCount() {
+ return this.remoteOperationsCount;
+ }
+
+ public ColaDocumentChangeMessage transformAgainst(ColaDocumentChangeMessage localMsg, boolean localMsgHighPrio) {
+ Trace.entering(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_ENTERING, this.getClass(), "transformAgainst", localMsg); //$NON-NLS-1$
+ final ColaDocumentChangeMessage transformedMsg = trafoStrat.getOperationalTransform(this, localMsg, localMsgHighPrio);
+ Trace.entering(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_EXITING, this.getClass(), "transformAgainst", transformedMsg); //$NON-NLS-1$
+ return transformedMsg;
+ }
+
+ public String toString() {
+ final StringBuffer buf = new StringBuffer("ColaDocumentChangeMessage["); //$NON-NLS-1$
+ buf.append("text=").append(getText()).append(";offset=").append(getOffset()); //$NON-NLS-1$ //$NON-NLS-2$
+ buf.append(";length=").append(getLengthOfReplacedText()).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();
+ }
+
+ public void setSplitUp(boolean toBeSplitUp) {
+ this.splitUp = toBeSplitUp;
+ }
+
+ public boolean isSplitUp() {
+ return splitUp;
+ }
+
+ public void setSplitUpRepresentation(List splitUpRepresentation) {
+ this.splitUpRepresentation = splitUpRepresentation;
+ }
+
+ public List getSplitUpRepresentation() {
+ return splitUpRepresentation;
+ }
+
+ public void addToSplitUpRepresentation(ColaDocumentChangeMessage splitUpRepresentationPart) {
+ this.splitUpRepresentation.add(splitUpRepresentationPart);
+ }
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaInsertionTransformationStategy.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaInsertionTransformationStategy.java
new file mode 100644
index 000000000..e91f728bd
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaInsertionTransformationStategy.java
@@ -0,0 +1,105 @@
+/****************************************************************************
+ * Copyright (c) 2008 Mustafa K. 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
+ *
+ * Contributors:
+ * Mustafa K. Isik - initial API and implementation
+ *****************************************************************************/
+
+package org.eclipse.ecf.internal.sync.doc.cola;
+
+import org.eclipse.ecf.core.util.Trace;
+import org.eclipse.ecf.internal.sync.Activator;
+import org.eclipse.ecf.internal.sync.SyncDebugOptions;
+import org.eclipse.ecf.sync.doc.messages.DocumentChangeMessage;
+
+public class ColaInsertionTransformationStategy implements ColaTransformationStrategy {
+
+ private static final long serialVersionUID = 5192625383622519749L;
+ private static ColaInsertionTransformationStategy INSTANCE;
+
+ private ColaInsertionTransformationStategy() {
+ // default constructor is private to enforce singleton property via
+ // static factory method
+ }
+
+ public static ColaTransformationStrategy getInstance() {
+ if (INSTANCE == null) {
+ INSTANCE = new ColaInsertionTransformationStategy();
+ }
+ return INSTANCE;
+ }
+
+ /**
+ * 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) {
+
+ Trace.entering(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_ENTERING, this.getClass(), "getOperationalTransform", new Object[] {remoteIncomingMsg, localAppliedMsg, new Boolean(localMsgHighPrio)}); //$NON-NLS-1$
+
+ 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());
+
+ }
+ }
+ }
+
+ Trace.exiting(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_EXITING, this.getClass(), "getOperationalTransform", remoteTransformedMsg); //$NON-NLS-1$
+ return remoteTransformedMsg;
+ }
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaReplacementTransformationStategy.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaReplacementTransformationStategy.java
new file mode 100644
index 000000000..370c68f00
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaReplacementTransformationStategy.java
@@ -0,0 +1,44 @@
+/****************************************************************************
+ * Copyright (c) 2008 Mustafa K. 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
+ *
+ * Contributors:
+ * Mustafa K. Isik - initial API and implementation
+ *****************************************************************************/
+
+package org.eclipse.ecf.internal.sync.doc.cola;
+
+import org.eclipse.ecf.core.util.Trace;
+import org.eclipse.ecf.internal.sync.Activator;
+import org.eclipse.ecf.internal.sync.SyncDebugOptions;
+
+//TODO make this to be something like a marker interface, does not need to be a class
+public class ColaReplacementTransformationStategy implements ColaTransformationStrategy {
+
+ private static final long serialVersionUID = -7295023855308474804L;
+ private static ColaReplacementTransformationStategy INSTANCE;
+
+ private ColaReplacementTransformationStategy() {
+ // default constructor is private to enforce singleton property via
+ // static factory method
+ }
+
+ public static ColaTransformationStrategy getInstance() {
+ if (INSTANCE == null) {
+ INSTANCE = new ColaReplacementTransformationStategy();
+ }
+ return INSTANCE;
+ }
+
+ public ColaDocumentChangeMessage getOperationalTransform(ColaDocumentChangeMessage remoteMsg, ColaDocumentChangeMessage appliedLocalMsg, boolean localMsgHighPrio) {
+ Trace.entering(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_ENTERING, this.getClass(), "getOperationalTransform", new Object[] {remoteMsg, appliedLocalMsg, new Boolean(localMsgHighPrio)}); //$NON-NLS-1$
+
+ Trace.exiting(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_EXITING, this.getClass(), "getOperationalTransform", null); //$NON-NLS-1$
+
+ return null;
+ }
+
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaSynchronizationStrategy.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaSynchronizationStrategy.java
new file mode 100644
index 000000000..96d3a44df
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaSynchronizationStrategy.java
@@ -0,0 +1,220 @@
+/****************************************************************************
+ * Copyright (c) 2008 Mustafa K. 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
+ *
+ * Contributors:
+ * Mustafa K. Isik - initial API and implementation
+ *****************************************************************************/
+
+package org.eclipse.ecf.internal.sync.doc.cola;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.ecf.core.identity.ID;
+import org.eclipse.ecf.core.util.Trace;
+import org.eclipse.ecf.internal.sync.Activator;
+import org.eclipse.ecf.internal.sync.SyncDebugOptions;
+import org.eclipse.ecf.sync.doc.IDocumentChange;
+import org.eclipse.ecf.sync.doc.IDocumentChangeMessage;
+import org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategy;
+import org.eclipse.ecf.sync.doc.SerializationException;
+import org.eclipse.ecf.sync.doc.messages.DocumentChangeMessage;
+import org.eclipse.osgi.util.NLS;
+
+public class ColaSynchronizationStrategy implements IDocumentSynchronizationStrategy {
+
+ // <ColaDocumentChangeMessage>
+ private final LinkedList unacknowledgedLocalOperations;
+ private final boolean isInitiator;
+ private long localOperationsCount;
+ private long remoteOperationsCount;
+
+ // <DocShare, ColaSynchronizationStrategy>
+ private static Map sessionStrategies = new HashMap();
+
+ private ColaSynchronizationStrategy(boolean isInitiator) {
+ this.isInitiator = isInitiator;
+ unacknowledgedLocalOperations = new LinkedList();
+ localOperationsCount = 0;
+ remoteOperationsCount = 0;
+ }
+
+ public static ColaSynchronizationStrategy getInstanceFor(ID client, boolean isInitiator) {
+ if (sessionStrategies.get(client) == null) {
+ sessionStrategies.put(client, new ColaSynchronizationStrategy(isInitiator));
+ }
+ return (ColaSynchronizationStrategy) sessionStrategies.get(client);
+ }
+
+ public static void cleanUpFor(ID client) {
+ sessionStrategies.remove(client);
+ }
+
+ public DocumentChangeMessage registerOutgoingMessage(DocumentChangeMessage localMsg) {
+ Trace.entering(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_ENTERING, this.getClass(), "registerOutgoingMessage", localMsg); //$NON-NLS-1$
+ final ColaDocumentChangeMessage colaMsg = new ColaDocumentChangeMessage(localMsg, localOperationsCount, remoteOperationsCount);
+ if (!colaMsg.isReplacement()) {
+ unacknowledgedLocalOperations.add(colaMsg);
+ localOperationsCount++;
+ }
+ Trace.exiting(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_EXITING, this.getClass(), "registerOutgoingMessage", colaMsg); //$NON-NLS-1$
+ return colaMsg;
+ }
+
+ /**
+ * Handles proper transformation of incoming <code>ColaDocumentChangeMessage</code>s.
+ * Returned <code>DocumentChangeMessage</code>s can be applied directly to the
+ * shared document. The method implements the concurrency algorithm described
+ * in <code>http://wiki.eclipse.org/RT_Shared_Editing</code>
+ * @param remoteMsg
+ * @return List contains <code>DocumentChangeMessage</code>s ready for sequential application to document
+ */
+ public List transformIncomingMessage(final DocumentChangeMessage remoteMsg) {
+ if (!(remoteMsg instanceof ColaDocumentChangeMessage)) {
+ throw new IllegalArgumentException("DocumentChangeMessage is incompatible with Cola SynchronizationStrategy"); //$NON-NLS-1$
+ }
+ Trace.entering(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_ENTERING, this.getClass(), "transformIncomingMessage", remoteMsg); //$NON-NLS-1$
+ ColaDocumentChangeMessage transformedRemote = (ColaDocumentChangeMessage) remoteMsg;
+
+ final List transformedRemotes = new LinkedList();
+ transformedRemotes.add(transformedRemote);
+
+ remoteOperationsCount++;
+ //this is where the concurrency algorithm is executed
+ if (!unacknowledgedLocalOperations.isEmpty()) {//Do not remove this. It is necessary. The following iterator does not suffice.
+ // remove operations from queue that have been implicitly
+ // acknowledged as received on the remote site by the reception of
+ // this message
+ for (final Iterator it = unacknowledgedLocalOperations.iterator(); it.hasNext();) {
+ final ColaDocumentChangeMessage unackedLocalOp = (ColaDocumentChangeMessage) 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
+ // don't require to be transformed against
+
+ if (!unacknowledgedLocalOperations.isEmpty()) {
+ ColaDocumentChangeMessage localOp = (ColaDocumentChangeMessage) unacknowledgedLocalOperations.getFirst();
+ Assert.isTrue(transformedRemote.getRemoteOperationsCount() == localOp.getLocalOperationsCount());
+
+ for (final ListIterator unackOpsListIt = unacknowledgedLocalOperations.listIterator(); unackOpsListIt.hasNext();) {
+ for (final ListIterator trafoRemotesIt = transformedRemotes.listIterator(); trafoRemotesIt.hasNext();) {
+ // returns new instance
+ // clarify operation preference, owner/docshare initiator
+ // consistently comes first
+ localOp = (ColaDocumentChangeMessage) unackOpsListIt.next();
+ transformedRemote = (ColaDocumentChangeMessage) trafoRemotesIt.next();
+ transformedRemote = transformedRemote.transformAgainst(localOp, isInitiator);
+
+ if (transformedRemote.isSplitUp()) {
+ //currently this only happens for a remote deletion that needs to be transformed against a locally applied insertion
+ //attention: before applying a list of deletions to docshare, the indices need to be updated/finalized one last time
+ //since deletions can only be applied sequentially and every deletion is going to change the underlying document and the
+ //respective indices!
+ trafoRemotesIt.remove();
+ for (final Iterator splitUpIterator = transformedRemote.getSplitUpRepresentation().iterator(); splitUpIterator.hasNext();) {
+ trafoRemotesIt.add(splitUpIterator.next());
+ }
+ //according to the ListIterator documentation it seems so as if the following line is unnecessary,
+ //as a call to next() after the last removal and additions will return what it would have returned anyway
+ //trafoRemotesIt.next();//TODO not sure about the need for this - I want to jump over the two inserted ops and reach the end of this iterator
+ }
+
+ //TODO check whether or not this collection shuffling does what it is supposed to, i.e. remove current localop in unack list and add split up representation instead
+ if (localOp.isSplitUp()) {
+ //local operation has been split up during operational transform --> remove current version and add new versions plus jump over those
+ unackOpsListIt.remove();
+ for (final Iterator splitUpOpIterator = localOp.getSplitUpRepresentation().iterator(); splitUpOpIterator.hasNext();) {
+ unackOpsListIt.add(splitUpOpIterator.next());
+ }
+ //according to the ListIterator documentation it seems so as if the following line is unnecessary,
+ //as a call to next() after the last removal and additions will return what it would have returned anyway
+ //unackOpsListIt.next();//TODO check whether or not this does jump over both inserted operations that replaced the current unack op
+ }//end split up localop handling
+ }//transformedRemotes List iteration
+ }
+ }
+
+ }
+ Trace.exiting(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_EXITING, this.getClass(), "transformIncomingMessage", transformedRemote); //$NON-NLS-1$
+
+ //TODO find a cleaner and more OO way of cleaning up the list if it contains multiple deletions:
+ if (transformedRemotes.size() > 1) {
+ final ColaDocumentChangeMessage firstOp = (ColaDocumentChangeMessage) transformedRemotes.get(0);
+ if (firstOp.isDeletion()) {
+ //this means all operations in the return list must also be deletions, i.e. modify virtual/optimistic offset for sequential application to document
+ final ListIterator deletionFinalizerIt = transformedRemotes.listIterator();
+ ColaDocumentChangeMessage previousDel = (ColaDocumentChangeMessage) deletionFinalizerIt.next();//jump over first del-op does not need modification, we know this is OK because of previous size check;
+ ColaDocumentChangeMessage currentDel;
+
+ for (; deletionFinalizerIt.hasNext();) {
+ currentDel = (ColaDocumentChangeMessage) deletionFinalizerIt.next();
+ currentDel.setOffset(currentDel.getOffset() - previousDel.getLengthOfReplacedText());
+ previousDel = currentDel;
+ }
+ }
+ }
+
+ return transformedRemotes;
+ }
+
+ public String toString() {
+ final StringBuffer buf = new StringBuffer("ColaSynchronizationStrategy"); //$NON-NLS-1$
+ return buf.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategy#registerLocalChange(org.eclipse.ecf.sync.doc.IDocumentChange)
+ */
+ public IDocumentChangeMessage[] registerLocalChange(IDocumentChange localChange) {
+ Trace.entering(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_ENTERING, this.getClass(), "registerLocalChange", localChange); //$NON-NLS-1$
+ final ColaDocumentChangeMessage colaMsg = new ColaDocumentChangeMessage(new DocumentChangeMessage(localChange.getOffset(), localChange.getLengthOfReplacedText(), localChange.getText()), localOperationsCount, remoteOperationsCount);
+ if (!colaMsg.isReplacement()) {
+ unacknowledgedLocalOperations.add(colaMsg);
+ localOperationsCount++;
+ }
+ Trace.exiting(Activator.PLUGIN_ID, SyncDebugOptions.METHODS_EXITING, this.getClass(), "registerLocalChange", colaMsg); //$NON-NLS-1$
+ return new IDocumentChangeMessage[] {colaMsg};
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategy#toDocumentChangeMessage(byte[])
+ */
+ public IDocumentChange deserializeToDocumentChange(byte[] bytes) throws SerializationException {
+ return DocumentChangeMessage.deserialize(bytes);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategy#transformRemoteChange(org.eclipse.ecf.sync.doc.IDocumentChangeMessage)
+ */
+ public IDocumentChange[] transformRemoteChange(IDocumentChange remoteChange) {
+ if (!(remoteChange instanceof DocumentChangeMessage))
+ return new IDocumentChange[] {};
+ final DocumentChangeMessage m = (DocumentChangeMessage) remoteChange;
+ final List l = this.transformIncomingMessage(m);
+ return (IDocumentChange[]) l.toArray(new IDocumentChange[] {});
+ }
+} \ No newline at end of file
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaSynchronizationStrategyFactory.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaSynchronizationStrategyFactory.java
new file mode 100644
index 000000000..6ebbe0fab
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaSynchronizationStrategyFactory.java
@@ -0,0 +1,39 @@
+/****************************************************************************
+ * 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.sync.doc.cola;
+
+import org.eclipse.ecf.core.identity.ID;
+import org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategy;
+import org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategyFactory;
+
+/**
+ *
+ */
+public class ColaSynchronizationStrategyFactory implements IDocumentSynchronizationStrategyFactory {
+
+ public static final String SYNCHSTRATEGY_PROVIDER = "org.eclipse.ecf.internal.sync.doc.cola";
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategyFactory#disposeSynchronizationStragety(org.eclipse.ecf.core.identity.ID)
+ */
+ public void disposeSynchronizationStragety(ID uniqueID) {
+ ColaSynchronizationStrategy.cleanUpFor(uniqueID);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategyFactory#getSyncronizationStrategy(org.eclipse.ecf.core.identity.ID, boolean)
+ */
+ public IDocumentSynchronizationStrategy getSyncronizationStrategy(ID uniqueID, boolean isInitiator) {
+ return ColaSynchronizationStrategy.getInstanceFor(uniqueID, isInitiator);
+ }
+
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaTransformationStrategy.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaTransformationStrategy.java
new file mode 100644
index 000000000..64542cfe7
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/cola/ColaTransformationStrategy.java
@@ -0,0 +1,19 @@
+/****************************************************************************
+ * Copyright (c) 2008 Mustafa K. 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
+ *
+ * Contributors:
+ * Mustafa K. Isik - initial API and implementation
+ *****************************************************************************/
+
+package org.eclipse.ecf.internal.sync.doc.cola;
+
+import java.io.Serializable;
+
+public interface ColaTransformationStrategy extends Serializable {
+
+ ColaDocumentChangeMessage getOperationalTransform(ColaDocumentChangeMessage remoteIncomingMsg, ColaDocumentChangeMessage localAppliedMsg, boolean localMsgHighPrio);
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/identity/IdentitySynchronizationStrategy.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/identity/IdentitySynchronizationStrategy.java
new file mode 100644
index 000000000..796e0cd78
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/identity/IdentitySynchronizationStrategy.java
@@ -0,0 +1,46 @@
+/****************************************************************************
+ * 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.sync.doc.identity;
+
+import org.eclipse.ecf.sync.doc.IDocumentChange;
+import org.eclipse.ecf.sync.doc.IDocumentChangeMessage;
+import org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategy;
+import org.eclipse.ecf.sync.doc.SerializationException;
+import org.eclipse.ecf.sync.doc.messages.DocumentChangeMessage;
+
+/**
+ *
+ */
+public class IdentitySynchronizationStrategy implements IDocumentSynchronizationStrategy {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategy#deserializeToDocumentChange(byte[])
+ */
+ public IDocumentChange deserializeToDocumentChange(byte[] bytes) throws SerializationException {
+ return DocumentChangeMessage.deserialize(bytes);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategy#registerLocalChange(org.eclipse.ecf.sync.doc.IDocumentChange)
+ */
+ public IDocumentChangeMessage[] registerLocalChange(IDocumentChange localChange) {
+ return new IDocumentChangeMessage[] {new DocumentChangeMessage(localChange.getOffset(), localChange.getLengthOfReplacedText(), localChange.getText())};
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategy#transformRemoteChange(org.eclipse.ecf.sync.doc.IDocumentChange)
+ */
+ public IDocumentChange[] transformRemoteChange(IDocumentChange remoteChange) {
+ return new IDocumentChange[] {remoteChange};
+ }
+
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/identity/IdentitySynchronizationStrategyFactory.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/identity/IdentitySynchronizationStrategyFactory.java
new file mode 100644
index 000000000..534e797ba
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/internal/sync/doc/identity/IdentitySynchronizationStrategyFactory.java
@@ -0,0 +1,38 @@
+/****************************************************************************
+ * 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.sync.doc.identity;
+
+import org.eclipse.ecf.core.identity.ID;
+import org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategy;
+import org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategyFactory;
+
+/**
+ *
+ */
+public class IdentitySynchronizationStrategyFactory implements IDocumentSynchronizationStrategyFactory {
+
+ public static final String SYNCHSTRATEGY_PROVIDER = "org.eclipse.ecf.sync.doc.identity";
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategyFactory#disposeSynchronizationStragety(org.eclipse.ecf.core.identity.ID)
+ */
+ public void disposeSynchronizationStragety(ID uniqueID) {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ecf.sync.doc.IDocumentSynchronizationStrategyFactory#getSyncronizationStrategy(org.eclipse.ecf.core.identity.ID, boolean)
+ */
+ public IDocumentSynchronizationStrategy getSyncronizationStrategy(ID uniqueID, boolean isInitiator) {
+ return new IdentitySynchronizationStrategy();
+ }
+
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/IServiceConstants.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/IServiceConstants.java
new file mode 100644
index 000000000..f71468a6c
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/IServiceConstants.java
@@ -0,0 +1,21 @@
+/****************************************************************************
+ * 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.sync;
+
+/**
+ *
+ */
+public interface IServiceConstants {
+ public static final String SYNCSTRATEGY_TYPE_PROPERTY = "org.eclipse.ecf.type";
+ public static final String SYNCSTRATEGY_PROVIDER_PROPETY = "org.eclipse.ecf.sync.provider";
+
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentChange.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentChange.java
new file mode 100644
index 000000000..8743b7c59
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentChange.java
@@ -0,0 +1,37 @@
+/****************************************************************************
+ * 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.sync.doc;
+
+/**
+ * Local document change. Instances of this class represent
+ * local changes to a replicated document.
+ */
+public interface IDocumentChange {
+ /**
+ * Get offset in document where change has or will occur.
+ * @return int the offset
+ */
+ public int getOffset();
+
+ /**
+ * Get length of text that was replaced.
+ * @return length of replaced text
+ */
+ public int getLengthOfReplacedText();
+
+ /**
+ * Get the new text.
+ * @return String text. Will not return <code>null</code>, but
+ * may return empty string.
+ */
+ public String getText();
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentChangeMessage.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentChangeMessage.java
new file mode 100644
index 000000000..d3d2d8cd1
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentChangeMessage.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.sync.doc;
+
+/**
+ * Document change message. Instances of this interface
+ * may be serialized to a byte [] so that they can be
+ * communicated to remote processes.
+ */
+public interface IDocumentChangeMessage {
+
+ public byte[] toByteArray() throws SerializationException;
+
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentSynchronizationStrategy.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentSynchronizationStrategy.java
new file mode 100644
index 000000000..776e66861
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentSynchronizationStrategy.java
@@ -0,0 +1,58 @@
+/****************************************************************************
+ * 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.sync.doc;
+
+/**
+ * Document synchronization strategy. Instances implementing this interface
+ * expose the ability for clients to synchronize combinations of local
+ * and remote documents.
+ * <p></p>
+ * Owners that wish to synchronize local and remote changes
+ * should call {@link #registerLocalChange(IDocumentChange)} when local
+ * changes occur, and then serialize returned {@link IDocumentChangeMessage}s and
+ * deliver the change message to remotes. When remote change messages are received,
+ * they should first be deserized via {@link #deserializeToDocumentChange(byte[])}, and then
+ * passed to {@link #transformRemoteChange(IDocumentChange)} to transform
+ * the change so that when the returned IDocumentChanges are applied to the local
+ * document its state will be consistent with other client(s).
+ */
+public interface IDocumentSynchronizationStrategy {
+
+ /**
+ * Register local document change with document synchronization strategy. This method
+ * should be synchronously called when a local change has
+ * been made to the underlying document.
+ * @param localChange the IDocumentChange made to the local document
+ * @return IDocumentChangeMessage[] an array of document change message to be
+ * delivered to remote participants.
+ */
+ public IDocumentChangeMessage[] registerLocalChange(IDocumentChange localChange);
+
+ /**
+ * Transform remote document change into a set of local document changes to
+ * be synchronously applied to the local document.
+ * @param remoteChange the remote document change instance to
+ * be transformed by this synchronization strategy.
+ * @return IDocumentChange[] to apply to local document
+ */
+ public IDocumentChange[] transformRemoteChange(IDocumentChange remoteChange);
+
+ /**
+ * Deserialization of given byte array to concrete instance of
+ * IDocumentChange object to represent local change to be applied
+ *
+ * @param bytes the bytes to be deserialized
+ * @return IDocumentChange instance from bytes. Will not be <code>null</code>.
+ * @throws SerializationException thrown if some problem deserializing given bytes.
+ */
+ public IDocumentChange deserializeToDocumentChange(byte[] bytes) throws SerializationException;
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentSynchronizationStrategyFactory.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentSynchronizationStrategyFactory.java
new file mode 100644
index 000000000..f0f1967f2
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/IDocumentSynchronizationStrategyFactory.java
@@ -0,0 +1,39 @@
+/****************************************************************************
+ * 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.sync.doc;
+
+import org.eclipse.ecf.core.identity.ID;
+
+/**
+ * Factory for creating {@link IDocumentSynchronizationStrategy} instances for
+ * a uniquely identified entity. This interface is exposed as a service and
+ * provides an entry point for clients.
+ */
+public interface IDocumentSynchronizationStrategyFactory {
+
+ public static final String SYNCHSTRATEGY_TYPE = "org.eclipse.ecf.sync.doc";
+
+ /**
+ * Get an IDocumentSynchronizationStrategy for a unique ID. Should not be <code>null</code>.
+ * @param uniqueID the uniqueID to identify the client of the {@link IDocumentSynchronizationStrategy}.
+ * @param isInitiator whether the client is the initiator of the
+ * shared editing, or the receiver.
+ * @return IDocumentSynchronizationStrategy for the given uniqueID.
+ */
+ public IDocumentSynchronizationStrategy getSyncronizationStrategy(ID uniqueID, boolean isInitiator);
+
+ /**
+ * Clean up the synchronization strategy caching for a given uniqueID. Should not be <code>null</code>.
+ * @param uniqueID the ID of the
+ */
+ public void disposeSynchronizationStragety(ID uniqueID);
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/SerializationException.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/SerializationException.java
new file mode 100644
index 000000000..e477717b7
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/SerializationException.java
@@ -0,0 +1,58 @@
+/****************************************************************************
+ * 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.sync.doc;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ecf.core.util.ECFException;
+import org.eclipse.ecf.internal.sync.Activator;
+
+/**
+ *
+ */
+public class SerializationException extends ECFException {
+
+ private static final long serialVersionUID = -8702959540799683251L;
+
+ /**
+ * @param message
+ * message associated with exception
+ */
+ public SerializationException(String message) {
+ this(message, null);
+ }
+
+ /**
+ * @param cause
+ * the cause of the new exception
+ */
+ public SerializationException(Throwable cause) {
+ this(null, cause);
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public SerializationException(String message, Throwable cause) {
+ this(new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, ((message == null) ? "" : message), cause)); //$NON-NLS-1$
+ }
+
+ /**
+ * @param status
+ * the status for th
+ */
+ public SerializationException(IStatus status) {
+ super(status);
+ }
+
+}
diff --git a/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/messages/DocumentChangeMessage.java b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/messages/DocumentChangeMessage.java
new file mode 100644
index 000000000..ae75fa90c
--- /dev/null
+++ b/framework/bundles/org.eclipse.ecf.sync/src/org/eclipse/ecf/sync/doc/messages/DocumentChangeMessage.java
@@ -0,0 +1,109 @@
+/****************************************************************************
+ * Copyright (c) 2007, 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
+ * Mustafa K. Isik
+ *****************************************************************************/
+
+package org.eclipse.ecf.sync.doc.messages;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.eclipse.ecf.sync.doc.IDocumentChange;
+import org.eclipse.ecf.sync.doc.IDocumentChangeMessage;
+import org.eclipse.ecf.sync.doc.SerializationException;
+
+/**
+ *
+ */
+public class DocumentChangeMessage implements IDocumentChange, IDocumentChangeMessage {
+
+ private static final long serialVersionUID = -3195542805471664496L;
+
+ public static DocumentChangeMessage deserialize(byte[] bytes) throws SerializationException {
+ try {
+ final ByteArrayInputStream bins = new ByteArrayInputStream(bytes);
+ final ObjectInputStream oins = new ObjectInputStream(bins);
+ return (DocumentChangeMessage) oins.readObject();
+ } catch (final Exception e) {
+ throw new SerializationException("Exception deserializing DocumentChangeMessage", e);
+ }
+ }
+
+ final String text;
+ int offset;
+ int length;
+
+ public DocumentChangeMessage(int offset, int length, String text) {
+ this.offset = offset;
+ this.length = length;
+ 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 getLengthOfReplacedText() {
+ return length;
+ }
+
+ public void setLengthOfReplacedText(int length) {
+ this.length = length;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public int getLengthOfInsertedText() {
+ return this.text.length();
+ }
+
+ public String toString() {
+ final StringBuffer buf = new StringBuffer("DocumentChangeMessage["); //$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();
+ }
+
+ private byte[] serialize() throws IOException {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ final ObjectOutputStream oos = new ObjectOutputStream(bos);
+ oos.writeObject(this);
+ return bos.toByteArray();
+ }
+
+ public byte[] toByteArray() throws SerializationException {
+ try {
+ return serialize();
+ } catch (final IOException e) {
+ throw new SerializationException("Exception serializing DocumentChangeMessage", e);
+ }
+ }
+
+}

Back to the top